diff -pNaur -X b/Documentation/dontdiff a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c --- a/arch/arm/mach-omap1/board-palmte.c 2006-07-16 06:39:22.000000000 +0200 +++ b/arch/arm/mach-omap1/board-palmte.c 2006-07-16 06:05:25.000000000 +0200 @@ -40,6 +40,8 @@ #include #include +#include + static void __init omap_palmte_init_irq(void) { omap1_init_common_hw(); @@ -176,11 +178,27 @@ static struct platform_device palmte_bac }, }; +static struct tsc2102_config palmte_tsc2102_config = { + .uwire_cs = 0, /* As opposed to 3 */ + .pintdav_pin = OMAP_GPIO_IRQ(PALMTE_PINTDAV_GPIO), + .use_internal = 0, + .monitor = TSC_BAT1 | TSC_AUX | TSC_TEMP1 | TSC_TEMP2, +}; + +static struct platform_device palmte_tsc2102_device = { + .name = "tsc2102", + .id = -1, + .dev = { + .platform_data = &palmte_tsc2102_config, + }, +}; + static struct platform_device *devices[] __initdata = { &palmte_rom_device, &palmte_kp_device, &palmte_lcd_device, &palmte_backlight_device, + &palmte_tsc2102_device, &palmte_irda_device, }; @@ -217,6 +235,13 @@ static struct omap_board_config_kernel p static void __init palmte_gpio_setup(void) { + /* Set TSC2102 PINTDAV pin as input */ + if (omap_request_gpio(PALMTE_PINTDAV_GPIO)) { + printk(KERN_ERR "Could not reserve PINTDAV GPIO!\n"); + return; + } + omap_set_gpio_direction(PALMTE_PINTDAV_GPIO, 1); + /* Set MMC/SD host WP pin as input */ if (omap_request_gpio(PALMTE_MMC_WP_GPIO)) { printk(KERN_ERR "Could not reserve WP GPIO!\n"); diff -pNaur -X b/Documentation/dontdiff a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig --- a/drivers/hwmon/Kconfig 2006-07-16 06:39:22.000000000 +0200 +++ b/drivers/hwmon/Kconfig 2006-07-16 06:10:41.000000000 +0200 @@ -449,6 +449,18 @@ config SENSORS_HDAPS Say Y here if you have an applicable laptop and want to experience the awesome power of hdaps. +config SENSORS_TSC2102 + tristate "TI TSC2102 battery & temperature sensors" + depends on HWMON && ARCH_OMAP + select OMAP_TSC2102 + help + Say Y if your board has a TSC2102 chip and you want to + have its battery state, auxiliary input and temperature + sensors exported through hwmon. + + This driver can also be built as a module. In this case + the module will be called tsc2102_sensors. + config HWMON_DEBUG_CHIP bool "Hardware Monitoring Chip debugging messages" depends on HWMON diff -pNaur -X b/Documentation/dontdiff a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile --- a/drivers/hwmon/Makefile 2006-07-16 06:39:22.000000000 +0200 +++ b/drivers/hwmon/Makefile 2006-07-16 06:10:49.000000000 +0200 @@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_VIA686A) += via686a obj-$(CONFIG_SENSORS_VT8231) += vt8231.o obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +obj-$(CONFIG_SENSORS_TSC2102) += tsc2102_sensors.o ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff -pNaur -X b/Documentation/dontdiff a/drivers/hwmon/tsc2102_sensors.c b/drivers/hwmon/tsc2102_sensors.c --- a/drivers/hwmon/tsc2102_sensors.c 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/hwmon/tsc2102_sensors.c 2006-07-16 06:12:14.000000000 +0200 @@ -0,0 +1,168 @@ +/* + * drivers/hwmon/tsc2102_sensors.c + * + * hwmon interface for TSC2102 sensors + * + * Copyright (c) 2005 Andrzej Zaborowski + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include + +#include + +static struct tsc2102_hwmon { + struct class_device *dev; + int bat[2], aux, temp[2]; + struct mutex lock; +} hwmon; + +static void omap_tsc2102_ports(int bat1, int bat2, int aux) +{ + mutex_lock(&hwmon.lock); + hwmon.bat[0] = bat1; + hwmon.bat[1] = bat2; + hwmon.aux = aux; + mutex_unlock(&hwmon.lock); +} + +static void omap_tsc2102_temp1(int temp) +{ + mutex_lock(&hwmon.lock); + hwmon.temp[0] = temp; + mutex_unlock(&hwmon.lock); +} + +static void omap_tsc2102_temp2(int temp) +{ + mutex_lock(&hwmon.lock); + hwmon.temp[1] = temp; + mutex_unlock(&hwmon.lock); +} + +#define TSC2102_INPUT(devname, field) \ +static ssize_t show_ ## devname(struct device *dev, \ + struct device_attribute *devattr, char *buf) \ +{ \ + struct tsc2102_hwmon *devhwmon = dev_get_drvdata(dev); \ + int value; \ + mutex_lock(&devhwmon->lock); \ + value = devhwmon->field; \ + mutex_unlock(&devhwmon->lock); \ + return sprintf(buf, "%i\n", value); \ +} \ +static DEVICE_ATTR(devname ## _input, S_IRUGO, show_ ## devname, NULL); + +TSC2102_INPUT(in0, bat[0]) +TSC2102_INPUT(in1, bat[1]) +TSC2102_INPUT(in2, aux) +TSC2102_INPUT(temp1, temp[0]) +TSC2102_INPUT(temp2, temp[1]) + +static int omap_tsc2102_hwmon_probe(struct platform_device *pdev) +{ + struct tsc2102_config *pdata = pdev->dev.platform_data; + int status = 0; + + mutex_init(&hwmon.lock); + hwmon.dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon.dev)) { + printk(KERN_ERR "tsc2102_hwmon: Class registration failed\n"); + return PTR_ERR(hwmon.dev); + } + + platform_set_drvdata(pdev, &hwmon); + + if (pdata->monitor & (TSC_BAT1 | TSC_BAT2 | TSC_AUX)) + status |= omap_tsc2102_ports_cb(omap_tsc2102_ports); + if (pdata->monitor & TSC_TEMP1) + status |= omap_tsc2102_temp1_cb(omap_tsc2102_temp1); + if (pdata->monitor & TSC_TEMP2) + status |= omap_tsc2102_temp2_cb(omap_tsc2102_temp2); + if (status) { + hwmon_device_unregister(hwmon.dev); + return status; + } + + if (pdata->monitor & TSC_BAT1) + device_create_file(&pdev->dev, &dev_attr_in0_input); + if (pdata->monitor & TSC_BAT2) + device_create_file(&pdev->dev, &dev_attr_in1_input); + if (pdata->monitor & TSC_AUX) + device_create_file(&pdev->dev, &dev_attr_in2_input); + if (pdata->monitor & TSC_TEMP1) + device_create_file(&pdev->dev, &dev_attr_temp1_input); + if (pdata->monitor & TSC_TEMP2) + device_create_file(&pdev->dev, &dev_attr_temp2_input); + + return 0; +} + +static int omap_tsc2102_hwmon_remove(struct platform_device *pdev) +{ + struct tsc2102_hwmon *dev = platform_get_drvdata(pdev); + + omap_tsc2102_ports_cb(0); + omap_tsc2102_temp1_cb(0); + omap_tsc2102_temp2_cb(0); + hwmon_device_unregister(dev->dev); + return 0; +} + +static int +omap_tsc2102_hwmon_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int omap_tsc2102_hwmon_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver omap_tsc2102_hwmon_driver = { + .probe = omap_tsc2102_hwmon_probe, + .remove = omap_tsc2102_hwmon_remove, + .suspend = omap_tsc2102_hwmon_suspend, + .resume = omap_tsc2102_hwmon_resume, + .driver = { + .name = "tsc2102-hwmon", + }, +}; + +static int __init omap_tsc2102_hwmon_init(void) +{ + if (platform_driver_register(&omap_tsc2102_hwmon_driver)) + return -ENODEV; + + return 0; +} + +static void __exit omap_tsc2102_hwmon_exit(void) +{ + platform_driver_unregister(&omap_tsc2102_hwmon_driver); +} + +module_init(omap_tsc2102_hwmon_init); +module_exit(omap_tsc2102_hwmon_exit); + +MODULE_AUTHOR("Andrzej Zaborowski"); +MODULE_DESCRIPTION("hwmon driver for TI TSC2102 sensors."); +MODULE_LICENSE("GPL"); diff -pNaur -X b/Documentation/dontdiff a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig --- a/drivers/input/touchscreen/Kconfig 2006-07-16 06:39:48.000000000 +0200 +++ b/drivers/input/touchscreen/Kconfig 2006-07-16 06:35:01.000000000 +0200 @@ -112,10 +112,11 @@ endif config TOUCHSCREEN_OMAP tristate "OMAP touchscreen input driver" depends on INPUT && INPUT_TOUCHSCREEN && ARCH_OMAP - select OMAP_TSC2101 + select OMAP_TSC2101 if MACH_OMAP_H3 || MACH_OMAP_H2 + select OMAP_TSC2102 if MACH_OMAP_PALMTE help Say Y here if you have an OMAP based board with touchscreen - attached to it, e.g. OMAP Innovator, OSK, H2 or H3 + attached to it, e.g. OMAP Innovator, OSK, H2, H3, PalmTE If unsure, say N. diff -pNaur -X b/Documentation/dontdiff a/drivers/input/touchscreen/omap/Makefile b/drivers/input/touchscreen/omap/Makefile --- a/drivers/input/touchscreen/omap/Makefile 2006-07-16 06:39:22.000000000 +0200 +++ b/drivers/input/touchscreen/omap/Makefile 2006-07-16 06:13:21.000000000 +0200 @@ -8,5 +8,6 @@ objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MAC objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o +objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_PALMTE) += tsc2102_ts.o omapts-objs := omap_ts.o $(objs-yy) diff -pNaur -X b/Documentation/dontdiff a/drivers/input/touchscreen/omap/tsc2102_ts.c b/drivers/input/touchscreen/omap/tsc2102_ts.c --- a/drivers/input/touchscreen/omap/tsc2102_ts.c 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/input/touchscreen/omap/tsc2102_ts.c 2006-07-16 06:14:14.000000000 +0200 @@ -0,0 +1,146 @@ +/* + * input/touchscreen/omap/tsc2102_ts.c + * + * Touchscreen input device driver for boards using the TSC 2102 chip. + * + * Copyright (c) 2006 Andrzej Zaborowski + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct input_dev *dev; + +static void omap_tsc2102_touch(int touching) +{ + if (!touching) { + input_report_abs(dev, ABS_X, 0); + input_report_abs(dev, ABS_Y, 0); + input_report_abs(dev, ABS_PRESSURE, 0); + input_sync(dev); + } + + input_report_key(dev, BTN_TOUCH, touching); + + do_poke_blanked_console = 1; +} + +static void omap_tsc2102_coords(int x, int y, int z1, int z2) +{ + int p; + + /* Calculate the touch resistance a la equation #1 */ + if (z1 != 0) + p = x * (z2 - z1) / (z1 << 4); + else + p = 1; + + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_abs(dev, ABS_PRESSURE, p); + input_sync(dev); +} + +static int omap_tsc2102_ts_probe(struct platform_device *pdev) +{ + int status; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + status = omap_tsc2102_touch_cb(omap_tsc2102_touch); + if (status) { + input_free_device(dev); + return status; + } + + status = omap_tsc2102_coords_cb(omap_tsc2102_coords); + if (status) { + input_free_device(dev); + return status; + } + + dev->name = "TSC2102 Touchscreen"; + dev->dev = &pdev->dev; + dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + dev->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); + dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_register_device(dev); + + printk("OMAP TSC2102 touchscreen driver initialized\n"); + return 0; +} + +static int omap_tsc2102_ts_remove(struct platform_device *pdev) +{ + omap_tsc2102_touch_cb(0); + omap_tsc2102_coords_cb(0); + input_unregister_device(dev); + return 0; +} + +static int +omap_tsc2102_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int omap_tsc2102_ts_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver omap_tsc2102_ts_driver = { + .probe = omap_tsc2102_ts_probe, + .remove = omap_tsc2102_ts_remove, + .suspend = omap_tsc2102_ts_suspend, + .resume = omap_tsc2102_ts_resume, + .driver = { + .name = "tsc2102-ts", + }, +}; + +static int __init omap_tsc2102_ts_init(void) +{ + int ret; + + ret = platform_driver_register(&omap_tsc2102_ts_driver); + if (ret) + return -ENODEV; + + return 0; +} + +static void __exit omap_tsc2102_ts_exit(void) +{ + platform_driver_unregister(&omap_tsc2102_ts_driver); +} + +module_init(omap_tsc2102_ts_init); +module_exit(omap_tsc2102_ts_exit); + +MODULE_AUTHOR("Andrzej Zaborowski"); +MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2102."); +MODULE_LICENSE("GPL"); diff -pNaur -X b/Documentation/dontdiff a/drivers/ssi/Kconfig b/drivers/ssi/Kconfig --- a/drivers/ssi/Kconfig 2006-07-16 06:39:22.000000000 +0200 +++ b/drivers/ssi/Kconfig 2006-07-16 06:15:16.000000000 +0200 @@ -15,4 +15,12 @@ config OMAP_TSC2101 ---help--- Say Y here if you want support for the TSC2101 codec. It is needed for touchscreen and audio on OMAP1610 and 1710. + +config OMAP_TSC2102 + depends on ARCH_OMAP1 || ARCH_OMAP15XX + tristate "TSC2102 codec support for Touchscreen" + select OMAP_UWIRE if MACH_OMAP_PALMTE + ---help--- + Say Y here if you want support for the TSC2102 codec. It is + needed for the touchscreen driver on some boards. endmenu diff -pNaur -X b/Documentation/dontdiff a/drivers/ssi/Makefile b/drivers/ssi/Makefile --- a/drivers/ssi/Makefile 2006-07-16 06:39:22.000000000 +0200 +++ b/drivers/ssi/Makefile 2006-07-16 06:16:43.000000000 +0200 @@ -4,3 +4,4 @@ obj-$(CONFIG_OMAP_UWIRE) += omap-uwire.o obj-$(CONFIG_OMAP_TSC2101) += omap-tsc2101.o +obj-$(CONFIG_OMAP_TSC2102) += omap-tsc2102.o diff -pNaur -X b/Documentation/dontdiff a/drivers/ssi/omap-tsc2102.c b/drivers/ssi/omap-tsc2102.c --- a/drivers/ssi/omap-tsc2102.c 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/ssi/omap-tsc2102.c 2006-07-16 06:18:44.000000000 +0200 @@ -0,0 +1,588 @@ +/* + * drivers/ssi/omap-tsc2102.c + * + * TSC2102 codec interface driver for the OMAP platform + * + * Copyright (c) 2005 Andrzej Zaborowski + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#if CONFIG_ARCH_OMAP15XX +#include <../drivers/ssi/omap-uwire.h> +#else +#error "Unsupported configuration" +#endif + +/* Bit field definitions for TS Control */ +#define TSC2102_ADC_TS_CONTROL 0x8bf4 +#define TSC2102_ADC_SCAN_CONTROL 0x2ff4 +#define TSC2102_ADC_T1_CONTROL 0x2bf4 +#define TSC2102_ADC_T2_CONTROL 0x33f4 +#define TSC2102_ADC_DAV 0x4000 +#define TSC2102_ADC_INT_REF 0x0016 +#define TSC2102_ADC_EXT_REF 0x0002 +#define TSC2102_CONFIG_TIMES 0x0008 +#define TSC2102_RESET 0xbb00 +#define TSC2102_ADC_PSTCM (1 << 15) +#define TSC2102_ADC_ADST (1 << 14) +#define TSC2102_TS_DAV 0x0780 +#define TSC2102_PS_DAV 0x0078 +#define TSC2102_T1_DAV 0x0004 +#define TSC2102_T2_DAV 0x0002 + +struct tsc2102_dev { + struct tsc2102_config *pdata; + spinlock_t lock; + struct clk *mclk_ck; + int state; /* 0: TS, 1: Portscan, 2-3: Temps */ + struct timer_list ts_timer; /* Busy-wait for PEN UP */ + struct timer_list mode_timer; /* Change .state every some time */ + int pendown; + omap_tsc2102_touch_t touch_cb; + omap_tsc2102_coords_t coords_cb; + omap_tsc2102_ports_t ports_cb; + omap_tsc2102_temp_t temp1_cb; + omap_tsc2102_temp_t temp2_cb; + unsigned int ts_msecs; + unsigned int mode_msecs; +}; + +static struct tsc2102_dev tsc; + +module_param_named(touch_check_msecs, tsc.ts_msecs, uint, 0); +MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs"); + +module_param_named(sensor_scan_msecs, tsc.mode_msecs, uint, 0); +MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval"); + +void omap_tsc2102_write(int page, u8 address, u16 data) +{ + int ret; + + /* Address */ + ret = omap_uwire_data_transfer(tsc.pdata->uwire_cs, + (page << 11) | (address << 5), 16, + 0, NULL, 1); + if (ret) { + printk(KERN_ERR "uwire-write returned error for address %x\n", + address); + return; + } + + /* Data */ + ret = omap_uwire_data_transfer(tsc.pdata->uwire_cs, + data, 16, 0, NULL, 0); + if (ret) { + printk(KERN_ERR "uwire-write returned error for address %x\n", + address); + return; + } +} + +void omap_tsc2102_reads(int page, u8 startaddress, u16 *data, int numregs) +{ + int i; + + /* Address */ + (void) omap_uwire_data_transfer(tsc.pdata->uwire_cs, + 0x8000 | (page << 11) | (startaddress << 5), + 16, 0, NULL, 1); + + /* Data */ + for (i = 0; i < (numregs - 1); i ++, data ++) + omap_uwire_data_transfer(tsc.pdata->uwire_cs, + 0, 0, 16, data, 1); + + omap_uwire_data_transfer(tsc.pdata->uwire_cs, 0, 0, 16, data, 0); +} + +u16 omap_tsc2102_read(int page, u8 address) +{ + u16 ret; + omap_tsc2102_reads(page, address, &ret, 1); + return ret; +} + +#define omap_tsc2102_cb_register_func(cb, cb_t) \ +int omap_tsc2102_ ## cb(cb_t handler) \ +{ \ + spin_lock(&tsc.lock); \ + \ + /* Lock the module */ \ + if (handler && !tsc.cb) \ + if (!try_module_get(THIS_MODULE)) { \ + printk(KERN_INFO "Failed to get TSC module\n"); \ + } \ + if (!handler && tsc.cb) \ + module_put(THIS_MODULE); \ + \ + tsc.cb = handler; \ + \ + spin_unlock(&tsc.lock); \ + return 0; \ +} + +omap_tsc2102_cb_register_func(touch_cb, omap_tsc2102_touch_t) +omap_tsc2102_cb_register_func(coords_cb, omap_tsc2102_coords_t) +omap_tsc2102_cb_register_func(ports_cb, omap_tsc2102_ports_t) +omap_tsc2102_cb_register_func(temp1_cb, omap_tsc2102_temp_t) +omap_tsc2102_cb_register_func(temp2_cb, omap_tsc2102_temp_t) + +#ifdef DEBUG +static void omap_tsc2102_print_dav(void) +{ + u16 status = omap_tsc2102_read(TSC2102_TS_STATUS_CTRL); + if (status & 0x0fff) + printk("TSC2102: data in"); + if (status & 0x0400) + printk(" X"); + if (status & 0x0200) + printk(" Y"); + if (status & 0x0100) + printk(" Z1"); + if (status & 0x0080) + printk(" Z2"); + if (status & 0x0040) + printk(" BAT1"); + if (status & 0x0020) + printk(" BAT2"); + if (status & 0x0010) + printk(" AUX1"); + if (status & 0x0008) + printk(" AUX2"); + if (status & 0x0004) + printk(" TEMP1"); + if (status & 0x0002) + printk(" TEMP2"); + if (status & 0x0001) + printk(" KP"); + if (status & 0x0fff) + printk(".\n"); +} +#endif + +static inline void omap_tsc2102_touchscreen_mode(struct tsc2102_dev *dev) +{ + /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */ + omap_tsc2102_write(TSC2102_TS_ADC_CTRL, TSC2102_ADC_TS_CONTROL); +} + +static inline void omap_tsc2102_portscan_mode(struct tsc2102_dev *dev) +{ + /* Scan BAT1, BAT2, AUX, 12-bit, 16 samples, 500 usec */ + omap_tsc2102_write(TSC2102_TS_ADC_CTRL, TSC2102_ADC_SCAN_CONTROL); +} + +static inline void omap_tsc2102_temp1_mode(struct tsc2102_dev *dev) +{ + /* Scan TEMP1, 12-bit, 16 samples, 500 usec */ + omap_tsc2102_write(TSC2102_TS_ADC_CTRL, TSC2102_ADC_T1_CONTROL); +} + +static inline void omap_tsc2102_temp2_mode(struct tsc2102_dev *dev) +{ + /* Scan TEMP2, 12-bit, 16 samples, 500 usec */ + omap_tsc2102_write(TSC2102_TS_ADC_CTRL, TSC2102_ADC_T2_CONTROL); +} + +static void omap_tsc2102_mode(struct tsc2102_dev *dev) +{ + switch (dev->state) { + case 0: + omap_tsc2102_touchscreen_mode(dev); + break; + case 1: + omap_tsc2102_portscan_mode(dev); + break; + case 2: + omap_tsc2102_temp1_mode(dev); + break; + case 3: + omap_tsc2102_temp2_mode(dev); + break; + default: + dev->state = 0; + omap_tsc2102_touchscreen_mode(dev); + break; + } +} + +static void omap_tsc2102_new_mode(struct tsc2102_dev *dev) +{ + /* Abort current conversion if any */ + omap_tsc2102_write(TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST); + + dev->state ++; + omap_tsc2102_mode(dev); +} + +/* TSC has new data for us availiable. */ +static irqreturn_t +omap_tsc2102_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct tsc2102_dev *dev = (struct tsc2102_dev *) dev_id; + u16 data[4], status; + spin_lock(&dev->lock); + + status = omap_tsc2102_read(TSC2102_TS_STATUS_CTRL); + + /* + * Read all converted data from corresponding registers + * so that the ADC can move on to a new conversion. + */ + if (status & TSC2102_TS_DAV) { + omap_tsc2102_reads(TSC2102_TS_X, data, 4); + if (!dev->pendown) { + dev->pendown = 1; + if (dev->touch_cb) + dev->touch_cb(1); + + mod_timer(&dev->ts_timer, jiffies + + msecs_to_jiffies(dev->ts_msecs)); + } + if (dev->coords_cb) + dev->coords_cb(data[0], data[1], data[2], data[3]); + } + if (status & TSC2102_PS_DAV) { + omap_tsc2102_reads(TSC2102_TS_BAT1, data, 3); + if (dev->ports_cb) + dev->ports_cb(data[0], data[1], data[2]); + } + if (status & TSC2102_T1_DAV) { + *data = omap_tsc2102_read(TSC2102_TS_TEMP1); + if (dev->temp1_cb) + dev->temp1_cb(*data); + } + if (status & TSC2102_T2_DAV) { + *data = omap_tsc2102_read(TSC2102_TS_TEMP2); + if (dev->temp2_cb) + dev->temp2_cb(*data); + } + + if (dev->state) + omap_tsc2102_new_mode(dev); + + spin_unlock(&dev->lock); + return IRQ_HANDLED; +} + +static void omap_tsc2102_mode_timer(unsigned long data) +{ + struct tsc2102_dev *dev = (struct tsc2102_dev *) data; + + spin_lock(&dev->lock); + + BUG_ON(dev->state); + + omap_tsc2102_new_mode(dev); + mod_timer(&dev->mode_timer, jiffies + + msecs_to_jiffies(dev->mode_msecs)); + spin_unlock(&dev->lock); +} + +/* + * There are at least three ways to check for pen-up: + * - the PINT/DAV pin state, + * - reading PSTCM bit in ADC Control register (D15, offset 0x00), + * - reading ADST bit in ADC Control register (D14, offset 0x00), + * ADC idle would indicate no screen touch. + * Unfortunately none of them seems to be 100% accurate and you will + * find they are totally inconsistent, i.e. you get to see any arbitrary + * combination of values in these three bits. So we will busy-wait + * for a moment when all three indicate a pen-up, using a timer, before + * we report a pen-up. + */ +static void omap_tsc2102_pressure(unsigned long data) +{ + struct tsc2102_dev *dev = (struct tsc2102_dev *) data; + u16 status; + + spin_lock(&dev->lock); + + BUG_ON(!dev->pendown); + + status = omap_tsc2102_read(TSC2102_TS_ADC_CTRL); + if (dev->state || + (status & TSC2102_ADC_PSTCM) || + !(status & TSC2102_ADC_ADST)) { + mod_timer(&dev->ts_timer, jiffies + + msecs_to_jiffies(dev->ts_msecs)); + } else { + dev->pendown = 0; + if (dev->touch_cb) + dev->touch_cb(0); + } + + spin_unlock(&dev->lock); +} + +static int omap_tsc2102_configure(struct tsc2102_dev *dev) +{ + unsigned long uwire_flags = 0; + + uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE; + omap_uwire_configure_mode(dev->pdata->uwire_cs, uwire_flags); + + /* Reset the chip */ + omap_tsc2102_write(TSC2102_TS_RESET_CTRL, TSC2102_RESET); + + /* Reference mode, 100 usec delay, 1.25 V reference */ + if (dev->pdata->use_internal) + omap_tsc2102_write(TSC2102_TS_REF_CTRL, TSC2102_ADC_INT_REF); + else + omap_tsc2102_write(TSC2102_TS_REF_CTRL, TSC2102_ADC_EXT_REF); + + /* 84 usec precharge time, 32 usec sense time */ + omap_tsc2102_write(TSC2102_TS_CONFIG_CTRL, TSC2102_CONFIG_TIMES); + + /* PINTDAV acts as DAV */ + omap_tsc2102_write(TSC2102_TS_STATUS_CTRL, TSC2102_ADC_DAV); + + omap_tsc2102_mode(dev); + mod_timer(&dev->mode_timer, jiffies + + msecs_to_jiffies(dev->mode_msecs)); + return 0; +} + +#ifdef CONFIG_PM +/* + * Suspend the chip. + */ +static int +omap_tsc2102_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tsc2102_dev *dev = platform_get_drvdata(pdev); + + if (!dev) + return 0; + + spin_lock(&dev->lock); + + del_timer(&dev->mode_timer); + del_timer(&dev->ts_timer); + + if (dev->pendown && dev->touch_cb) + dev->touch_cb(0); + + /* Abort current conversion and power down the ADC */ + omap_tsc2102_write(TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST); + + /* TSC2102 Audio shutdown */ + omap_tsc2102_write(TSC2102_AUDIO2_CTRL, 0x0000); + omap_tsc2102_write(TSC2102_PLL1_CTRL, 0x0000); + omap_tsc2102_write(TSC2102_DAC_POWER_CTRL, 0xafe0); + + spin_unlock(&dev->lock); + return 0; +} + +/* + * Resume chip operation. + */ +static int omap_tsc2102_resume(struct platform_device *pdev) +{ + struct tsc2102_dev *dev = platform_get_drvdata(pdev); + int err; + + if (!dev) + return 0; + + spin_lock(&dev->lock); + + dev->state = 0; + dev->pendown = 0; + + err = omap_tsc2102_configure(&tsc); + + spin_unlock(&dev->lock); + return err; +} +#else +#define omap_tsc2102_suspend NULL +#define omap_tsc2102_resume NULL +#endif + +static struct platform_device omap_tsc2102_ts_device = { + .name = "tsc2102-ts", + .id = -1, +}; + +static struct platform_device omap_tsc2102_hwmon_device = { + .name = "tsc2102-hwmon", + .id = -1, +}; + +static struct platform_device omap_tsc2102_alsa_device = { + .name = "tsc2102-alsa", + .id = -1, +}; + +static int omap_tsc2102_probe(struct platform_device *pdev) +{ + struct tsc2102_config *pdata = pdev->dev.platform_data; + int err = 0; + + if (!pdata) { + printk(KERN_ERR "TSC2102 Platform data not supplied\n"); + return -ENOENT; + } + + if (!pdata->pintdav_pin) { + printk(KERN_ERR "TSC2102 Invalid irq value\n"); + return -ENOENT; + } + + tsc.pdata = pdata; + tsc.lock = SPIN_LOCK_UNLOCKED; + tsc.state = 0; + tsc.pendown = 0; + tsc.ts_msecs = 10; + tsc.mode_msecs = 500; + + spin_lock(&tsc.lock); + + /* Get the MCLK - assuming the rate is at 12000000 */ + tsc.mclk_ck = clk_get(0, "mclk"); + if (!tsc.mclk_ck) { + printk(KERN_ERR "Unable to get the clock MCLK\n"); + err = -EPERM; + goto done; + } + + clk_enable(tsc.mclk_ck); + + set_irq_type(pdata->pintdav_pin, IRQT_FALLING); + if (request_irq(pdata->pintdav_pin, omap_tsc2102_handler, + SA_SAMPLE_RANDOM, "tsc2102", &tsc)) { + printk(KERN_ERR "Could not allocate touchscreen IRQ!\n"); + err = -EINVAL; + goto err_clk; + } + + setup_timer(&tsc.ts_timer, + omap_tsc2102_pressure, (unsigned long) &tsc); + setup_timer(&tsc.mode_timer, + omap_tsc2102_mode_timer, (unsigned long) &tsc); + + err = omap_tsc2102_configure(&tsc); + if (err) + goto err_timer; + + platform_set_drvdata(pdev, &tsc); + + omap_tsc2102_ts_device.dev.platform_data = pdata; + err = platform_device_register(&omap_tsc2102_ts_device); + if (err) + goto err_timer; + + omap_tsc2102_hwmon_device.dev.platform_data = pdata; + err = platform_device_register(&omap_tsc2102_hwmon_device); + if (err) + goto err_ts; + + omap_tsc2102_alsa_device.dev.platform_data = pdata; + err = platform_device_register(&omap_tsc2102_alsa_device); + + if (!err) + goto done; + + platform_device_unregister(&omap_tsc2102_hwmon_device); +err_ts: + platform_device_unregister(&omap_tsc2102_ts_device); +err_timer: + del_timer(&tsc.ts_timer); + del_timer(&tsc.mode_timer); +err_clk: + clk_disable(tsc.mclk_ck); + clk_put(tsc.mclk_ck); +done: + spin_unlock(&tsc.lock); + return err; +} + +static int omap_tsc2102_remove(struct platform_device *pdev) +{ + struct tsc2102_dev *dev = platform_get_drvdata(pdev); + + spin_lock(&dev->lock); + + platform_device_unregister(&omap_tsc2102_ts_device); + platform_device_unregister(&omap_tsc2102_hwmon_device); + platform_device_unregister(&omap_tsc2102_alsa_device); + + /* Release the MCLK */ + clk_disable(dev->mclk_ck); + clk_put(dev->mclk_ck); + + del_timer(&tsc.mode_timer); + del_timer(&tsc.ts_timer); + + spin_unlock(&dev->lock); + + return 0; +} + +static struct platform_driver tsc2102_driver = { + .probe = omap_tsc2102_probe, + .remove = omap_tsc2102_remove, + .suspend = omap_tsc2102_suspend, + .resume = omap_tsc2102_resume, + .driver = { + .name = "tsc2102", + }, +}; + +static char __initdata banner[] = KERN_INFO "TI TSC2102 driver initializing\n"; + +static int __init omap_tsc2102_init(void) +{ + printk(banner); + return platform_driver_register(&tsc2102_driver); +} + +static void __exit omap_tsc2102_exit(void) +{ + platform_driver_unregister(&tsc2102_driver); +} + +module_init(omap_tsc2102_init); +module_exit(omap_tsc2102_exit); + +EXPORT_SYMBOL(omap_tsc2102_read); +EXPORT_SYMBOL(omap_tsc2102_reads); +EXPORT_SYMBOL(omap_tsc2102_write); + +MODULE_AUTHOR("Andrzej Zaborowski"); +MODULE_DESCRIPTION("Interface driver for TI TSC2102 chips."); +MODULE_LICENSE("GPL"); diff -pNaur -X b/Documentation/dontdiff a/drivers/ssi/omap-uwire.c b/drivers/ssi/omap-uwire.c --- a/drivers/ssi/omap-uwire.c 2006-07-16 06:39:22.000000000 +0200 +++ b/drivers/ssi/omap-uwire.c 2006-07-16 06:16:51.000000000 +0200 @@ -212,6 +212,10 @@ static int __init omap_uwire_init(void) omap_cfg_reg(N14_1610_UWIRE_CS0); omap_cfg_reg(P15_1610_UWIRE_CS3); } + if (machine_is_omap_palmte()) { + omap_cfg_reg(N14_1610_UWIRE_CS0); + omap_cfg_reg(P15_1610_UWIRE_CS3); + } if (machine_is_omap_perseus2()) { /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */ int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000; diff -pNaur -X b/Documentation/dontdiff a/include/asm-arm/hardware/tsc2102.h b/include/asm-arm/hardware/tsc2102.h --- a/include/asm-arm/hardware/tsc2102.h 1970-01-01 01:00:00.000000000 +0100 +++ b/include/asm-arm/hardware/tsc2102.h 2006-07-16 06:20:41.000000000 +0200 @@ -0,0 +1,118 @@ +/* + * include/asm-arm/hardware/tsc2102.h + * + * TI TSC2102 Touchscreen, Audio and Battery control register definitions + * + * Copyright (c) 2005 Andrzej Zaborowski + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ASM_HARDWARE_TSC2102_H +#define __ASM_HARDWARE_TSC2102_H + +struct tsc2102_config { + int uwire_cs; + int pintdav_pin; + int use_internal; + u32 monitor; +}; + +#define TSC_BAT1 (1 << 0) +#define TSC_BAT2 (1 << 1) +#define TSC_AUX (1 << 2) +#define TSC_TEMP1 (1 << 4) +#define TSC_TEMP2 (1 << 5) + +extern u16 omap_tsc2102_read(int page, u8 address); +extern void omap_tsc2102_reads(int page, u8 startaddress, u16 *data, + int numregs); +extern void omap_tsc2102_write(int page, u8 address, u16 data); + +typedef void (*omap_tsc2102_touch_t)(int touching); +typedef void (*omap_tsc2102_coords_t)(int x, int y, int z1, int z2); +typedef void (*omap_tsc2102_ports_t)(int bat1, int bat2, int aux); +typedef void (*omap_tsc2102_temp_t)(int temp); +extern int omap_tsc2102_touch_cb(omap_tsc2102_touch_t handler); +extern int omap_tsc2102_coords_cb(omap_tsc2102_coords_t handler); +extern int omap_tsc2102_ports_cb(omap_tsc2102_ports_t handler); +extern int omap_tsc2102_temp1_cb(omap_tsc2102_temp_t handler); +extern int omap_tsc2102_temp2_cb(omap_tsc2102_temp_t handler); + +/* Page 0, Touch Screen & Keypad Data registers */ +#define TSC2102_TS_X 0, 0x00 +#define TSC2102_TS_Y 0, 0x01 +#define TSC2102_TS_Z1 0, 0x02 +#define TSC2102_TS_Z2 0, 0x03 +#define TSC2102_TS_BAT1 0, 0x05 +#define TSC2102_TS_BAT2 0, 0x06 +#define TSC2102_TS_AUX 0, 0x07 +#define TSC2102_TS_TEMP1 0, 0x09 +#define TSC2102_TS_TEMP2 0, 0x0a + +/* Page 1, Touch Screen & Keypad Control registers */ +#define TSC2102_TS_ADC_CTRL 1, 0x00 +#define TSC2102_TS_STATUS_CTRL 1, 0x01 +#define TSC2102_TS_REF_CTRL 1, 0x03 +#define TSC2102_TS_RESET_CTRL 1, 0x04 +#define TSC2102_TS_CONFIG_CTRL 1, 0x05 + +/* Page 2, Audio Control registers */ +#define TSC2102_AUDIO1_CTRL 2, 0x00 +#define TSC2102_DAC_GAIN_CTRL 2, 0x02 +#define TSC2102_AUDIO2_CTRL 2, 0x04 +#define TSC2102_DAC_POWER_CTRL 2, 0x05 +#define TSC2102_AUDIO3_CTRL 2, 0x06 +#define TSC2102_LCH_BASS_BOOST_N0 2, 0x07 +#define TSC2102_LCH_BASS_BOOST_N1 2, 0x08 +#define TSC2102_LCH_BASS_BOOST_N2 2, 0x09 +#define TSC2102_LCH_BASS_BOOST_N3 2, 0x0a +#define TSC2102_LCH_BASS_BOOST_N4 2, 0x0b +#define TSC2102_LCH_BASS_BOOST_N5 2, 0x0c +#define TSC2102_LCH_BASS_BOOST_D1 2, 0x0d +#define TSC2102_LCH_BASS_BOOST_D2 2, 0x0e +#define TSC2102_LCH_BASS_BOOST_D4 2, 0x0f +#define TSC2102_LCH_BASS_BOOST_D5 2, 0x10 +#define TSC2102_RCH_BASS_BOOST_N0 2, 0x11 +#define TSC2102_RCH_BASS_BOOST_N1 2, 0x12 +#define TSC2102_RCH_BASS_BOOST_N2 2, 0x13 +#define TSC2102_RCH_BASS_BOOST_N3 2, 0x14 +#define TSC2102_RCH_BASS_BOOST_N4 2, 0x15 +#define TSC2102_RCH_BASS_BOOST_N5 2, 0x16 +#define TSC2102_RCH_BASS_BOOST_D1 2, 0x17 +#define TSC2102_RCH_BASS_BOOST_D2 2, 0x18 +#define TSC2102_RCH_BASS_BOOST_D4 2, 0x19 +#define TSC2102_RCH_BASS_BOOST_D5 2, 0x1a +#define TSC2102_PLL1_CTRL 2, 0x1b +#define TSC2102_PLL2_CTRL 2, 0x1c +#define TSC2102_AUDIO4_CTRL 2, 0x1d + +/* Bit position */ +#define TSC2102_BIT(ARG) (0x01 << (ARG)) + +/* Field masks for Audio Control */ +#define TSC2102_AC_ADCHPF(ARG) (((ARG) & 0x03) << 14) +#define TSC2102_AC_WLEN(ARG) (((ARG) & 0x03) << 10) +#define TSC2102_AC_DATFM(ARG) (((ARG) & 0x03) << 8) +#define TSC2102_AC_DACFS(ARG) (((ARG) & 0x07) << 3) +#define TSC2102_AC_ADCFS(ARG) (((ARG) & 0x07)) + +/* Field masks for TSC2102_DAC_GAIN_CTRL */ +#define TSC2102_DGC_DALMU TSC2102_BIT(15) +#define TSC2102_DGC_DALVL(ARG) (((ARG) & 0x7F) << 8) +#define TSC2102_DGC_DARMU TSC2102_BIT(7) +#define TSC2102_DGC_DARVL(ARG) (((ARG) & 0x7F)) + +#endif /* __ASM_HARDWARE_TSC2102_H */