xref: /linux/drivers/input/touchscreen/ti_am335x_tsc.c (revision bb76dc09ddfc135c6c5e8eb7d3c583bfa8bdd439)
155c04de5SPatil, Rachna /*
255c04de5SPatil, Rachna  * TI Touch Screen driver
355c04de5SPatil, Rachna  *
455c04de5SPatil, Rachna  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
555c04de5SPatil, Rachna  *
655c04de5SPatil, Rachna  * This program is free software; you can redistribute it and/or
755c04de5SPatil, Rachna  * modify it under the terms of the GNU General Public License as
855c04de5SPatil, Rachna  * published by the Free Software Foundation version 2.
955c04de5SPatil, Rachna  *
1055c04de5SPatil, Rachna  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
1155c04de5SPatil, Rachna  * kind, whether express or implied; without even the implied warranty
1255c04de5SPatil, Rachna  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1355c04de5SPatil, Rachna  * GNU General Public License for more details.
1455c04de5SPatil, Rachna  */
1555c04de5SPatil, Rachna 
1655c04de5SPatil, Rachna 
1755c04de5SPatil, Rachna #include <linux/init.h>
1855c04de5SPatil, Rachna #include <linux/kernel.h>
1955c04de5SPatil, Rachna #include <linux/err.h>
2055c04de5SPatil, Rachna #include <linux/module.h>
2155c04de5SPatil, Rachna #include <linux/input.h>
2255c04de5SPatil, Rachna #include <linux/slab.h>
2355c04de5SPatil, Rachna #include <linux/interrupt.h>
2455c04de5SPatil, Rachna #include <linux/clk.h>
2555c04de5SPatil, Rachna #include <linux/platform_device.h>
2655c04de5SPatil, Rachna #include <linux/io.h>
2755c04de5SPatil, Rachna #include <linux/input/ti_am335x_tsc.h>
2855c04de5SPatil, Rachna #include <linux/delay.h>
2955c04de5SPatil, Rachna 
302b99bafaSPatil, Rachna #include <linux/mfd/ti_am335x_tscadc.h>
3155c04de5SPatil, Rachna 
3255c04de5SPatil, Rachna #define ADCFSM_STEPID		0x10
3355c04de5SPatil, Rachna #define SEQ_SETTLE		275
3455c04de5SPatil, Rachna #define MAX_12BIT		((1 << 12) - 1)
3555c04de5SPatil, Rachna 
36*bb76dc09SPatil, Rachna static const int config_pins[] = {
37*bb76dc09SPatil, Rachna 	STEPCONFIG_XPP,
38*bb76dc09SPatil, Rachna 	STEPCONFIG_XNN,
39*bb76dc09SPatil, Rachna 	STEPCONFIG_YPP,
40*bb76dc09SPatil, Rachna 	STEPCONFIG_YNN,
41*bb76dc09SPatil, Rachna };
42*bb76dc09SPatil, Rachna 
4355c04de5SPatil, Rachna struct titsc {
4455c04de5SPatil, Rachna 	struct input_dev	*input;
452b99bafaSPatil, Rachna 	struct ti_tscadc_dev	*mfd_tscadc;
4655c04de5SPatil, Rachna 	unsigned int		irq;
4755c04de5SPatil, Rachna 	unsigned int		wires;
4855c04de5SPatil, Rachna 	unsigned int		x_plate_resistance;
4955c04de5SPatil, Rachna 	bool			pen_down;
5055c04de5SPatil, Rachna 	int			steps_to_configure;
51*bb76dc09SPatil, Rachna 	u32			config_inp[4];
52*bb76dc09SPatil, Rachna 	u32			bit_xp, bit_xn, bit_yp, bit_yn;
53*bb76dc09SPatil, Rachna 	u32			inp_xp, inp_xn, inp_yp, inp_yn;
5455c04de5SPatil, Rachna };
5555c04de5SPatil, Rachna 
5655c04de5SPatil, Rachna static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
5755c04de5SPatil, Rachna {
582b99bafaSPatil, Rachna 	return readl(ts->mfd_tscadc->tscadc_base + reg);
5955c04de5SPatil, Rachna }
6055c04de5SPatil, Rachna 
6155c04de5SPatil, Rachna static void titsc_writel(struct titsc *tsc, unsigned int reg,
6255c04de5SPatil, Rachna 					unsigned int val)
6355c04de5SPatil, Rachna {
642b99bafaSPatil, Rachna 	writel(val, tsc->mfd_tscadc->tscadc_base + reg);
6555c04de5SPatil, Rachna }
6655c04de5SPatil, Rachna 
67*bb76dc09SPatil, Rachna static int titsc_config_wires(struct titsc *ts_dev)
68*bb76dc09SPatil, Rachna {
69*bb76dc09SPatil, Rachna 	u32 analog_line[4];
70*bb76dc09SPatil, Rachna 	u32 wire_order[4];
71*bb76dc09SPatil, Rachna 	int i, bit_cfg;
72*bb76dc09SPatil, Rachna 
73*bb76dc09SPatil, Rachna 	for (i = 0; i < 4; i++) {
74*bb76dc09SPatil, Rachna 		/*
75*bb76dc09SPatil, Rachna 		 * Get the order in which TSC wires are attached
76*bb76dc09SPatil, Rachna 		 * w.r.t. each of the analog input lines on the EVM.
77*bb76dc09SPatil, Rachna 		 */
78*bb76dc09SPatil, Rachna 		analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4;
79*bb76dc09SPatil, Rachna 		wire_order[i] = ts_dev->config_inp[i] & 0x0F;
80*bb76dc09SPatil, Rachna 		if (WARN_ON(analog_line[i] > 7))
81*bb76dc09SPatil, Rachna 			return -EINVAL;
82*bb76dc09SPatil, Rachna 		if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins)))
83*bb76dc09SPatil, Rachna 			return -EINVAL;
84*bb76dc09SPatil, Rachna 	}
85*bb76dc09SPatil, Rachna 
86*bb76dc09SPatil, Rachna 	for (i = 0; i < 4; i++) {
87*bb76dc09SPatil, Rachna 		int an_line;
88*bb76dc09SPatil, Rachna 		int wi_order;
89*bb76dc09SPatil, Rachna 
90*bb76dc09SPatil, Rachna 		an_line = analog_line[i];
91*bb76dc09SPatil, Rachna 		wi_order = wire_order[i];
92*bb76dc09SPatil, Rachna 		bit_cfg = config_pins[wi_order];
93*bb76dc09SPatil, Rachna 		if (bit_cfg == 0)
94*bb76dc09SPatil, Rachna 			return -EINVAL;
95*bb76dc09SPatil, Rachna 		switch (wi_order) {
96*bb76dc09SPatil, Rachna 		case 0:
97*bb76dc09SPatil, Rachna 			ts_dev->bit_xp = bit_cfg;
98*bb76dc09SPatil, Rachna 			ts_dev->inp_xp = an_line;
99*bb76dc09SPatil, Rachna 			break;
100*bb76dc09SPatil, Rachna 
101*bb76dc09SPatil, Rachna 		case 1:
102*bb76dc09SPatil, Rachna 			ts_dev->bit_xn = bit_cfg;
103*bb76dc09SPatil, Rachna 			ts_dev->inp_xn = an_line;
104*bb76dc09SPatil, Rachna 			break;
105*bb76dc09SPatil, Rachna 
106*bb76dc09SPatil, Rachna 		case 2:
107*bb76dc09SPatil, Rachna 			ts_dev->bit_yp = bit_cfg;
108*bb76dc09SPatil, Rachna 			ts_dev->inp_yp = an_line;
109*bb76dc09SPatil, Rachna 			break;
110*bb76dc09SPatil, Rachna 		case 3:
111*bb76dc09SPatil, Rachna 			ts_dev->bit_yn = bit_cfg;
112*bb76dc09SPatil, Rachna 			ts_dev->inp_yn = an_line;
113*bb76dc09SPatil, Rachna 			break;
114*bb76dc09SPatil, Rachna 		}
115*bb76dc09SPatil, Rachna 	}
116*bb76dc09SPatil, Rachna 	return 0;
117*bb76dc09SPatil, Rachna }
118*bb76dc09SPatil, Rachna 
11955c04de5SPatil, Rachna static void titsc_step_config(struct titsc *ts_dev)
12055c04de5SPatil, Rachna {
12155c04de5SPatil, Rachna 	unsigned int	config;
122abeccee4SPatil, Rachna 	unsigned int	stepenable = 0;
12355c04de5SPatil, Rachna 	int i, total_steps;
12455c04de5SPatil, Rachna 
12555c04de5SPatil, Rachna 	/* Configure the Step registers */
12655c04de5SPatil, Rachna 	total_steps = 2 * ts_dev->steps_to_configure;
12755c04de5SPatil, Rachna 
12855c04de5SPatil, Rachna 	config = STEPCONFIG_MODE_HWSYNC |
129*bb76dc09SPatil, Rachna 			STEPCONFIG_AVG_16 | ts_dev->bit_xp;
13055c04de5SPatil, Rachna 	switch (ts_dev->wires) {
13155c04de5SPatil, Rachna 	case 4:
132*bb76dc09SPatil, Rachna 		config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
13355c04de5SPatil, Rachna 		break;
13455c04de5SPatil, Rachna 	case 5:
135*bb76dc09SPatil, Rachna 		config |= ts_dev->bit_yn |
136*bb76dc09SPatil, Rachna 				STEPCONFIG_INP_AN4 | ts_dev->bit_xn |
137*bb76dc09SPatil, Rachna 				ts_dev->bit_yp;
13855c04de5SPatil, Rachna 		break;
13955c04de5SPatil, Rachna 	case 8:
140*bb76dc09SPatil, Rachna 		config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
14155c04de5SPatil, Rachna 		break;
14255c04de5SPatil, Rachna 	}
14355c04de5SPatil, Rachna 
14455c04de5SPatil, Rachna 	for (i = 1; i <= ts_dev->steps_to_configure; i++) {
14555c04de5SPatil, Rachna 		titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
14655c04de5SPatil, Rachna 		titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
14755c04de5SPatil, Rachna 	}
14855c04de5SPatil, Rachna 
14955c04de5SPatil, Rachna 	config = 0;
15055c04de5SPatil, Rachna 	config = STEPCONFIG_MODE_HWSYNC |
151*bb76dc09SPatil, Rachna 			STEPCONFIG_AVG_16 | ts_dev->bit_yn |
15255c04de5SPatil, Rachna 			STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1;
15355c04de5SPatil, Rachna 	switch (ts_dev->wires) {
15455c04de5SPatil, Rachna 	case 4:
155*bb76dc09SPatil, Rachna 		config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
15655c04de5SPatil, Rachna 		break;
15755c04de5SPatil, Rachna 	case 5:
158*bb76dc09SPatil, Rachna 		config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 |
159*bb76dc09SPatil, Rachna 				ts_dev->bit_xn | ts_dev->bit_yp;
16055c04de5SPatil, Rachna 		break;
16155c04de5SPatil, Rachna 	case 8:
162*bb76dc09SPatil, Rachna 		config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
16355c04de5SPatil, Rachna 		break;
16455c04de5SPatil, Rachna 	}
16555c04de5SPatil, Rachna 
16655c04de5SPatil, Rachna 	for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) {
16755c04de5SPatil, Rachna 		titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
16855c04de5SPatil, Rachna 		titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
16955c04de5SPatil, Rachna 	}
17055c04de5SPatil, Rachna 
17155c04de5SPatil, Rachna 	config = 0;
17255c04de5SPatil, Rachna 	/* Charge step configuration */
173*bb76dc09SPatil, Rachna 	config = ts_dev->bit_xp | ts_dev->bit_yn |
17455c04de5SPatil, Rachna 			STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
175*bb76dc09SPatil, Rachna 			STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp);
17655c04de5SPatil, Rachna 
17755c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_CHARGECONFIG, config);
17855c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
17955c04de5SPatil, Rachna 
18055c04de5SPatil, Rachna 	config = 0;
18155c04de5SPatil, Rachna 	/* Configure to calculate pressure */
18255c04de5SPatil, Rachna 	config = STEPCONFIG_MODE_HWSYNC |
183*bb76dc09SPatil, Rachna 			STEPCONFIG_AVG_16 | ts_dev->bit_yp |
184*bb76dc09SPatil, Rachna 			ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
185*bb76dc09SPatil, Rachna 			STEPCONFIG_INP(ts_dev->inp_xp);
18655c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config);
18755c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1),
18855c04de5SPatil, Rachna 			STEPCONFIG_OPENDLY);
18955c04de5SPatil, Rachna 
190*bb76dc09SPatil, Rachna 	config |= STEPCONFIG_INP(ts_dev->inp_yn) | STEPCONFIG_FIFO1;
19155c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config);
19255c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2),
19355c04de5SPatil, Rachna 			STEPCONFIG_OPENDLY);
19455c04de5SPatil, Rachna 
195abeccee4SPatil, Rachna 	/* The steps1 … end and bit 0 for TS_Charge */
196abeccee4SPatil, Rachna 	stepenable = (1 << (total_steps + 2)) - 1;
197abeccee4SPatil, Rachna 	am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable);
19855c04de5SPatil, Rachna }
19955c04de5SPatil, Rachna 
20055c04de5SPatil, Rachna static void titsc_read_coordinates(struct titsc *ts_dev,
20155c04de5SPatil, Rachna 				    unsigned int *x, unsigned int *y)
20255c04de5SPatil, Rachna {
20355c04de5SPatil, Rachna 	unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
20455c04de5SPatil, Rachna 	unsigned int prev_val_x = ~0, prev_val_y = ~0;
20555c04de5SPatil, Rachna 	unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
20655c04de5SPatil, Rachna 	unsigned int read, diff;
2072b99bafaSPatil, Rachna 	unsigned int i, channel;
20855c04de5SPatil, Rachna 
20955c04de5SPatil, Rachna 	/*
21055c04de5SPatil, Rachna 	 * Delta filter is used to remove large variations in sampled
21155c04de5SPatil, Rachna 	 * values from ADC. The filter tries to predict where the next
21255c04de5SPatil, Rachna 	 * coordinate could be. This is done by taking a previous
21355c04de5SPatil, Rachna 	 * coordinate and subtracting it form current one. Further the
21455c04de5SPatil, Rachna 	 * algorithm compares the difference with that of a present value,
21555c04de5SPatil, Rachna 	 * if true the value is reported to the sub system.
21655c04de5SPatil, Rachna 	 */
21755c04de5SPatil, Rachna 	for (i = 0; i < fifocount - 1; i++) {
2182b99bafaSPatil, Rachna 		read = titsc_readl(ts_dev, REG_FIFO0);
2192b99bafaSPatil, Rachna 		channel = read & 0xf0000;
2202b99bafaSPatil, Rachna 		channel = channel >> 0x10;
2212b99bafaSPatil, Rachna 		if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) {
2222b99bafaSPatil, Rachna 			read &= 0xfff;
22355c04de5SPatil, Rachna 			diff = abs(read - prev_val_x);
22455c04de5SPatil, Rachna 			if (diff < prev_diff_x) {
22555c04de5SPatil, Rachna 				prev_diff_x = diff;
22655c04de5SPatil, Rachna 				*x = read;
22755c04de5SPatil, Rachna 			}
22855c04de5SPatil, Rachna 			prev_val_x = read;
2292b99bafaSPatil, Rachna 		}
23055c04de5SPatil, Rachna 
2312b99bafaSPatil, Rachna 		read = titsc_readl(ts_dev, REG_FIFO1);
2322b99bafaSPatil, Rachna 		channel = read & 0xf0000;
2332b99bafaSPatil, Rachna 		channel = channel >> 0x10;
2342b99bafaSPatil, Rachna 		if ((channel >= ts_dev->steps_to_configure) &&
2352b99bafaSPatil, Rachna 			(channel < (2 * ts_dev->steps_to_configure - 1))) {
2362b99bafaSPatil, Rachna 			read &= 0xfff;
23755c04de5SPatil, Rachna 			diff = abs(read - prev_val_y);
23855c04de5SPatil, Rachna 			if (diff < prev_diff_y) {
23955c04de5SPatil, Rachna 				prev_diff_y = diff;
24055c04de5SPatil, Rachna 				*y = read;
24155c04de5SPatil, Rachna 			}
24255c04de5SPatil, Rachna 			prev_val_y = read;
24355c04de5SPatil, Rachna 		}
24455c04de5SPatil, Rachna 	}
2452b99bafaSPatil, Rachna }
24655c04de5SPatil, Rachna 
24755c04de5SPatil, Rachna static irqreturn_t titsc_irq(int irq, void *dev)
24855c04de5SPatil, Rachna {
24955c04de5SPatil, Rachna 	struct titsc *ts_dev = dev;
25055c04de5SPatil, Rachna 	struct input_dev *input_dev = ts_dev->input;
25155c04de5SPatil, Rachna 	unsigned int status, irqclr = 0;
25255c04de5SPatil, Rachna 	unsigned int x = 0, y = 0;
25355c04de5SPatil, Rachna 	unsigned int z1, z2, z;
25455c04de5SPatil, Rachna 	unsigned int fsm;
2552b99bafaSPatil, Rachna 	unsigned int fifo1count, fifo0count;
2562b99bafaSPatil, Rachna 	int i;
25755c04de5SPatil, Rachna 
25855c04de5SPatil, Rachna 	status = titsc_readl(ts_dev, REG_IRQSTATUS);
25955c04de5SPatil, Rachna 	if (status & IRQENB_FIFO0THRES) {
26055c04de5SPatil, Rachna 		titsc_read_coordinates(ts_dev, &x, &y);
26155c04de5SPatil, Rachna 
26255c04de5SPatil, Rachna 		z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff;
26355c04de5SPatil, Rachna 		z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff;
26455c04de5SPatil, Rachna 
2652b99bafaSPatil, Rachna 		fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT);
2662b99bafaSPatil, Rachna 		for (i = 0; i < fifo1count; i++)
2672b99bafaSPatil, Rachna 			titsc_readl(ts_dev, REG_FIFO1);
2682b99bafaSPatil, Rachna 
2692b99bafaSPatil, Rachna 		fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT);
2702b99bafaSPatil, Rachna 		for (i = 0; i < fifo0count; i++)
2712b99bafaSPatil, Rachna 			titsc_readl(ts_dev, REG_FIFO0);
2722b99bafaSPatil, Rachna 
27355c04de5SPatil, Rachna 		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
27455c04de5SPatil, Rachna 			/*
27555c04de5SPatil, Rachna 			 * Calculate pressure using formula
27655c04de5SPatil, Rachna 			 * Resistance(touch) = x plate resistance *
27755c04de5SPatil, Rachna 			 * x postion/4096 * ((z2 / z1) - 1)
27855c04de5SPatil, Rachna 			 */
27955c04de5SPatil, Rachna 			z = z2 - z1;
28055c04de5SPatil, Rachna 			z *= x;
28155c04de5SPatil, Rachna 			z *= ts_dev->x_plate_resistance;
28255c04de5SPatil, Rachna 			z /= z1;
28355c04de5SPatil, Rachna 			z = (z + 2047) >> 12;
28455c04de5SPatil, Rachna 
28555c04de5SPatil, Rachna 			if (z <= MAX_12BIT) {
28655c04de5SPatil, Rachna 				input_report_abs(input_dev, ABS_X, x);
28755c04de5SPatil, Rachna 				input_report_abs(input_dev, ABS_Y, y);
28855c04de5SPatil, Rachna 				input_report_abs(input_dev, ABS_PRESSURE, z);
28955c04de5SPatil, Rachna 				input_report_key(input_dev, BTN_TOUCH, 1);
29055c04de5SPatil, Rachna 				input_sync(input_dev);
29155c04de5SPatil, Rachna 			}
29255c04de5SPatil, Rachna 		}
29355c04de5SPatil, Rachna 		irqclr |= IRQENB_FIFO0THRES;
29455c04de5SPatil, Rachna 	}
29555c04de5SPatil, Rachna 
29655c04de5SPatil, Rachna 	/*
29755c04de5SPatil, Rachna 	 * Time for sequencer to settle, to read
29855c04de5SPatil, Rachna 	 * correct state of the sequencer.
29955c04de5SPatil, Rachna 	 */
30055c04de5SPatil, Rachna 	udelay(SEQ_SETTLE);
30155c04de5SPatil, Rachna 
30255c04de5SPatil, Rachna 	status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
30355c04de5SPatil, Rachna 	if (status & IRQENB_PENUP) {
30455c04de5SPatil, Rachna 		/* Pen up event */
30555c04de5SPatil, Rachna 		fsm = titsc_readl(ts_dev, REG_ADCFSM);
30655c04de5SPatil, Rachna 		if (fsm == ADCFSM_STEPID) {
30755c04de5SPatil, Rachna 			ts_dev->pen_down = false;
30855c04de5SPatil, Rachna 			input_report_key(input_dev, BTN_TOUCH, 0);
30955c04de5SPatil, Rachna 			input_report_abs(input_dev, ABS_PRESSURE, 0);
31055c04de5SPatil, Rachna 			input_sync(input_dev);
31155c04de5SPatil, Rachna 		} else {
31255c04de5SPatil, Rachna 			ts_dev->pen_down = true;
31355c04de5SPatil, Rachna 		}
31455c04de5SPatil, Rachna 		irqclr |= IRQENB_PENUP;
31555c04de5SPatil, Rachna 	}
31655c04de5SPatil, Rachna 
31755c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
31855c04de5SPatil, Rachna 
319abeccee4SPatil, Rachna 	am335x_tsc_se_update(ts_dev->mfd_tscadc);
32055c04de5SPatil, Rachna 	return IRQ_HANDLED;
32155c04de5SPatil, Rachna }
32255c04de5SPatil, Rachna 
32355c04de5SPatil, Rachna /*
32455c04de5SPatil, Rachna  * The functions for inserting/removing driver as a module.
32555c04de5SPatil, Rachna  */
32655c04de5SPatil, Rachna 
32731564cbdSLinus Torvalds static int titsc_probe(struct platform_device *pdev)
32855c04de5SPatil, Rachna {
32955c04de5SPatil, Rachna 	struct titsc *ts_dev;
33055c04de5SPatil, Rachna 	struct input_dev *input_dev;
331a9bce1b0SSebastian Andrzej Siewior 	struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev);
3322b99bafaSPatil, Rachna 	struct mfd_tscadc_board	*pdata;
33355c04de5SPatil, Rachna 	int err;
3342b99bafaSPatil, Rachna 
3352b99bafaSPatil, Rachna 	pdata = tscadc_dev->dev->platform_data;
33655c04de5SPatil, Rachna 
33755c04de5SPatil, Rachna 	if (!pdata) {
3382b99bafaSPatil, Rachna 		dev_err(&pdev->dev, "Could not find platform data\n");
33955c04de5SPatil, Rachna 		return -EINVAL;
34055c04de5SPatil, Rachna 	}
34155c04de5SPatil, Rachna 
34255c04de5SPatil, Rachna 	/* Allocate memory for device */
34355c04de5SPatil, Rachna 	ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL);
34455c04de5SPatil, Rachna 	input_dev = input_allocate_device();
34555c04de5SPatil, Rachna 	if (!ts_dev || !input_dev) {
34655c04de5SPatil, Rachna 		dev_err(&pdev->dev, "failed to allocate memory.\n");
34755c04de5SPatil, Rachna 		err = -ENOMEM;
34855c04de5SPatil, Rachna 		goto err_free_mem;
34955c04de5SPatil, Rachna 	}
35055c04de5SPatil, Rachna 
3512b99bafaSPatil, Rachna 	tscadc_dev->tsc = ts_dev;
3522b99bafaSPatil, Rachna 	ts_dev->mfd_tscadc = tscadc_dev;
35355c04de5SPatil, Rachna 	ts_dev->input = input_dev;
3542b99bafaSPatil, Rachna 	ts_dev->irq = tscadc_dev->irq;
3552b99bafaSPatil, Rachna 	ts_dev->wires = pdata->tsc_init->wires;
3562b99bafaSPatil, Rachna 	ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance;
3572b99bafaSPatil, Rachna 	ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure;
358*bb76dc09SPatil, Rachna 	memcpy(ts_dev->config_inp, pdata->tsc_init->wire_config,
359*bb76dc09SPatil, Rachna 			sizeof(pdata->tsc_init->wire_config));
36055c04de5SPatil, Rachna 
36155c04de5SPatil, Rachna 	err = request_irq(ts_dev->irq, titsc_irq,
36255c04de5SPatil, Rachna 			  0, pdev->dev.driver->name, ts_dev);
36355c04de5SPatil, Rachna 	if (err) {
36455c04de5SPatil, Rachna 		dev_err(&pdev->dev, "failed to allocate irq.\n");
3652b99bafaSPatil, Rachna 		goto err_free_mem;
36655c04de5SPatil, Rachna 	}
36755c04de5SPatil, Rachna 
36855c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
369*bb76dc09SPatil, Rachna 	err = titsc_config_wires(ts_dev);
370*bb76dc09SPatil, Rachna 	if (err) {
371*bb76dc09SPatil, Rachna 		dev_err(&pdev->dev, "wrong i/p wire configuration\n");
372*bb76dc09SPatil, Rachna 		goto err_free_irq;
373*bb76dc09SPatil, Rachna 	}
37455c04de5SPatil, Rachna 	titsc_step_config(ts_dev);
37555c04de5SPatil, Rachna 	titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure);
37655c04de5SPatil, Rachna 
3772b99bafaSPatil, Rachna 	input_dev->name = "ti-tsc";
37855c04de5SPatil, Rachna 	input_dev->dev.parent = &pdev->dev;
37955c04de5SPatil, Rachna 
38055c04de5SPatil, Rachna 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
38155c04de5SPatil, Rachna 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
38255c04de5SPatil, Rachna 
38355c04de5SPatil, Rachna 	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
38455c04de5SPatil, Rachna 	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
38555c04de5SPatil, Rachna 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
38655c04de5SPatil, Rachna 
38755c04de5SPatil, Rachna 	/* register to the input system */
38855c04de5SPatil, Rachna 	err = input_register_device(input_dev);
38955c04de5SPatil, Rachna 	if (err)
3902b99bafaSPatil, Rachna 		goto err_free_irq;
39155c04de5SPatil, Rachna 
39255c04de5SPatil, Rachna 	platform_set_drvdata(pdev, ts_dev);
39355c04de5SPatil, Rachna 	return 0;
39455c04de5SPatil, Rachna 
39555c04de5SPatil, Rachna err_free_irq:
39655c04de5SPatil, Rachna 	free_irq(ts_dev->irq, ts_dev);
39755c04de5SPatil, Rachna err_free_mem:
39855c04de5SPatil, Rachna 	input_free_device(input_dev);
39955c04de5SPatil, Rachna 	kfree(ts_dev);
40055c04de5SPatil, Rachna 	return err;
40155c04de5SPatil, Rachna }
40255c04de5SPatil, Rachna 
40331564cbdSLinus Torvalds static int titsc_remove(struct platform_device *pdev)
40455c04de5SPatil, Rachna {
405a9bce1b0SSebastian Andrzej Siewior 	struct titsc *ts_dev = platform_get_drvdata(pdev);
406a9bce1b0SSebastian Andrzej Siewior 	u32 steps;
40755c04de5SPatil, Rachna 
40855c04de5SPatil, Rachna 	free_irq(ts_dev->irq, ts_dev);
40955c04de5SPatil, Rachna 
410abeccee4SPatil, Rachna 	/* total steps followed by the enable mask */
411abeccee4SPatil, Rachna 	steps = 2 * ts_dev->steps_to_configure + 2;
412abeccee4SPatil, Rachna 	steps = (1 << steps) - 1;
413abeccee4SPatil, Rachna 	am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps);
414abeccee4SPatil, Rachna 
41555c04de5SPatil, Rachna 	input_unregister_device(ts_dev->input);
41655c04de5SPatil, Rachna 
41755c04de5SPatil, Rachna 	platform_set_drvdata(pdev, NULL);
4182b99bafaSPatil, Rachna 	kfree(ts_dev);
41955c04de5SPatil, Rachna 	return 0;
42055c04de5SPatil, Rachna }
42155c04de5SPatil, Rachna 
4222b99bafaSPatil, Rachna #ifdef CONFIG_PM
4232b99bafaSPatil, Rachna static int titsc_suspend(struct device *dev)
4242b99bafaSPatil, Rachna {
425a9bce1b0SSebastian Andrzej Siewior 	struct titsc *ts_dev = dev_get_drvdata(dev);
426a9bce1b0SSebastian Andrzej Siewior 	struct ti_tscadc_dev *tscadc_dev;
4272b99bafaSPatil, Rachna 	unsigned int idle;
4282b99bafaSPatil, Rachna 
429a9bce1b0SSebastian Andrzej Siewior 	tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
4302b99bafaSPatil, Rachna 	if (device_may_wakeup(tscadc_dev->dev)) {
4312b99bafaSPatil, Rachna 		idle = titsc_readl(ts_dev, REG_IRQENABLE);
4322b99bafaSPatil, Rachna 		titsc_writel(ts_dev, REG_IRQENABLE,
4332b99bafaSPatil, Rachna 				(idle | IRQENB_HW_PEN));
4342b99bafaSPatil, Rachna 		titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
4352b99bafaSPatil, Rachna 	}
4362b99bafaSPatil, Rachna 	return 0;
4372b99bafaSPatil, Rachna }
4382b99bafaSPatil, Rachna 
4392b99bafaSPatil, Rachna static int titsc_resume(struct device *dev)
4402b99bafaSPatil, Rachna {
441a9bce1b0SSebastian Andrzej Siewior 	struct titsc *ts_dev = dev_get_drvdata(dev);
442a9bce1b0SSebastian Andrzej Siewior 	struct ti_tscadc_dev *tscadc_dev;
4432b99bafaSPatil, Rachna 
444a9bce1b0SSebastian Andrzej Siewior 	tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
4452b99bafaSPatil, Rachna 	if (device_may_wakeup(tscadc_dev->dev)) {
4462b99bafaSPatil, Rachna 		titsc_writel(ts_dev, REG_IRQWAKEUP,
4472b99bafaSPatil, Rachna 				0x00);
4482b99bafaSPatil, Rachna 		titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
4492b99bafaSPatil, Rachna 	}
4502b99bafaSPatil, Rachna 	titsc_step_config(ts_dev);
4512b99bafaSPatil, Rachna 	titsc_writel(ts_dev, REG_FIFO0THR,
4522b99bafaSPatil, Rachna 			ts_dev->steps_to_configure);
4532b99bafaSPatil, Rachna 	return 0;
4542b99bafaSPatil, Rachna }
4552b99bafaSPatil, Rachna 
4562b99bafaSPatil, Rachna static const struct dev_pm_ops titsc_pm_ops = {
4572b99bafaSPatil, Rachna 	.suspend = titsc_suspend,
4582b99bafaSPatil, Rachna 	.resume  = titsc_resume,
4592b99bafaSPatil, Rachna };
4602b99bafaSPatil, Rachna #define TITSC_PM_OPS (&titsc_pm_ops)
4612b99bafaSPatil, Rachna #else
4622b99bafaSPatil, Rachna #define TITSC_PM_OPS NULL
4632b99bafaSPatil, Rachna #endif
4642b99bafaSPatil, Rachna 
46555c04de5SPatil, Rachna static struct platform_driver ti_tsc_driver = {
46655c04de5SPatil, Rachna 	.probe	= titsc_probe,
46731564cbdSLinus Torvalds 	.remove	= titsc_remove,
46855c04de5SPatil, Rachna 	.driver	= {
46955c04de5SPatil, Rachna 		.name   = "tsc",
47055c04de5SPatil, Rachna 		.owner	= THIS_MODULE,
4712b99bafaSPatil, Rachna 		.pm	= TITSC_PM_OPS,
47255c04de5SPatil, Rachna 	},
47355c04de5SPatil, Rachna };
47455c04de5SPatil, Rachna module_platform_driver(ti_tsc_driver);
47555c04de5SPatil, Rachna 
47655c04de5SPatil, Rachna MODULE_DESCRIPTION("TI touchscreen controller driver");
47755c04de5SPatil, Rachna MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
47855c04de5SPatil, Rachna MODULE_LICENSE("GPL");
479