Index: linux-2.6.15-rc1/drivers/mfd/tsc2101.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.15-rc1/drivers/mfd/tsc2101.h	2005-11-19 23:13:42.000000000 +0000
@@ -0,0 +1,158 @@
+/*
+ * TI TSC2101 Hardware definitions
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@o-hand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/* Modes */
+#define TSC2101_MODE_TS   1
+#define TSC2101_MODE_MISC 2
+
+/* Address constructs */
+#define TSC2101_READ     (1 << 15)    /* Read Register */
+#define TSC2101_WRITE    (0 << 15)    /* Write Register */
+#define TSC2101_PAGE(x)  ((x & 0xf) << 11) /* Memory Page to access */
+#define TSC2101_ADDR(x)  ((x & 0x3f) << 5) /* Memory Address to access */
+
+#define TSC2101_P0_REG(x) (TSC2101_PAGE(0) | TSC2101_ADDR(x))
+#define TSC2101_P1_REG(x) (TSC2101_PAGE(1) | TSC2101_ADDR(x))
+#define TSC2101_P2_REG(x) (TSC2101_PAGE(2) | TSC2101_ADDR(x))
+#define TSC2101_P3_REG(x) (TSC2101_PAGE(3) | TSC2101_ADDR(x))
+
+/* Page 0 Registers */
+#define TSC2101_REG_X      TSC2101_P0_REG(0x0)
+#define TSC2101_REG_Y      TSC2101_P0_REG(0x1)
+#define TSC2101_REG_Z1     TSC2101_P0_REG(0x2)
+#define TSC2101_REG_Z2     TSC2101_P0_REG(0x3)
+#define TSC2101_REG_BAT    TSC2101_P0_REG(0x5)
+#define TSC2101_REG_AUX1   TSC2101_P0_REG(0x7)
+#define TSC2101_REG_AUX2   TSC2101_P0_REG(0x8)
+#define TSC2101_REG_TEMP1  TSC2101_P0_REG(0x9)
+#define TSC2101_REG_TEMP2  TSC2101_P0_REG(0xa)
+
+/* Page 1 Registers */
+#define TSC2101_REG_ADC       TSC2101_P1_REG(0x0)
+#define TSC2101_REG_STATUS    TSC2101_P1_REG(0x1)
+#define TSC2101_REG_BUFMODE   TSC2101_P1_REG(0x2)
+#define TSC2101_REG_REF       TSC2101_P1_REG(0x3)
+#define TSC2101_REG_RESETCTL  TSC2101_P1_REG(0x4)
+#define TSC2101_REG_CONFIG    TSC2101_P1_REG(0x5)
+#define TSC2101_REG_TEMPMAX   TSC2101_P1_REG(0x6)
+#define TSC2101_REG_TEMPMIN   TSC2101_P1_REG(0x7)
+#define TSC2101_REG_AUX1MAX   TSC2101_P1_REG(0x8)
+#define TSC2101_REG_AUX1MIN   TSC2101_P1_REG(0x9)
+#define TSC2101_REG_AUX2MAX   TSC2101_P1_REG(0xa)
+#define TSC2101_REG_AUX2MIN   TSC2101_P1_REG(0xb)
+#define TSC2101_REG_MEASURE   TSC2101_P1_REG(0xc)
+#define TSC2101_REG_DELAY     TSC2101_P1_REG(0xd)
+
+/* Page 2 Registers */
+#define TSC2101_REG_AUDIOCON1   TSC2101_P2_REG(0x0)
+#define TSC2101_REG_HEADSETPGA  TSC2101_P2_REG(0x1)
+#define TSC2101_REG_DACPGA      TSC2101_P2_REG(0x2)
+#define TSC2101_REG_MIXERPGA    TSC2101_P2_REG(0x3)
+#define TSC2101_REG_AUDIOCON2   TSC2101_P2_REG(0x4)
+#define TSC2101_REG_PWRDOWN     TSC2101_P2_REG(0x5)
+#define TSC2101_REG_AUDIOCON3   TSC2101_P2_REG(0x6)
+#define TSC2101_REG_DAEFC(x)	TSC2101_P2_REG(0x7+x)
+#define TSC2101_REG_PLL1        TSC2101_P2_REG(0x1b)
+#define TSC2101_REG_PLL2        TSC2101_P2_REG(0x1c)
+#define TSC2101_REG_AUDIOCON4   TSC2101_P2_REG(0x1d)
+#define TSC2101_REG_HANDSETPGA  TSC2101_P2_REG(0x1e)
+#define TSC2101_REG_BUZZPGA     TSC2101_P2_REG(0x1f)
+#define TSC2101_REG_AUDIOCON5   TSC2101_P2_REG(0x20)
+#define TSC2101_REG_AUDIOCON6   TSC2101_P2_REG(0x21)
+#define TSC2101_REG_AUDIOCON7   TSC2101_P2_REG(0x22)
+#define TSC2101_REG_GPIO        TSC2101_P2_REG(0x23)
+#define TSC2101_REG_AGCCON      TSC2101_P2_REG(0x24)
+#define TSC2101_REG_DRVPWRDWN   TSC2101_P2_REG(0x25)
+#define TSC2101_REG_MICAGC      TSC2101_P2_REG(0x26)
+#define TSC2101_REG_CELLAGC     TSC2101_P2_REG(0x27)
+
+/* Page 2 Registers */
+#define TSC2101_REG_BUFLOC(x)	TSC2101_P3_REG(x)
+
+/* Status Register Masks */
+
+#define TSC2101_STATUS_T2STAT   (1 << 1)
+#define TSC2101_STATUS_T1STAT   (1 << 2)
+#define TSC2101_STATUS_AX2STAT  (1 << 3)
+#define TSC2101_STATUS_AX1STAT  (1 << 4)
+#define TSC2101_STATUS_BSTAT    (1 << 6)
+#define TSC2101_STATUS_Z2STAT   (1 << 7)
+#define TSC2101_STATUS_Z1STAT   (1 << 8)
+#define TSC2101_STATUS_YSTAT    (1 << 9)
+#define TSC2101_STATUS_XSTAT    (1 << 10)
+#define TSC2101_STATUS_DAVAIL   (1 << 11)     
+#define TSC2101_STATUS_HCTLM    (1 << 12)
+#define TSC2101_STATUS_PWRDN    (1 << 13)
+#define TSC2101_STATUS_PINTDAV_SHIFT (14)
+#define TSC2101_STATUS_PINTDAV_MASK  (0x03)
+
+
+
+
+
+
+
+#define TSC2101_ADC_PSM (1<<15) // pen status mode on ctrlreg adc
+#define TSC2101_ADC_STS (1<<14) // stop continuous scanning.
+#define TSC2101_ADC_AD3 (1<<13) 
+#define TSC2101_ADC_AD2 (1<<12) 
+#define TSC2101_ADC_AD1 (1<<11) 
+#define TSC2101_ADC_AD0 (1<<10) 
+#define TSC2101_ADC_ADMODE(x) ((x<<10) & TSC2101_ADC_ADMODE_MASK)
+#define TSC2101_ADC_ADMODE_MASK (0xf<<10)  
+
+#define TSC2101_ADC_RES(x) ((x<<8) & TSC2101_ADC_RES_MASK )
+#define TSC2101_ADC_RES_MASK (0x3<<8)  
+#define TSC2101_ADC_RES_12BITP (0) // 12-bit ADC resolution (default)
+#define TSC2101_ADC_RES_8BIT (1) // 8-bit ADC resolution
+#define TSC2101_ADC_RES_10BIT (2) // 10-bit ADC resolution
+#define TSC2101_ADC_RES_12BIT (3) // 12-bit ADC resolution
+
+#define TSC2101_ADC_AVG(x) ((x<<6) & TSC2101_ADC_AVG_MASK )
+#define TSC2101_ADC_AVG_MASK (0x3<<6)  
+#define TSC2101_ADC_NOAVG (0) //  a-d does no averaging
+#define TSC2101_ADC_4AVG (1) //  a-d does averaging of 4 samples
+#define TSC2101_ADC_8AVG (2) //  a-d does averaging of 8 samples
+#define TSC2101_ADC_16AVG (3) //  a-d does averaging of 16 samples
+
+#define TSC2101_ADC_CL(x) ((x<<4) & TSC2101_ADC_CL_MASK )
+#define TSC2101_ADC_CL_MASK (0x3<<4)
+#define TSC2101_ADC_CL_8MHZ_8BIT (0)
+#define TSC2101_ADC_CL_4MHZ_10BIT (1)
+#define TSC2101_ADC_CL_2MHZ_12BIT (2)
+#define TSC2101_ADC_CL_1MHZ_12BIT (3)
+#define TSC2101_ADC_CL0 (1<< 4)  
+
+/* ADC - Panel Voltage Stabilisation Time */
+#define TSC2101_ADC_PV(x)     ((x<<1) & TSC2101_ADC_PV_MASK )
+#define TSC2101_ADC_PV_MASK   (0x7<<1)
+#define TSC2101_ADC_PV_100ms  (0x7)  /* 100ms */
+#define TSC2101_ADC_PV_50ms   (0x6)  /* 50ms  */
+#define TSC2101_ADC_PV_10ms   (0x5)  /* 10ms  */
+#define TSC2101_ADC_PV_5ms    (0x4)  /* 5ms   */
+#define TSC2101_ADC_PV_1ms    (0x3)  /* 1ms   */
+#define TSC2101_ADC_PV_500us  (0x2)  /* 500us */
+#define TSC2101_ADC_PV_100us  (0x1)  /* 100us */
+#define TSC2101_ADC_PV_0s     (0x0)  /* 0s    */
+
+#define TSC2101_ADC_AVGFILT_MEAN     (0<<0)  /* Mean Average Filter */
+#define TSC2101_ADC_AVGFILT_MEDIAN   (1<<0)  /* Median Average Filter */
+
+#define TSC2101_ADC_x (1<< 0) // don't care
+
+#define TSC2101_CONFIG_DAV (1<<6)
+
+#define TSC2101_KEY_STC (1<<15) // keypad status
+#define TSC2101_KEY_SCS (1<<14) // keypad scan status
+
+
Index: linux-2.6.15-rc1/drivers/mfd/Kconfig
===================================================================
--- linux-2.6.15-rc1.orig/drivers/mfd/Kconfig	2005-11-12 01:43:36.000000000 +0000
+++ linux-2.6.15-rc1/drivers/mfd/Kconfig	2005-11-19 23:13:42.000000000 +0000
@@ -23,3 +23,13 @@
 	depends on MCP_UCB1200 && INPUT
 
 endmenu
+
+menu "Multi-Function Devices"
+
+config MFD_TSC2101
+	bool 
+	depends MACH_HX2750
+	help
+	  Support for TI TSC2101 Touchscreen and Audio Codec
+
+endmenu
Index: linux-2.6.15-rc1/drivers/input/touchscreen/tsc2101_ts.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.15-rc1/drivers/input/touchscreen/tsc2101_ts.c	2005-11-19 23:13:42.000000000 +0000
@@ -0,0 +1,56 @@
+/*
+ * Texas Instruments TSC2101 Touchscreen Driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@o-hand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/mfd/tsc2101.h>
+
+#define X_AXIS_MAX		3830
+#define X_AXIS_MIN		150
+#define Y_AXIS_MAX		3830
+#define Y_AXIS_MIN		190
+#define PRESSURE_MIN	0
+#define PRESSURE_MAX	20000
+
+void tsc2101_ts_report(struct tsc2101_data *tsc2101_ts, int x, int y, int p, int pendown)
+{
+	input_report_abs(&(tsc2101_ts->inputdevice), ABS_X, x);
+	input_report_abs(&(tsc2101_ts->inputdevice), ABS_Y, y);
+	input_report_abs(&(tsc2101_ts->inputdevice), ABS_PRESSURE, p);
+	input_report_key(&(tsc2101_ts->inputdevice), BTN_TOUCH, pendown);
+	input_sync(&(tsc2101_ts->inputdevice));
+
+	return;
+}
+
+void tsc2101_ts_setup(struct device *dev)
+{
+	struct tsc2101_data *tsc2101_ts = dev_get_drvdata(dev);
+	
+	init_input_dev(&(tsc2101_ts->inputdevice));
+	tsc2101_ts->inputdevice.name = "tsc2101_ts";
+	tsc2101_ts->inputdevice.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	tsc2101_ts->inputdevice.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+	input_set_abs_params(&tsc2101_ts->inputdevice, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+	input_set_abs_params(&tsc2101_ts->inputdevice, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+	input_set_abs_params(&tsc2101_ts->inputdevice, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
+	input_register_device(&(tsc2101_ts->inputdevice));
+
+	printk("tsc2101 touchscreen driver initialized\n");
+
+	return 0;
+}
+
Index: linux-2.6.15-rc1/drivers/input/touchscreen/Kconfig
===================================================================
--- linux-2.6.15-rc1.orig/drivers/input/touchscreen/Kconfig	2005-11-12 01:43:36.000000000 +0000
+++ linux-2.6.15-rc1/drivers/input/touchscreen/Kconfig	2005-11-19 23:13:42.000000000 +0000
@@ -95,4 +95,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called hp680_ts_input.
 
+config TOUCHSCREEN_TSC2101
+	tristate "TI TSC2101 touchscreen input driver"
+	depends on MACH_HX2750 && INPUT && INPUT_TOUCHSCREEN
+	default y	
+	help
+	  Say Y here to enable the touchscreen driver for the Texas 
+	  Instruments TSC2101 SoC Device.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ads7846_ts.
+
 endif
Index: linux-2.6.15-rc1/drivers/input/touchscreen/Makefile
===================================================================
--- linux-2.6.15-rc1.orig/drivers/input/touchscreen/Makefile	2005-11-12 01:43:36.000000000 +0000
+++ linux-2.6.15-rc1/drivers/input/touchscreen/Makefile	2005-11-19 23:13:42.000000000 +0000
@@ -11,3 +11,4 @@
 obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
 obj-$(CONFIG_TOUCHSCREEN_MK712)	+= mk712.o
 obj-$(CONFIG_TOUCHSCREEN_HP600)	+= hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2101)	+= tsc2101_ts.o
Index: linux-2.6.15-rc1/drivers/mfd/tsc2101.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.15-rc1/drivers/mfd/tsc2101.c	2005-11-19 23:33:05.000000000 +0000
@@ -0,0 +1,336 @@
+/*
+ * TI TSC2102 Common Code
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@o-hand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/tsc2101.h> 
+#include "tsc2101.h"
+
+extern void tsc2101_ts_setup(struct device *dev);
+extern void tsc2101_ts_report(struct tsc2101_data *devdata, int x, int y, int p, int pendown);
+
+static int tsc2101_regread(struct tsc2101_data *devdata, int regnum)
+{
+	int reg;
+	devdata->platform->send(TSC2101_READ, regnum, &reg, 1);
+	return reg;
+}
+
+static void tsc2101_regwrite(struct tsc2101_data *devdata, int regnum, int value)
+{
+	int reg=value;
+	devdata->platform->send(TSC2101_WRITE, regnum, &reg, 1);
+	return;
+}
+
+static int tsc2101_ts_penup(struct tsc2101_data *devdata)
+{
+	return !( tsc2101_regread(devdata, TSC2101_REG_STATUS) & TSC2101_STATUS_DAVAIL);
+}
+
+#define TSC2101_ADC_DEFAULT (TSC2101_ADC_RES(TSC2101_ADC_RES_12BITP) | TSC2101_ADC_AVG(TSC2101_ADC_4AVG) | TSC2101_ADC_CL(TSC2101_ADC_CL_1MHZ_12BIT) | TSC2101_ADC_PV(TSC2101_ADC_PV_500us) | TSC2101_ADC_AVGFILT_MEAN) 
+
+static void tsc2101_readdata(struct tsc2101_data *devdata, struct tsc2101_ts_event *ts_data)
+{
+	int z1,z2;
+	u32 values[4],status;
+
+	status=tsc2101_regread(devdata, TSC2101_REG_STATUS);
+    
+	if (status & (TSC2101_STATUS_XSTAT | TSC2101_STATUS_YSTAT | TSC2101_STATUS_Z1STAT 
+		| TSC2101_STATUS_Z2STAT)) {
+
+		/* Read X, Y, Z1 and Z2 */
+		devdata->platform->send(TSC2101_READ, TSC2101_REG_X, &values[0], 4);
+
+		ts_data->x=values[0];
+		ts_data->y=values[1];
+		z1=values[2];
+		z2=values[3];
+
+		/* Calculate Pressure */
+		if ((z1 != 0) && (ts_data->x!=0) && (ts_data->y!=0)) 
+			ts_data->p = ((ts_data->x * (z2 -z1) / z1));
+		else
+			ts_data->p=0;
+	}
+	
+    if (status & TSC2101_STATUS_BSTAT) {
+		devdata->platform->send(TSC2101_READ, TSC2101_REG_BAT, &values[0], 1);
+	   	devdata->miscdata.bat=values[0];
+	}	
+	if (status & TSC2101_STATUS_AX1STAT) {
+		devdata->platform->send(TSC2101_READ, TSC2101_REG_AUX1, &values[0], 1);
+		devdata->miscdata.aux1=values[0];
+	}
+    if (status & TSC2101_STATUS_AX2STAT) {
+    	devdata->platform->send(TSC2101_READ, TSC2101_REG_AUX2, &values[0], 1);
+    	devdata->miscdata.aux2=values[0];
+	}
+    if (status & TSC2101_STATUS_T1STAT) {
+    	devdata->platform->send(TSC2101_READ, TSC2101_REG_TEMP1, &values[0], 1);
+    	devdata->miscdata.temp1=values[0];
+	}
+    if (status & TSC2101_STATUS_T2STAT) {
+    	devdata->platform->send(TSC2101_READ, TSC2101_REG_TEMP2, &values[0], 1);
+    	devdata->miscdata.temp2=values[0];
+    }
+    if (devdata->mode == TSC2101_MODE_MISC) {
+		/* Switch back to touchscreen autoscan */
+		tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_PSM | TSC2101_ADC_ADMODE(0x2));
+		devdata->mode = TSC2101_MODE_TS;
+	}    	
+}
+
+static void tsc2101_ts_enable(struct tsc2101_data *devdata)
+{
+	//tsc2101_regwrite(devdata, TSC2101_REG_RESETCTL, 0xbb00);
+	
+	/* PINTDAV is data available only */
+	tsc2101_regwrite(devdata, TSC2101_REG_STATUS, 0x4000);
+
+	/* disable buffer mode */
+	tsc2101_regwrite(devdata, TSC2101_REG_BUFMODE, 0x0);
+
+	/* use internal reference, 100 usec power-up delay,
+	 * power down between conversions, 1.25V internal reference */
+	tsc2101_regwrite(devdata, TSC2101_REG_REF, 0x16);
+			   
+	/* enable touch detection, 84usec precharge time, 32 usec sense time */
+	tsc2101_regwrite(devdata, TSC2101_REG_CONFIG, 0x08);
+			   
+	/* 3 msec conversion delays  */
+	tsc2101_regwrite(devdata, TSC2101_REG_DELAY, 0x0900);
+
+	/*
+	 * TSC2101-controlled conversions
+	 * 12-bit samples
+	 * continuous X,Y,Z1,Z2 scan mode
+	 * average (mean) 4 samples per coordinate
+	 * 1 MHz internal conversion clock
+	 * 500 usec panel voltage stabilization delay
+	 */
+	tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_PSM | TSC2101_ADC_ADMODE(0x2));
+
+	return;
+}
+
+static void tsc2101_ts_disable(struct tsc2101_data *devdata)
+{
+	/* stop conversions and power down */
+	tsc2101_regwrite(devdata, TSC2101_REG_ADC, 0x4000);
+}
+
+static void ts_interrupt_main(struct tsc2101_data *devdata, int isTimer, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct tsc2101_ts_event ts_data;
+
+	spin_lock_irqsave(&devdata->lock, flags);
+
+    if (devdata->mode == TSC2101_MODE_MISC) {
+		tsc2101_readdata(devdata, &ts_data);
+		mod_timer(&(devdata->ts_timer), jiffies + HZ / 100);
+	} else if (devdata->platform->pendown()) {
+		devdata->pendown = 1;
+		tsc2101_readdata(devdata, &ts_data);
+		tsc2101_ts_report(devdata, ts_data.x, ts_data.y, ts_data.p, 1);
+		mod_timer(&(devdata->ts_timer), jiffies + HZ / 100);
+	} else if (devdata->pendown > 0 && devdata->pendown < 3) {
+		mod_timer(&(devdata->ts_timer), jiffies + HZ / 100);
+		devdata->pendown++;
+	} else {
+		if (devdata->pendown) 
+			tsc2101_ts_report(devdata, 0, 0, 0, 0);
+
+		devdata->pendown = 0;
+
+		set_irq_type(devdata->platform->irq,IRQT_FALLING);
+
+		/* This must be checked after set_irq_type() to make sure no data was missed */
+		if (devdata->platform->pendown()) {
+			tsc2101_readdata(devdata, &ts_data);
+			mod_timer(&(devdata->ts_timer), jiffies + HZ / 100);
+		} 
+	}
+	
+	spin_unlock_irqrestore(&devdata->lock, flags);
+}
+
+
+static void tsc2101_timer(unsigned long data)
+{
+	struct tsc2101_data *devdata = (struct tsc2101_data *) data;
+
+	ts_interrupt_main(devdata, 1, NULL);
+}
+
+static irqreturn_t tsc2101_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct tsc2101_data *devdata = dev_id;
+	
+	set_irq_type(devdata->platform->irq,IRQT_NOEDGE);
+	ts_interrupt_main(devdata, 0, regs);
+	return IRQ_HANDLED;
+}
+
+
+static void tsc2101_get_miscdata(struct tsc2101_data *devdata)
+{
+	static int i=0;
+	unsigned long flags;
+
+	if (devdata->pendown == 0) {
+		i++;
+		spin_lock_irqsave(&devdata->lock, flags);
+		devdata->mode = TSC2101_MODE_MISC;
+		if (i==1) 
+			tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_ADMODE(0x6));
+		else if (i==2) 
+			tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_ADMODE(0x7));
+		else if (i==3)
+			tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_ADMODE(0x8));
+		else if (i==4)
+			tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_ADMODE(0xa));
+		else if (i>=5) {
+			tsc2101_regwrite(devdata, TSC2101_REG_ADC, TSC2101_ADC_DEFAULT | TSC2101_ADC_ADMODE(0xc));
+			i=0;
+		}
+		spin_unlock_irqrestore(&devdata->lock, flags);
+	}
+}
+
+
+static void tsc2101_misc_timer(unsigned long data)
+{
+	
+	struct tsc2101_data *devdata = (struct tsc2101_data *) data;
+	tsc2101_get_miscdata(devdata);
+	mod_timer(&(devdata->misc_timer), jiffies + HZ);	
+}
+
+void tsc2101_print_miscdata(struct device *dev)
+{
+	struct tsc2101_data *devdata = dev_get_drvdata(dev);
+
+	printk(KERN_ERR "TSC2101 Bat:   %04x\n",devdata->miscdata.bat);
+	printk(KERN_ERR "TSC2101 Aux1:  %04x\n",devdata->miscdata.aux1);
+	printk(KERN_ERR "TSC2101 Aux2:  %04x\n",devdata->miscdata.aux2);
+	printk(KERN_ERR "TSC2101 Temp1: %04x\n",devdata->miscdata.temp1);
+	printk(KERN_ERR "TSC2101 Temp2: %04x\n",devdata->miscdata.temp2);
+}
+
+static int tsc2101_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct tsc2101_data *devdata = platform_get_drvdata(pdev);
+	
+	tsc2101_ts_disable(devdata);
+	devdata->platform->suspend();
+
+	return 0;
+}
+
+static int tsc2101_resume(struct platform_device *pdev)
+{
+	struct tsc2101_data *devdata = platform_get_drvdata(pdev);
+
+	devdata->platform->resume();
+	tsc2101_ts_enable(devdata);
+
+	return 0;
+}
+
+
+static int __init tsc2101_probe(struct platform_device *pdev)
+{
+	struct tsc2101_data *devdata;
+	struct tsc2101_ts_event ts_data;
+
+	if (!(devdata = kcalloc(1, sizeof(struct tsc2101_data), GFP_KERNEL)))
+		return -ENOMEM;
+	
+	platform_set_drvdata(pdev, devdata);
+	spin_lock_init(&devdata->lock);
+	devdata->platform = pdev->dev.platform_data;
+	devdata->mode = TSC2101_MODE_MISC;
+
+	init_timer(&devdata->ts_timer);
+	devdata->ts_timer.data = (unsigned long) devdata;
+	devdata->ts_timer.function = tsc2101_timer;
+
+	init_timer(&devdata->misc_timer);
+	devdata->misc_timer.data = (unsigned long) devdata;
+	devdata->misc_timer.function = tsc2101_misc_timer;
+
+	/* request irq */
+	if (request_irq(devdata->platform->irq, tsc2101_handler, 0, "tsc2101", devdata)) {
+		printk(KERN_ERR "tsc2101: Could not allocate touchscreen IRQ!\n");
+		kfree(devdata);
+		return -EINVAL;
+	}
+	
+	tsc2101_ts_setup(&pdev->dev);
+	tsc2101_ts_enable(devdata);
+
+	set_irq_type(devdata->platform->irq,IRQT_FALLING);
+	/* Check there is no pending data */
+	tsc2101_readdata(devdata, &ts_data);
+
+	mod_timer(&(devdata->misc_timer), jiffies + HZ);	
+	
+	return 0;
+}
+
+
+static  int __exit tsc2101_remove(struct device *dev)
+{
+	struct tsc2101_data *devdata = dev_get_drvdata(dev);
+
+	free_irq(devdata->platform->irq, devdata);
+	del_timer_sync(&devdata->ts_timer);
+	del_timer_sync(&devdata->misc_timer);
+	input_unregister_device(&devdata->inputdevice);
+	tsc2101_ts_disable(devdata);
+	kfree(devdata);
+	return 0;
+}
+
+static struct platform_driver tsc2101_driver = {
+	.probe 		= tsc2101_probe,
+	.remove 	= __exit_p(tsc2101_remove),
+	.suspend 	= tsc2101_suspend,
+	.resume 	= tsc2101_resume,
+	.driver		= {
+		.name	= "tsc2101",
+	},
+};
+
+static int __init tsc2101_init(void)
+{
+	return platform_driver_register(&tsc2101_driver);
+}
+
+static void __exit tsc2101_exit(void)
+{
+	platform_driver_unregister(&tsc2101_driver);
+}
+
+module_init(tsc2101_init);
+module_exit(tsc2101_exit);
+
+MODULE_LICENSE("GPL");
Index: linux-2.6.15-rc1/drivers/mfd/Makefile
===================================================================
--- linux-2.6.15-rc1.orig/drivers/mfd/Makefile	2005-11-12 01:43:36.000000000 +0000
+++ linux-2.6.15-rc1/drivers/mfd/Makefile	2005-11-19 23:28:36.000000000 +0000
@@ -10,3 +10,5 @@
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
 endif
+
+obj-$(CONFIG_MFD_TSC2101)      += tsc2101.o
Index: linux-2.6.15-rc1/include/linux/mfd/tsc2101.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.15-rc1/include/linux/mfd/tsc2101.h	2005-11-19 23:13:42.000000000 +0000
@@ -0,0 +1,49 @@
+/*
+ * TI TSC2101 Structure Definitions
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@o-hand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+struct tsc2101_ts_event {
+	short p;
+	short x;
+	short y;
+};
+
+struct tsc2101_misc_data {
+	short bat;
+	short aux1;
+	short aux2;
+	short temp1;
+	short temp2;
+};
+
+struct tsc2101_data {
+	spinlock_t lock;
+	int pendown;
+	int mode;
+	struct tsc2101_platform_info *platform;
+	struct input_dev inputdevice;
+	struct timer_list ts_timer;
+	struct timer_list misc_timer;
+	struct tsc2101_misc_data miscdata;
+};
+
+struct tsc2101_platform_info {
+	void (*send)(int read, int command, int *values, int numval);
+	void (*suspend) (void);
+	void (*resume) (void);
+	int irq;
+	int (*pendown) (void);
+};
+
+
+
+
