xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/ti_am335x_tsc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * TI Touch Screen driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
7*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License as
8*4882a593Smuzhiyun  * published by the Free Software Foundation version 2.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11*4882a593Smuzhiyun  * kind, whether express or implied; without even the implied warranty
12*4882a593Smuzhiyun  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*4882a593Smuzhiyun  * GNU General Public License for more details.
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/err.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/input.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/interrupt.h>
23*4882a593Smuzhiyun #include <linux/clk.h>
24*4882a593Smuzhiyun #include <linux/platform_device.h>
25*4882a593Smuzhiyun #include <linux/io.h>
26*4882a593Smuzhiyun #include <linux/delay.h>
27*4882a593Smuzhiyun #include <linux/of.h>
28*4882a593Smuzhiyun #include <linux/of_device.h>
29*4882a593Smuzhiyun #include <linux/sort.h>
30*4882a593Smuzhiyun #include <linux/pm_wakeirq.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include <linux/mfd/ti_am335x_tscadc.h>
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define ADCFSM_STEPID		0x10
35*4882a593Smuzhiyun #define SEQ_SETTLE		275
36*4882a593Smuzhiyun #define MAX_12BIT		((1 << 12) - 1)
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define TSC_IRQENB_MASK		(IRQENB_FIFO0THRES | IRQENB_EOS | IRQENB_HW_PEN)
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static const int config_pins[] = {
41*4882a593Smuzhiyun 	STEPCONFIG_XPP,
42*4882a593Smuzhiyun 	STEPCONFIG_XNN,
43*4882a593Smuzhiyun 	STEPCONFIG_YPP,
44*4882a593Smuzhiyun 	STEPCONFIG_YNN,
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun struct titsc {
48*4882a593Smuzhiyun 	struct input_dev	*input;
49*4882a593Smuzhiyun 	struct ti_tscadc_dev	*mfd_tscadc;
50*4882a593Smuzhiyun 	struct device		*dev;
51*4882a593Smuzhiyun 	unsigned int		irq;
52*4882a593Smuzhiyun 	unsigned int		wires;
53*4882a593Smuzhiyun 	unsigned int		x_plate_resistance;
54*4882a593Smuzhiyun 	bool			pen_down;
55*4882a593Smuzhiyun 	int			coordinate_readouts;
56*4882a593Smuzhiyun 	u32			config_inp[4];
57*4882a593Smuzhiyun 	u32			bit_xp, bit_xn, bit_yp, bit_yn;
58*4882a593Smuzhiyun 	u32			inp_xp, inp_xn, inp_yp, inp_yn;
59*4882a593Smuzhiyun 	u32			step_mask;
60*4882a593Smuzhiyun 	u32			charge_delay;
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
titsc_readl(struct titsc * ts,unsigned int reg)63*4882a593Smuzhiyun static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	return readl(ts->mfd_tscadc->tscadc_base + reg);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
titsc_writel(struct titsc * tsc,unsigned int reg,unsigned int val)68*4882a593Smuzhiyun static void titsc_writel(struct titsc *tsc, unsigned int reg,
69*4882a593Smuzhiyun 					unsigned int val)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	writel(val, tsc->mfd_tscadc->tscadc_base + reg);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
titsc_config_wires(struct titsc * ts_dev)74*4882a593Smuzhiyun static int titsc_config_wires(struct titsc *ts_dev)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	u32 analog_line[4];
77*4882a593Smuzhiyun 	u32 wire_order[4];
78*4882a593Smuzhiyun 	int i, bit_cfg;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
81*4882a593Smuzhiyun 		/*
82*4882a593Smuzhiyun 		 * Get the order in which TSC wires are attached
83*4882a593Smuzhiyun 		 * w.r.t. each of the analog input lines on the EVM.
84*4882a593Smuzhiyun 		 */
85*4882a593Smuzhiyun 		analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4;
86*4882a593Smuzhiyun 		wire_order[i] = ts_dev->config_inp[i] & 0x0F;
87*4882a593Smuzhiyun 		if (WARN_ON(analog_line[i] > 7))
88*4882a593Smuzhiyun 			return -EINVAL;
89*4882a593Smuzhiyun 		if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins)))
90*4882a593Smuzhiyun 			return -EINVAL;
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
94*4882a593Smuzhiyun 		int an_line;
95*4882a593Smuzhiyun 		int wi_order;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 		an_line = analog_line[i];
98*4882a593Smuzhiyun 		wi_order = wire_order[i];
99*4882a593Smuzhiyun 		bit_cfg = config_pins[wi_order];
100*4882a593Smuzhiyun 		if (bit_cfg == 0)
101*4882a593Smuzhiyun 			return -EINVAL;
102*4882a593Smuzhiyun 		switch (wi_order) {
103*4882a593Smuzhiyun 		case 0:
104*4882a593Smuzhiyun 			ts_dev->bit_xp = bit_cfg;
105*4882a593Smuzhiyun 			ts_dev->inp_xp = an_line;
106*4882a593Smuzhiyun 			break;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 		case 1:
109*4882a593Smuzhiyun 			ts_dev->bit_xn = bit_cfg;
110*4882a593Smuzhiyun 			ts_dev->inp_xn = an_line;
111*4882a593Smuzhiyun 			break;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		case 2:
114*4882a593Smuzhiyun 			ts_dev->bit_yp = bit_cfg;
115*4882a593Smuzhiyun 			ts_dev->inp_yp = an_line;
116*4882a593Smuzhiyun 			break;
117*4882a593Smuzhiyun 		case 3:
118*4882a593Smuzhiyun 			ts_dev->bit_yn = bit_cfg;
119*4882a593Smuzhiyun 			ts_dev->inp_yn = an_line;
120*4882a593Smuzhiyun 			break;
121*4882a593Smuzhiyun 		}
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 	return 0;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
titsc_step_config(struct titsc * ts_dev)126*4882a593Smuzhiyun static void titsc_step_config(struct titsc *ts_dev)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	unsigned int	config;
129*4882a593Smuzhiyun 	int i;
130*4882a593Smuzhiyun 	int end_step, first_step, tsc_steps;
131*4882a593Smuzhiyun 	u32 stepenable;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	config = STEPCONFIG_MODE_HWSYNC |
134*4882a593Smuzhiyun 			STEPCONFIG_AVG_16 | ts_dev->bit_xp;
135*4882a593Smuzhiyun 	switch (ts_dev->wires) {
136*4882a593Smuzhiyun 	case 4:
137*4882a593Smuzhiyun 		config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
138*4882a593Smuzhiyun 		break;
139*4882a593Smuzhiyun 	case 5:
140*4882a593Smuzhiyun 		config |= ts_dev->bit_yn |
141*4882a593Smuzhiyun 				STEPCONFIG_INP_AN4 | ts_dev->bit_xn |
142*4882a593Smuzhiyun 				ts_dev->bit_yp;
143*4882a593Smuzhiyun 		break;
144*4882a593Smuzhiyun 	case 8:
145*4882a593Smuzhiyun 		config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	tsc_steps = ts_dev->coordinate_readouts * 2 + 2;
150*4882a593Smuzhiyun 	first_step = TOTAL_STEPS - tsc_steps;
151*4882a593Smuzhiyun 	/* Steps 16 to 16-coordinate_readouts is for X */
152*4882a593Smuzhiyun 	end_step = first_step + tsc_steps;
153*4882a593Smuzhiyun 	for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) {
154*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
155*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	config = 0;
159*4882a593Smuzhiyun 	config = STEPCONFIG_MODE_HWSYNC |
160*4882a593Smuzhiyun 			STEPCONFIG_AVG_16 | ts_dev->bit_yn |
161*4882a593Smuzhiyun 			STEPCONFIG_INM_ADCREFM;
162*4882a593Smuzhiyun 	switch (ts_dev->wires) {
163*4882a593Smuzhiyun 	case 4:
164*4882a593Smuzhiyun 		config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
165*4882a593Smuzhiyun 		break;
166*4882a593Smuzhiyun 	case 5:
167*4882a593Smuzhiyun 		config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 |
168*4882a593Smuzhiyun 				STEPCONFIG_XNP | STEPCONFIG_YPN;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 	case 8:
171*4882a593Smuzhiyun 		config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
172*4882a593Smuzhiyun 		break;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	/* 1 ... coordinate_readouts is for Y */
176*4882a593Smuzhiyun 	end_step = first_step + ts_dev->coordinate_readouts;
177*4882a593Smuzhiyun 	for (i = first_step; i < end_step; i++) {
178*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
179*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	/* Make CHARGECONFIG same as IDLECONFIG */
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	config = titsc_readl(ts_dev, REG_IDLECONFIG);
185*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_CHARGECONFIG, config);
186*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_CHARGEDELAY, ts_dev->charge_delay);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	/* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */
189*4882a593Smuzhiyun 	config = STEPCONFIG_MODE_HWSYNC |
190*4882a593Smuzhiyun 			STEPCONFIG_AVG_16 | ts_dev->bit_yp |
191*4882a593Smuzhiyun 			ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
192*4882a593Smuzhiyun 			STEPCONFIG_INP(ts_dev->inp_xp);
193*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
194*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_STEPDELAY(end_step),
195*4882a593Smuzhiyun 			STEPCONFIG_OPENDLY);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	end_step++;
198*4882a593Smuzhiyun 	config |= STEPCONFIG_INP(ts_dev->inp_yn);
199*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
200*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_STEPDELAY(end_step),
201*4882a593Smuzhiyun 			STEPCONFIG_OPENDLY);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */
204*4882a593Smuzhiyun 	stepenable = 1;
205*4882a593Smuzhiyun 	for (i = 0; i < tsc_steps; i++)
206*4882a593Smuzhiyun 		stepenable |= 1 << (first_step + i + 1);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	ts_dev->step_mask = stepenable;
209*4882a593Smuzhiyun 	am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
titsc_cmp_coord(const void * a,const void * b)212*4882a593Smuzhiyun static int titsc_cmp_coord(const void *a, const void *b)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	return *(int *)a - *(int *)b;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
titsc_read_coordinates(struct titsc * ts_dev,u32 * x,u32 * y,u32 * z1,u32 * z2)217*4882a593Smuzhiyun static void titsc_read_coordinates(struct titsc *ts_dev,
218*4882a593Smuzhiyun 		u32 *x, u32 *y, u32 *z1, u32 *z2)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	unsigned int yvals[7], xvals[7];
221*4882a593Smuzhiyun 	unsigned int i, xsum = 0, ysum = 0;
222*4882a593Smuzhiyun 	unsigned int creads = ts_dev->coordinate_readouts;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	for (i = 0; i < creads; i++) {
225*4882a593Smuzhiyun 		yvals[i] = titsc_readl(ts_dev, REG_FIFO0);
226*4882a593Smuzhiyun 		yvals[i] &= 0xfff;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	*z1 = titsc_readl(ts_dev, REG_FIFO0);
230*4882a593Smuzhiyun 	*z1 &= 0xfff;
231*4882a593Smuzhiyun 	*z2 = titsc_readl(ts_dev, REG_FIFO0);
232*4882a593Smuzhiyun 	*z2 &= 0xfff;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	for (i = 0; i < creads; i++) {
235*4882a593Smuzhiyun 		xvals[i] = titsc_readl(ts_dev, REG_FIFO0);
236*4882a593Smuzhiyun 		xvals[i] &= 0xfff;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/*
240*4882a593Smuzhiyun 	 * If co-ordinates readouts is less than 4 then
241*4882a593Smuzhiyun 	 * report the average. In case of 4 or more
242*4882a593Smuzhiyun 	 * readouts, sort the co-ordinate samples, drop
243*4882a593Smuzhiyun 	 * min and max values and report the average of
244*4882a593Smuzhiyun 	 * remaining values.
245*4882a593Smuzhiyun 	 */
246*4882a593Smuzhiyun 	if (creads <=  3) {
247*4882a593Smuzhiyun 		for (i = 0; i < creads; i++) {
248*4882a593Smuzhiyun 			ysum += yvals[i];
249*4882a593Smuzhiyun 			xsum += xvals[i];
250*4882a593Smuzhiyun 		}
251*4882a593Smuzhiyun 		ysum /= creads;
252*4882a593Smuzhiyun 		xsum /= creads;
253*4882a593Smuzhiyun 	} else {
254*4882a593Smuzhiyun 		sort(yvals, creads, sizeof(unsigned int),
255*4882a593Smuzhiyun 		     titsc_cmp_coord, NULL);
256*4882a593Smuzhiyun 		sort(xvals, creads, sizeof(unsigned int),
257*4882a593Smuzhiyun 		     titsc_cmp_coord, NULL);
258*4882a593Smuzhiyun 		for (i = 1; i < creads - 1; i++) {
259*4882a593Smuzhiyun 			ysum += yvals[i];
260*4882a593Smuzhiyun 			xsum += xvals[i];
261*4882a593Smuzhiyun 		}
262*4882a593Smuzhiyun 		ysum /= creads - 2;
263*4882a593Smuzhiyun 		xsum /= creads - 2;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 	*y = ysum;
266*4882a593Smuzhiyun 	*x = xsum;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
titsc_irq(int irq,void * dev)269*4882a593Smuzhiyun static irqreturn_t titsc_irq(int irq, void *dev)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	struct titsc *ts_dev = dev;
272*4882a593Smuzhiyun 	struct input_dev *input_dev = ts_dev->input;
273*4882a593Smuzhiyun 	unsigned int fsm, status, irqclr = 0;
274*4882a593Smuzhiyun 	unsigned int x = 0, y = 0;
275*4882a593Smuzhiyun 	unsigned int z1, z2, z;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
278*4882a593Smuzhiyun 	if (status & IRQENB_HW_PEN) {
279*4882a593Smuzhiyun 		ts_dev->pen_down = true;
280*4882a593Smuzhiyun 		irqclr |= IRQENB_HW_PEN;
281*4882a593Smuzhiyun 		pm_stay_awake(ts_dev->dev);
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	if (status & IRQENB_PENUP) {
285*4882a593Smuzhiyun 		fsm = titsc_readl(ts_dev, REG_ADCFSM);
286*4882a593Smuzhiyun 		if (fsm == ADCFSM_STEPID) {
287*4882a593Smuzhiyun 			ts_dev->pen_down = false;
288*4882a593Smuzhiyun 			input_report_key(input_dev, BTN_TOUCH, 0);
289*4882a593Smuzhiyun 			input_report_abs(input_dev, ABS_PRESSURE, 0);
290*4882a593Smuzhiyun 			input_sync(input_dev);
291*4882a593Smuzhiyun 			pm_relax(ts_dev->dev);
292*4882a593Smuzhiyun 		} else {
293*4882a593Smuzhiyun 			ts_dev->pen_down = true;
294*4882a593Smuzhiyun 		}
295*4882a593Smuzhiyun 		irqclr |= IRQENB_PENUP;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (status & IRQENB_EOS)
299*4882a593Smuzhiyun 		irqclr |= IRQENB_EOS;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	/*
302*4882a593Smuzhiyun 	 * ADC and touchscreen share the IRQ line.
303*4882a593Smuzhiyun 	 * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only
304*4882a593Smuzhiyun 	 */
305*4882a593Smuzhiyun 	if (status & IRQENB_FIFO0THRES) {
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
310*4882a593Smuzhiyun 			/*
311*4882a593Smuzhiyun 			 * Calculate pressure using formula
312*4882a593Smuzhiyun 			 * Resistance(touch) = x plate resistance *
313*4882a593Smuzhiyun 			 * x postion/4096 * ((z2 / z1) - 1)
314*4882a593Smuzhiyun 			 */
315*4882a593Smuzhiyun 			z = z1 - z2;
316*4882a593Smuzhiyun 			z *= x;
317*4882a593Smuzhiyun 			z *= ts_dev->x_plate_resistance;
318*4882a593Smuzhiyun 			z /= z2;
319*4882a593Smuzhiyun 			z = (z + 2047) >> 12;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 			if (z <= MAX_12BIT) {
322*4882a593Smuzhiyun 				input_report_abs(input_dev, ABS_X, x);
323*4882a593Smuzhiyun 				input_report_abs(input_dev, ABS_Y, y);
324*4882a593Smuzhiyun 				input_report_abs(input_dev, ABS_PRESSURE, z);
325*4882a593Smuzhiyun 				input_report_key(input_dev, BTN_TOUCH, 1);
326*4882a593Smuzhiyun 				input_sync(input_dev);
327*4882a593Smuzhiyun 			}
328*4882a593Smuzhiyun 		}
329*4882a593Smuzhiyun 		irqclr |= IRQENB_FIFO0THRES;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 	if (irqclr) {
332*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
333*4882a593Smuzhiyun 		if (status & IRQENB_EOS)
334*4882a593Smuzhiyun 			am335x_tsc_se_set_cache(ts_dev->mfd_tscadc,
335*4882a593Smuzhiyun 						ts_dev->step_mask);
336*4882a593Smuzhiyun 		return IRQ_HANDLED;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 	return IRQ_NONE;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
titsc_parse_dt(struct platform_device * pdev,struct titsc * ts_dev)341*4882a593Smuzhiyun static int titsc_parse_dt(struct platform_device *pdev,
342*4882a593Smuzhiyun 					struct titsc *ts_dev)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	struct device_node *node = pdev->dev.of_node;
345*4882a593Smuzhiyun 	int err;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (!node)
348*4882a593Smuzhiyun 		return -EINVAL;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	err = of_property_read_u32(node, "ti,wires", &ts_dev->wires);
351*4882a593Smuzhiyun 	if (err < 0)
352*4882a593Smuzhiyun 		return err;
353*4882a593Smuzhiyun 	switch (ts_dev->wires) {
354*4882a593Smuzhiyun 	case 4:
355*4882a593Smuzhiyun 	case 5:
356*4882a593Smuzhiyun 	case 8:
357*4882a593Smuzhiyun 		break;
358*4882a593Smuzhiyun 	default:
359*4882a593Smuzhiyun 		return -EINVAL;
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	err = of_property_read_u32(node, "ti,x-plate-resistance",
363*4882a593Smuzhiyun 			&ts_dev->x_plate_resistance);
364*4882a593Smuzhiyun 	if (err < 0)
365*4882a593Smuzhiyun 		return err;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/*
368*4882a593Smuzhiyun 	 * Try with the new binding first. If it fails, try again with
369*4882a593Smuzhiyun 	 * bogus, miss-spelled version.
370*4882a593Smuzhiyun 	 */
371*4882a593Smuzhiyun 	err = of_property_read_u32(node, "ti,coordinate-readouts",
372*4882a593Smuzhiyun 			&ts_dev->coordinate_readouts);
373*4882a593Smuzhiyun 	if (err < 0) {
374*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "please use 'ti,coordinate-readouts' instead\n");
375*4882a593Smuzhiyun 		err = of_property_read_u32(node, "ti,coordiante-readouts",
376*4882a593Smuzhiyun 				&ts_dev->coordinate_readouts);
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (err < 0)
380*4882a593Smuzhiyun 		return err;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (ts_dev->coordinate_readouts <= 0) {
383*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
384*4882a593Smuzhiyun 			 "invalid co-ordinate readouts, resetting it to 5\n");
385*4882a593Smuzhiyun 		ts_dev->coordinate_readouts = 5;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	err = of_property_read_u32(node, "ti,charge-delay",
389*4882a593Smuzhiyun 				   &ts_dev->charge_delay);
390*4882a593Smuzhiyun 	/*
391*4882a593Smuzhiyun 	 * If ti,charge-delay value is not specified, then use
392*4882a593Smuzhiyun 	 * CHARGEDLY_OPENDLY as the default value.
393*4882a593Smuzhiyun 	 */
394*4882a593Smuzhiyun 	if (err < 0) {
395*4882a593Smuzhiyun 		ts_dev->charge_delay = CHARGEDLY_OPENDLY;
396*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "ti,charge-delay not specified\n");
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	return of_property_read_u32_array(node, "ti,wire-config",
400*4882a593Smuzhiyun 			ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun  * The functions for inserting/removing driver as a module.
405*4882a593Smuzhiyun  */
406*4882a593Smuzhiyun 
titsc_probe(struct platform_device * pdev)407*4882a593Smuzhiyun static int titsc_probe(struct platform_device *pdev)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct titsc *ts_dev;
410*4882a593Smuzhiyun 	struct input_dev *input_dev;
411*4882a593Smuzhiyun 	struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev);
412*4882a593Smuzhiyun 	int err;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/* Allocate memory for device */
415*4882a593Smuzhiyun 	ts_dev = kzalloc(sizeof(*ts_dev), GFP_KERNEL);
416*4882a593Smuzhiyun 	input_dev = input_allocate_device();
417*4882a593Smuzhiyun 	if (!ts_dev || !input_dev) {
418*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to allocate memory.\n");
419*4882a593Smuzhiyun 		err = -ENOMEM;
420*4882a593Smuzhiyun 		goto err_free_mem;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	tscadc_dev->tsc = ts_dev;
424*4882a593Smuzhiyun 	ts_dev->mfd_tscadc = tscadc_dev;
425*4882a593Smuzhiyun 	ts_dev->input = input_dev;
426*4882a593Smuzhiyun 	ts_dev->irq = tscadc_dev->irq;
427*4882a593Smuzhiyun 	ts_dev->dev = &pdev->dev;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	err = titsc_parse_dt(pdev, ts_dev);
430*4882a593Smuzhiyun 	if (err) {
431*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Could not find valid DT data.\n");
432*4882a593Smuzhiyun 		goto err_free_mem;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	err = request_irq(ts_dev->irq, titsc_irq,
436*4882a593Smuzhiyun 			  IRQF_SHARED, pdev->dev.driver->name, ts_dev);
437*4882a593Smuzhiyun 	if (err) {
438*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to allocate irq.\n");
439*4882a593Smuzhiyun 		goto err_free_mem;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	device_init_wakeup(&pdev->dev, true);
443*4882a593Smuzhiyun 	err = dev_pm_set_wake_irq(&pdev->dev, ts_dev->irq);
444*4882a593Smuzhiyun 	if (err)
445*4882a593Smuzhiyun 		dev_err(&pdev->dev, "irq wake enable failed.\n");
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK);
448*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
449*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS);
450*4882a593Smuzhiyun 	err = titsc_config_wires(ts_dev);
451*4882a593Smuzhiyun 	if (err) {
452*4882a593Smuzhiyun 		dev_err(&pdev->dev, "wrong i/p wire configuration\n");
453*4882a593Smuzhiyun 		goto err_free_irq;
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 	titsc_step_config(ts_dev);
456*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_FIFO0THR,
457*4882a593Smuzhiyun 			ts_dev->coordinate_readouts * 2 + 2 - 1);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	input_dev->name = "ti-tsc";
460*4882a593Smuzhiyun 	input_dev->dev.parent = &pdev->dev;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
463*4882a593Smuzhiyun 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
466*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
467*4882a593Smuzhiyun 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	/* register to the input system */
470*4882a593Smuzhiyun 	err = input_register_device(input_dev);
471*4882a593Smuzhiyun 	if (err)
472*4882a593Smuzhiyun 		goto err_free_irq;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	platform_set_drvdata(pdev, ts_dev);
475*4882a593Smuzhiyun 	return 0;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun err_free_irq:
478*4882a593Smuzhiyun 	dev_pm_clear_wake_irq(&pdev->dev);
479*4882a593Smuzhiyun 	device_init_wakeup(&pdev->dev, false);
480*4882a593Smuzhiyun 	free_irq(ts_dev->irq, ts_dev);
481*4882a593Smuzhiyun err_free_mem:
482*4882a593Smuzhiyun 	input_free_device(input_dev);
483*4882a593Smuzhiyun 	kfree(ts_dev);
484*4882a593Smuzhiyun 	return err;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
titsc_remove(struct platform_device * pdev)487*4882a593Smuzhiyun static int titsc_remove(struct platform_device *pdev)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun 	struct titsc *ts_dev = platform_get_drvdata(pdev);
490*4882a593Smuzhiyun 	u32 steps;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	dev_pm_clear_wake_irq(&pdev->dev);
493*4882a593Smuzhiyun 	device_init_wakeup(&pdev->dev, false);
494*4882a593Smuzhiyun 	free_irq(ts_dev->irq, ts_dev);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/* total steps followed by the enable mask */
497*4882a593Smuzhiyun 	steps = 2 * ts_dev->coordinate_readouts + 2;
498*4882a593Smuzhiyun 	steps = (1 << steps) - 1;
499*4882a593Smuzhiyun 	am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	input_unregister_device(ts_dev->input);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	kfree(ts_dev);
504*4882a593Smuzhiyun 	return 0;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
titsc_suspend(struct device * dev)507*4882a593Smuzhiyun static int __maybe_unused titsc_suspend(struct device *dev)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	struct titsc *ts_dev = dev_get_drvdata(dev);
510*4882a593Smuzhiyun 	unsigned int idle;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	if (device_may_wakeup(dev)) {
513*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK);
514*4882a593Smuzhiyun 		idle = titsc_readl(ts_dev, REG_IRQENABLE);
515*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_IRQENABLE,
516*4882a593Smuzhiyun 				(idle | IRQENB_HW_PEN));
517*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 	return 0;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun 
titsc_resume(struct device * dev)522*4882a593Smuzhiyun static int __maybe_unused titsc_resume(struct device *dev)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun 	struct titsc *ts_dev = dev_get_drvdata(dev);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (device_may_wakeup(dev)) {
527*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_IRQWAKEUP,
528*4882a593Smuzhiyun 				0x00);
529*4882a593Smuzhiyun 		titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
530*4882a593Smuzhiyun 		pm_relax(dev);
531*4882a593Smuzhiyun 	}
532*4882a593Smuzhiyun 	titsc_step_config(ts_dev);
533*4882a593Smuzhiyun 	titsc_writel(ts_dev, REG_FIFO0THR,
534*4882a593Smuzhiyun 			ts_dev->coordinate_readouts * 2 + 2 - 1);
535*4882a593Smuzhiyun 	return 0;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(titsc_pm_ops, titsc_suspend, titsc_resume);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun static const struct of_device_id ti_tsc_dt_ids[] = {
541*4882a593Smuzhiyun 	{ .compatible = "ti,am3359-tsc", },
542*4882a593Smuzhiyun 	{ }
543*4882a593Smuzhiyun };
544*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun static struct platform_driver ti_tsc_driver = {
547*4882a593Smuzhiyun 	.probe	= titsc_probe,
548*4882a593Smuzhiyun 	.remove	= titsc_remove,
549*4882a593Smuzhiyun 	.driver	= {
550*4882a593Smuzhiyun 		.name   = "TI-am335x-tsc",
551*4882a593Smuzhiyun 		.pm	= &titsc_pm_ops,
552*4882a593Smuzhiyun 		.of_match_table = ti_tsc_dt_ids,
553*4882a593Smuzhiyun 	},
554*4882a593Smuzhiyun };
555*4882a593Smuzhiyun module_platform_driver(ti_tsc_driver);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun MODULE_DESCRIPTION("TI touchscreen controller driver");
558*4882a593Smuzhiyun MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
559*4882a593Smuzhiyun MODULE_LICENSE("GPL");
560