---
 drivers/input/touchscreen/Kconfig      |   13 +
 drivers/input/touchscreen/Makefile     |    1 
 drivers/input/touchscreen/tsc2101_ts.c |   67 ++++++
 drivers/mfd/Kconfig                    |    6 
 drivers/mfd/Makefile                   |    2 
 drivers/mfd/tsc2101.c                  |  340 +++++++++++++++++++++++++++++++++
 drivers/mfd/tsc2101.h                  |  158 +++++++++++++++
 include/linux/mfd/tsc2101.h            |   49 ++++
 8 files changed, 636 insertions(+)

Index: linux-2.6.23/drivers/mfd/tsc2101.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.23/drivers/mfd/tsc2101.h	2008-01-20 22:55:32.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.23/drivers/mfd/Kconfig
===================================================================
--- linux-2.6.23.orig/drivers/mfd/Kconfig	2008-01-20 22:54:34.000000000 +0000
+++ linux-2.6.23/drivers/mfd/Kconfig	2008-01-21 00:09:36.000000000 +0000
@@ -15,6 +15,12 @@ config MFD_SM501
 	  interface. The device may be connected by PCI or local bus with
 	  varying functions enabled.
 
+config MFD_TSC2101
+	bool
+	depends on MACH_HX2750
+	help
+	  Support for TI TSC2101 Touchscreen and Audio Codec
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
Index: linux-2.6.23/drivers/input/touchscreen/tsc2101_ts.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.23/drivers/input/touchscreen/tsc2101_ts.c	2008-01-21 00:02:12.000000000 +0000
@@ -0,0 +1,67 @@
+/*
+ * 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;
+}
+
+int tsc2101_ts_setup(struct device *dev)
+{
+	struct tsc2101_data *tsc2101_ts = dev_get_drvdata(dev);
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	tsc2101_ts->inputdevice = input_dev;
+
+	tsc2101_ts->inputdevice->name = "tsc2101_ts";
+	tsc2101_ts->inputdevice->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	tsc2101_ts->inputdevice->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(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);
+	err = input_register_device(tsc2101_ts->inputdevice);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+
+	printk("tsc2101 touchscreen driver initialized\n");
+
+	return 0;
+}
+
Index: linux-2.6.23/drivers/input/touchscreen/Kconfig
===================================================================
--- linux-2.6.23.orig/drivers/input/touchscreen/Kconfig	2008-01-20 22:54:34.000000000 +0000
+++ linux-2.6.23/drivers/input/touchscreen/Kconfig	2008-01-20 22:55:32.000000000 +0000
@@ -263,4 +263,17 @@ config TOUCHSCREEN_USB_GOTOP
 	bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
+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.23/drivers/input/touchscreen/Makefile
===================================================================
--- linux-2.6.23.orig/drivers/input/touchscreen/Makefile	2008-01-20 22:54:34.000000000 +0000
+++ linux-2.6.23/drivers/input/touchscreen/Makefile	2008-01-20 22:55:32.000000000 +0000
@@ -19,3 +19,4 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= pe
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2101)	+= tsc2101_ts.o
Index: linux-2.6.23/drivers/mfd/tsc2101.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.23/drivers/mfd/tsc2101.c	2008-01-20 22:55:32.000000000 +0000
@@ -0,0 +1,340 @@
+/*
+ * 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 <linux/irq.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)
+{
+	unsigned long flags;
+	struct tsc2101_ts_event ts_data;
+
+	spin_lock_irqsave(&devdata->lock, flags);
+
+	//printk(KERN_ERR "interrupt_main: %d, %d, %d, %d, %d, %d\n", ts_data.x, ts_data.y, ts_data.p, devdata->pendown, devdata->mode, devdata->platform->pendown());
+
+	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);
+}
+
+static irqreturn_t tsc2101_handler(int irq, void *dev_id)
+{
+	struct tsc2101_data *devdata = dev_id;
+
+	set_irq_type(devdata->platform->irq, IRQT_NOEDGE);
+	ts_interrupt_main(devdata, 0);
+	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, IRQF_TRIGGER_FALLING, "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.23/drivers/mfd/Makefile
===================================================================
--- linux-2.6.23.orig/drivers/mfd/Makefile	2008-01-20 22:54:34.000000000 +0000
+++ linux-2.6.23/drivers/mfd/Makefile	2008-01-21 00:09:36.000000000 +0000
@@ -12,3 +12,5 @@ obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
 endif
+
+obj-$(CONFIG_MFD_TSC2101)      += tsc2101.o
Index: linux-2.6.23/include/linux/mfd/tsc2101.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.23/include/linux/mfd/tsc2101.h	2008-01-20 22:55:32.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);
+};
+
+
+
+
