From 4c5ada67509fc0a47941813900c03b842e6452d1 Mon Sep 17 00:00:00 2001
From: Patil, Rachna <rachna@ti.com>
Date: Fri, 11 Nov 2011 18:28:54 +0530
Subject: [PATCH 3/9] AM335x: Add support for pressure measurement on TSC.

This patch adds support for pressure measurement configurations
on TSC. Along with X and Y co-ordinates pressure is also reported to
the sub-system.

Signed-off-by: Patil, Rachna <rachna@ti.com>
---
 arch/arm/mach-omap2/board-am335xevm.c |    1 +
 drivers/input/touchscreen/ti_tscadc.c |   77 +++++++++++++++++++++++++++------
 include/linux/input/ti_tscadc.h       |    3 +-
 3 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
index ecda26a..d7af6dd 100644
--- a/arch/arm/mach-omap2/board-am335xevm.c
+++ b/arch/arm/mach-omap2/board-am335xevm.c
@@ -194,6 +194,7 @@ static struct resource tsc_resources[]  = {
 
 static struct tsc_data am335x_touchscreen_data  = {
 	.wires  = 4,
+	.x_plate_resistance = 200,
 };
 
 static struct platform_device tsc_device = {
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
index 021db7f..9783435 100644
--- a/drivers/input/touchscreen/ti_tscadc.c
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -41,6 +41,10 @@
 #define TSCADC_REG_CHARGEDELAY		0x060
 #define TSCADC_REG_STEPCONFIG(n)	(0x64 + ((n-1) * 8))
 #define TSCADC_REG_STEPDELAY(n)		(0x68 + ((n-1) * 8))
+#define TSCADC_REG_STEPCONFIG13		0x0C4
+#define TSCADC_REG_STEPDELAY13		0x0C8
+#define TSCADC_REG_STEPCONFIG14		0x0CC
+#define TSCADC_REG_STEPDELAY14		0x0D0
 #define TSCADC_REG_FIFO0CNT		0xE4
 #define TSCADC_REG_FIFO0THR		0xE8
 #define TSCADC_REG_FIFO1CNT		0xF0
@@ -50,7 +54,7 @@
 
 /*	Register Bitfields	*/
 #define TSCADC_IRQWKUP_ENB		BIT(0)
-#define TSCADC_STPENB_STEPENB		0x1fFF
+#define TSCADC_STPENB_STEPENB		0x7FFF
 #define TSCADC_IRQENB_FIFO0THRES	BIT(2)
 #define TSCADC_IRQENB_FIFO1THRES	BIT(5)
 #define TSCADC_IRQENB_PENUP		BIT(9)
@@ -71,10 +75,11 @@
 #define TSCADC_STEPCONFIG_IDLE_INP	(1 << 22)
 #define TSCADC_STEPCONFIG_OPENDLY	0x018
 #define TSCADC_STEPCONFIG_SAMPLEDLY	0x88
-#define TSCADC_STEPCHARGE_INM_SWAP     BIT(16)
-#define TSCADC_STEPCHARGE_INM          BIT(15)
-#define TSCADC_STEPCHARGE_INP_SWAP     BIT(20)
-#define TSCADC_STEPCHARGE_INP          BIT(19)
+#define TSCADC_STEPCONFIG_Z1		(3 << 19)
+#define TSCADC_STEPCHARGE_INM_SWAP	BIT(16)
+#define TSCADC_STEPCHARGE_INM		BIT(15)
+#define TSCADC_STEPCHARGE_INP_SWAP	BIT(20)
+#define TSCADC_STEPCHARGE_INP		BIT(19)
 #define TSCADC_STEPCHARGE_RFM		(1 << 23)
 #define TSCADC_STEPCHARGE_DELAY		0x1
 #define TSCADC_CNTRLREG_TSCSSENB	BIT(0)
@@ -98,6 +103,7 @@ struct tscadc {
 	struct input_dev	*input;
 	int			wires;
 	int			analog_input;
+	int			x_plate_resistance;
 	struct clk		*clk;
 	int			irq;
 	void __iomem		*tsc_base;
@@ -118,6 +124,7 @@ static void tsc_step_config(struct tscadc *ts_dev)
 {
 	unsigned int	stepconfigx = 0, stepconfigy = 0;
 	unsigned int	delay, chargeconfig = 0;
+	unsigned int	stepconfigz1 = 0, stepconfigz2 = 0;
 	int i;
 
 	/* Configure the Step registers */
@@ -205,6 +212,18 @@ static void tsc_step_config(struct tscadc *ts_dev)
 	tscadc_writel(ts_dev, TSCADC_REG_CHARGECONFIG, chargeconfig);
 	tscadc_writel(ts_dev, TSCADC_REG_CHARGEDELAY, TSCADC_STEPCHARGE_DELAY);
 
+	 /* Configure to calculate pressure */
+	stepconfigz1 = TSCADC_STEPCONFIG_MODE_HWSYNC |
+				TSCADC_STEPCONFIG_2SAMPLES_AVG |
+				TSCADC_STEPCONFIG_XNP |
+				TSCADC_STEPCONFIG_YPN | TSCADC_STEPCONFIG_INM;
+	stepconfigz2 = stepconfigz1 | TSCADC_STEPCONFIG_Z1 |
+				TSCADC_STEPCONFIG_FIFO1;
+	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG13, stepconfigz1);
+	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY13, delay);
+	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG14, stepconfigz2);
+	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY14, delay);
+
 	tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB);
 }
 
@@ -235,14 +254,14 @@ static irqreturn_t tscadc_interrupt(int irq, void *dev)
 	unsigned int		prev_diff_x = ~0, prev_diff_y = ~0;
 	unsigned int		cur_diff_x = 0, cur_diff_y = 0;
 	unsigned int		val_x = 0, val_y = 0, diffx = 0, diffy = 0;
+	unsigned int		z1 = 0, z2 = 0, z = 0;
 
 	status = tscadc_readl(ts_dev, TSCADC_REG_IRQSTATUS);
 
 	if (status & TSCADC_IRQENB_FIFO1THRES) {
 		fifo0count = tscadc_readl(ts_dev, TSCADC_REG_FIFO0CNT);
 		fifo1count = tscadc_readl(ts_dev, TSCADC_REG_FIFO1CNT);
-
-		for (i = 0; i < fifo0count; i++) {
+		for (i = 0; i < (fifo0count-1); i++) {
 			readx1 = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
 			readx1 = readx1 & 0xfff;
 			if (readx1 > prev_val_x)
@@ -281,12 +300,39 @@ static irqreturn_t tscadc_interrupt(int irq, void *dev)
 		bckup_x = val_x;
 		bckup_y = val_y;
 
-		if (pen == 0) {
-			if ((diffx < 15) && (diffy < 15)) {
-				input_report_abs(input_dev, ABS_X, val_x);
-				input_report_abs(input_dev, ABS_Y, val_y);
-				input_report_key(input_dev, BTN_TOUCH, 1);
-				input_sync(input_dev);
+		z1 = ((tscadc_readl(ts_dev, TSCADC_REG_FIFO0)) & 0xfff);
+		z2 = ((tscadc_readl(ts_dev, TSCADC_REG_FIFO1)) & 0xfff);
+
+		if ((z1 != 0) && (z2 != 0)) {
+			/*
+			 * cal pressure using formula
+			 * Resistance(touch) = x plate resistance *
+			 * x postion/4096 * ((z2 / z1) - 1)
+			 */
+			z = z2 - z1;
+			z *= val_x;
+			z *= ts_dev->x_plate_resistance;
+			z /= z1;
+			z = (z + 2047) >> 12;
+
+			/*
+			 * Sample found inconsistent by debouncing
+			 * or pressure is beyond the maximum.
+			 * Don't report it to user space.
+			 */
+			if (pen == 0) {
+				if ((diffx < 15) && (diffy < 15)
+						&& (z <= MAX_12BIT)) {
+					input_report_abs(input_dev, ABS_X,
+							val_x);
+					input_report_abs(input_dev, ABS_Y,
+							val_y);
+					input_report_abs(input_dev, ABS_PRESSURE,
+							z);
+					input_report_key(input_dev, BTN_TOUCH,
+							1);
+					input_sync(input_dev);
+				}
 			}
 		}
 		irqclr |= TSCADC_IRQENB_FIFO1THRES;
@@ -303,6 +349,7 @@ static irqreturn_t tscadc_interrupt(int irq, void *dev)
 			bckup_x = 0;
 			bckup_y = 0;
 			input_report_key(input_dev, BTN_TOUCH, 0);
+			input_report_abs(input_dev, ABS_PRESSURE, 0);
 			input_sync(input_dev);
 		} else {
 			pen = 0;
@@ -403,6 +450,7 @@ static	int __devinit tscadc_probe(struct platform_device *pdev)
 
 	ts_dev->wires = pdata->wires;
 	ts_dev->analog_input = pdata->analog_input;
+	ts_dev->x_plate_resistance = pdata->x_plate_resistance;
 
 	/* Set the control register bits */
 	ctrl = TSCADC_CNTRLREG_STEPCONFIGWRT |
@@ -430,7 +478,7 @@ static	int __devinit tscadc_probe(struct platform_device *pdev)
 
 	tsc_step_config(ts_dev);
 
-	tscadc_writel(ts_dev, TSCADC_REG_FIFO1THR, 5);
+	tscadc_writel(ts_dev, TSCADC_REG_FIFO1THR, 6);
 
 	ctrl |= TSCADC_CNTRLREG_TSCSSENB;
 	tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
@@ -443,6 +491,7 @@ static	int __devinit tscadc_probe(struct platform_device *pdev)
 
 	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
 	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
 
 	/* register to the input system */
 	err = input_register_device(input_dev);
diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h
index b9d9a46..2c547bb 100644
--- a/include/linux/input/ti_tscadc.h
+++ b/include/linux/input/ti_tscadc.h
@@ -11,10 +11,11 @@
  *			XPUL = AN0,YPLL = AN1,XNUR = AN2,
  *			YNLR = AN3, then set this variable to
  *			0.
+ * @x_plate_resistance:	X plate resistance.
  */
 
 struct tsc_data {
 	int wires;
 	int analog_input;
-
+	int x_plate_resistance;
 };
-- 
1.7.2.5

