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/kernel.h> 1855c04de5SPatil, Rachna #include <linux/err.h> 1955c04de5SPatil, Rachna #include <linux/module.h> 2055c04de5SPatil, Rachna #include <linux/input.h> 2155c04de5SPatil, Rachna #include <linux/slab.h> 2255c04de5SPatil, Rachna #include <linux/interrupt.h> 2355c04de5SPatil, Rachna #include <linux/clk.h> 2455c04de5SPatil, Rachna #include <linux/platform_device.h> 2555c04de5SPatil, Rachna #include <linux/io.h> 2655c04de5SPatil, Rachna #include <linux/delay.h> 270396310bSPatil, Rachna #include <linux/of.h> 280396310bSPatil, Rachna #include <linux/of_device.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 36bb76dc09SPatil, Rachna static const int config_pins[] = { 37bb76dc09SPatil, Rachna STEPCONFIG_XPP, 38bb76dc09SPatil, Rachna STEPCONFIG_XNN, 39bb76dc09SPatil, Rachna STEPCONFIG_YPP, 40bb76dc09SPatil, Rachna STEPCONFIG_YNN, 41bb76dc09SPatil, Rachna }; 42bb76dc09SPatil, 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; 500396310bSPatil, Rachna int coordinate_readouts; 51bb76dc09SPatil, Rachna u32 config_inp[4]; 52bb76dc09SPatil, Rachna u32 bit_xp, bit_xn, bit_yp, bit_yn; 53bb76dc09SPatil, Rachna u32 inp_xp, inp_xn, inp_yp, inp_yn; 54baee5399SZubair Lutfullah u32 step_mask; 5555c04de5SPatil, Rachna }; 5655c04de5SPatil, Rachna 5755c04de5SPatil, Rachna static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) 5855c04de5SPatil, Rachna { 592b99bafaSPatil, Rachna return readl(ts->mfd_tscadc->tscadc_base + reg); 6055c04de5SPatil, Rachna } 6155c04de5SPatil, Rachna 6255c04de5SPatil, Rachna static void titsc_writel(struct titsc *tsc, unsigned int reg, 6355c04de5SPatil, Rachna unsigned int val) 6455c04de5SPatil, Rachna { 652b99bafaSPatil, Rachna writel(val, tsc->mfd_tscadc->tscadc_base + reg); 6655c04de5SPatil, Rachna } 6755c04de5SPatil, Rachna 68bb76dc09SPatil, Rachna static int titsc_config_wires(struct titsc *ts_dev) 69bb76dc09SPatil, Rachna { 70bb76dc09SPatil, Rachna u32 analog_line[4]; 71bb76dc09SPatil, Rachna u32 wire_order[4]; 72bb76dc09SPatil, Rachna int i, bit_cfg; 73bb76dc09SPatil, Rachna 74bb76dc09SPatil, Rachna for (i = 0; i < 4; i++) { 75bb76dc09SPatil, Rachna /* 76bb76dc09SPatil, Rachna * Get the order in which TSC wires are attached 77bb76dc09SPatil, Rachna * w.r.t. each of the analog input lines on the EVM. 78bb76dc09SPatil, Rachna */ 79bb76dc09SPatil, Rachna analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4; 80bb76dc09SPatil, Rachna wire_order[i] = ts_dev->config_inp[i] & 0x0F; 81bb76dc09SPatil, Rachna if (WARN_ON(analog_line[i] > 7)) 82bb76dc09SPatil, Rachna return -EINVAL; 83bb76dc09SPatil, Rachna if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins))) 84bb76dc09SPatil, Rachna return -EINVAL; 85bb76dc09SPatil, Rachna } 86bb76dc09SPatil, Rachna 87bb76dc09SPatil, Rachna for (i = 0; i < 4; i++) { 88bb76dc09SPatil, Rachna int an_line; 89bb76dc09SPatil, Rachna int wi_order; 90bb76dc09SPatil, Rachna 91bb76dc09SPatil, Rachna an_line = analog_line[i]; 92bb76dc09SPatil, Rachna wi_order = wire_order[i]; 93bb76dc09SPatil, Rachna bit_cfg = config_pins[wi_order]; 94bb76dc09SPatil, Rachna if (bit_cfg == 0) 95bb76dc09SPatil, Rachna return -EINVAL; 96bb76dc09SPatil, Rachna switch (wi_order) { 97bb76dc09SPatil, Rachna case 0: 98bb76dc09SPatil, Rachna ts_dev->bit_xp = bit_cfg; 99bb76dc09SPatil, Rachna ts_dev->inp_xp = an_line; 100bb76dc09SPatil, Rachna break; 101bb76dc09SPatil, Rachna 102bb76dc09SPatil, Rachna case 1: 103bb76dc09SPatil, Rachna ts_dev->bit_xn = bit_cfg; 104bb76dc09SPatil, Rachna ts_dev->inp_xn = an_line; 105bb76dc09SPatil, Rachna break; 106bb76dc09SPatil, Rachna 107bb76dc09SPatil, Rachna case 2: 108bb76dc09SPatil, Rachna ts_dev->bit_yp = bit_cfg; 109bb76dc09SPatil, Rachna ts_dev->inp_yp = an_line; 110bb76dc09SPatil, Rachna break; 111bb76dc09SPatil, Rachna case 3: 112bb76dc09SPatil, Rachna ts_dev->bit_yn = bit_cfg; 113bb76dc09SPatil, Rachna ts_dev->inp_yn = an_line; 114bb76dc09SPatil, Rachna break; 115bb76dc09SPatil, Rachna } 116bb76dc09SPatil, Rachna } 117bb76dc09SPatil, Rachna return 0; 118bb76dc09SPatil, Rachna } 119bb76dc09SPatil, Rachna 12055c04de5SPatil, Rachna static void titsc_step_config(struct titsc *ts_dev) 12155c04de5SPatil, Rachna { 12255c04de5SPatil, Rachna unsigned int config; 1238c896308SSebastian Andrzej Siewior int i; 124*3a59684cSBrad Griffis int end_step, first_step, tsc_steps; 1258c896308SSebastian Andrzej Siewior u32 stepenable; 12655c04de5SPatil, Rachna 12755c04de5SPatil, Rachna config = STEPCONFIG_MODE_HWSYNC | 128bb76dc09SPatil, Rachna STEPCONFIG_AVG_16 | ts_dev->bit_xp; 12955c04de5SPatil, Rachna switch (ts_dev->wires) { 13055c04de5SPatil, Rachna case 4: 131bb76dc09SPatil, Rachna config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; 13255c04de5SPatil, Rachna break; 13355c04de5SPatil, Rachna case 5: 134bb76dc09SPatil, Rachna config |= ts_dev->bit_yn | 135bb76dc09SPatil, Rachna STEPCONFIG_INP_AN4 | ts_dev->bit_xn | 136bb76dc09SPatil, Rachna ts_dev->bit_yp; 13755c04de5SPatil, Rachna break; 13855c04de5SPatil, Rachna case 8: 139bb76dc09SPatil, Rachna config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; 14055c04de5SPatil, Rachna break; 14155c04de5SPatil, Rachna } 14255c04de5SPatil, Rachna 143*3a59684cSBrad Griffis tsc_steps = ts_dev->coordinate_readouts * 2 + 2; 144*3a59684cSBrad Griffis first_step = TOTAL_STEPS - tsc_steps; 145*3a59684cSBrad Griffis /* Steps 16 to 16-coordinate_readouts is for X */ 146*3a59684cSBrad Griffis end_step = first_step + tsc_steps; 147*3a59684cSBrad Griffis for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) { 14855c04de5SPatil, Rachna titsc_writel(ts_dev, REG_STEPCONFIG(i), config); 14955c04de5SPatil, Rachna titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); 15055c04de5SPatil, Rachna } 15155c04de5SPatil, Rachna 15255c04de5SPatil, Rachna config = 0; 15355c04de5SPatil, Rachna config = STEPCONFIG_MODE_HWSYNC | 154bb76dc09SPatil, Rachna STEPCONFIG_AVG_16 | ts_dev->bit_yn | 1558c896308SSebastian Andrzej Siewior STEPCONFIG_INM_ADCREFM; 15655c04de5SPatil, Rachna switch (ts_dev->wires) { 15755c04de5SPatil, Rachna case 4: 158bb76dc09SPatil, Rachna config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); 15955c04de5SPatil, Rachna break; 16055c04de5SPatil, Rachna case 5: 161bb76dc09SPatil, Rachna config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 | 162bb76dc09SPatil, Rachna ts_dev->bit_xn | ts_dev->bit_yp; 16355c04de5SPatil, Rachna break; 16455c04de5SPatil, Rachna case 8: 165bb76dc09SPatil, Rachna config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); 16655c04de5SPatil, Rachna break; 16755c04de5SPatil, Rachna } 16855c04de5SPatil, Rachna 169*3a59684cSBrad Griffis /* 1 ... coordinate_readouts is for Y */ 170*3a59684cSBrad Griffis end_step = first_step + ts_dev->coordinate_readouts; 171*3a59684cSBrad Griffis for (i = first_step; i < end_step; i++) { 17255c04de5SPatil, Rachna titsc_writel(ts_dev, REG_STEPCONFIG(i), config); 17355c04de5SPatil, Rachna titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); 17455c04de5SPatil, Rachna } 17555c04de5SPatil, Rachna 17655c04de5SPatil, Rachna /* Charge step configuration */ 177bb76dc09SPatil, Rachna config = ts_dev->bit_xp | ts_dev->bit_yn | 17855c04de5SPatil, Rachna STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | 179bb76dc09SPatil, Rachna STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp); 18055c04de5SPatil, Rachna 18155c04de5SPatil, Rachna titsc_writel(ts_dev, REG_CHARGECONFIG, config); 18255c04de5SPatil, Rachna titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); 18355c04de5SPatil, Rachna 184*3a59684cSBrad Griffis /* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */ 18555c04de5SPatil, Rachna config = STEPCONFIG_MODE_HWSYNC | 186bb76dc09SPatil, Rachna STEPCONFIG_AVG_16 | ts_dev->bit_yp | 187bb76dc09SPatil, Rachna ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | 188bb76dc09SPatil, Rachna STEPCONFIG_INP(ts_dev->inp_xp); 1898c896308SSebastian Andrzej Siewior titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); 1908c896308SSebastian Andrzej Siewior titsc_writel(ts_dev, REG_STEPDELAY(end_step), 19155c04de5SPatil, Rachna STEPCONFIG_OPENDLY); 19255c04de5SPatil, Rachna 1938c896308SSebastian Andrzej Siewior end_step++; 1948c896308SSebastian Andrzej Siewior config |= STEPCONFIG_INP(ts_dev->inp_yn); 1958c896308SSebastian Andrzej Siewior titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); 1968c896308SSebastian Andrzej Siewior titsc_writel(ts_dev, REG_STEPDELAY(end_step), 19755c04de5SPatil, Rachna STEPCONFIG_OPENDLY); 19855c04de5SPatil, Rachna 199*3a59684cSBrad Griffis /* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */ 200*3a59684cSBrad Griffis stepenable = 1; 201*3a59684cSBrad Griffis for (i = 0; i < tsc_steps; i++) 202*3a59684cSBrad Griffis stepenable |= 1 << (first_step + i + 1); 203*3a59684cSBrad Griffis 204baee5399SZubair Lutfullah ts_dev->step_mask = stepenable; 2057e170c6eSSebastian Andrzej Siewior am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); 20655c04de5SPatil, Rachna } 20755c04de5SPatil, Rachna 20855c04de5SPatil, Rachna static void titsc_read_coordinates(struct titsc *ts_dev, 2098c896308SSebastian Andrzej Siewior u32 *x, u32 *y, u32 *z1, u32 *z2) 21055c04de5SPatil, Rachna { 21155c04de5SPatil, Rachna unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); 21255c04de5SPatil, Rachna unsigned int prev_val_x = ~0, prev_val_y = ~0; 21355c04de5SPatil, Rachna unsigned int prev_diff_x = ~0, prev_diff_y = ~0; 21455c04de5SPatil, Rachna unsigned int read, diff; 2152b99bafaSPatil, Rachna unsigned int i, channel; 2168c896308SSebastian Andrzej Siewior unsigned int creads = ts_dev->coordinate_readouts; 217*3a59684cSBrad Griffis unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2); 21855c04de5SPatil, Rachna 2198c896308SSebastian Andrzej Siewior *z1 = *z2 = 0; 2208c896308SSebastian Andrzej Siewior if (fifocount % (creads * 2 + 2)) 2218c896308SSebastian Andrzej Siewior fifocount -= fifocount % (creads * 2 + 2); 22255c04de5SPatil, Rachna /* 22355c04de5SPatil, Rachna * Delta filter is used to remove large variations in sampled 22455c04de5SPatil, Rachna * values from ADC. The filter tries to predict where the next 22555c04de5SPatil, Rachna * coordinate could be. This is done by taking a previous 22655c04de5SPatil, Rachna * coordinate and subtracting it form current one. Further the 22755c04de5SPatil, Rachna * algorithm compares the difference with that of a present value, 22855c04de5SPatil, Rachna * if true the value is reported to the sub system. 22955c04de5SPatil, Rachna */ 2308c896308SSebastian Andrzej Siewior for (i = 0; i < fifocount; i++) { 2312b99bafaSPatil, Rachna read = titsc_readl(ts_dev, REG_FIFO0); 2328c896308SSebastian Andrzej Siewior 2338c896308SSebastian Andrzej Siewior channel = (read & 0xf0000) >> 16; 2342b99bafaSPatil, Rachna read &= 0xfff; 235*3a59684cSBrad Griffis if (channel > first_step + creads + 2) { 23655c04de5SPatil, Rachna diff = abs(read - prev_val_x); 23755c04de5SPatil, Rachna if (diff < prev_diff_x) { 23855c04de5SPatil, Rachna prev_diff_x = diff; 23955c04de5SPatil, Rachna *x = read; 24055c04de5SPatil, Rachna } 24155c04de5SPatil, Rachna prev_val_x = read; 24255c04de5SPatil, Rachna 243*3a59684cSBrad Griffis } else if (channel == first_step + creads + 1) { 244*3a59684cSBrad Griffis *z1 = read; 245*3a59684cSBrad Griffis 246*3a59684cSBrad Griffis } else if (channel == first_step + creads + 2) { 247*3a59684cSBrad Griffis *z2 = read; 248*3a59684cSBrad Griffis 249*3a59684cSBrad Griffis } else if (channel > first_step) { 25055c04de5SPatil, Rachna diff = abs(read - prev_val_y); 25155c04de5SPatil, Rachna if (diff < prev_diff_y) { 25255c04de5SPatil, Rachna prev_diff_y = diff; 25355c04de5SPatil, Rachna *y = read; 25455c04de5SPatil, Rachna } 25555c04de5SPatil, Rachna prev_val_y = read; 25655c04de5SPatil, Rachna } 25755c04de5SPatil, Rachna } 2582b99bafaSPatil, Rachna } 25955c04de5SPatil, Rachna 26055c04de5SPatil, Rachna static irqreturn_t titsc_irq(int irq, void *dev) 26155c04de5SPatil, Rachna { 26255c04de5SPatil, Rachna struct titsc *ts_dev = dev; 26355c04de5SPatil, Rachna struct input_dev *input_dev = ts_dev->input; 26455c04de5SPatil, Rachna unsigned int status, irqclr = 0; 26555c04de5SPatil, Rachna unsigned int x = 0, y = 0; 26655c04de5SPatil, Rachna unsigned int z1, z2, z; 26755c04de5SPatil, Rachna unsigned int fsm; 26855c04de5SPatil, Rachna 26955c04de5SPatil, Rachna status = titsc_readl(ts_dev, REG_IRQSTATUS); 270baee5399SZubair Lutfullah /* 271baee5399SZubair Lutfullah * ADC and touchscreen share the IRQ line. 272baee5399SZubair Lutfullah * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only 273baee5399SZubair Lutfullah */ 27455c04de5SPatil, Rachna if (status & IRQENB_FIFO0THRES) { 27555c04de5SPatil, Rachna 2768c896308SSebastian Andrzej Siewior titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); 2772b99bafaSPatil, Rachna 27855c04de5SPatil, Rachna if (ts_dev->pen_down && z1 != 0 && z2 != 0) { 27955c04de5SPatil, Rachna /* 28055c04de5SPatil, Rachna * Calculate pressure using formula 28155c04de5SPatil, Rachna * Resistance(touch) = x plate resistance * 28255c04de5SPatil, Rachna * x postion/4096 * ((z2 / z1) - 1) 28355c04de5SPatil, Rachna */ 2848c896308SSebastian Andrzej Siewior z = z1 - z2; 28555c04de5SPatil, Rachna z *= x; 28655c04de5SPatil, Rachna z *= ts_dev->x_plate_resistance; 2878c896308SSebastian Andrzej Siewior z /= z2; 28855c04de5SPatil, Rachna z = (z + 2047) >> 12; 28955c04de5SPatil, Rachna 29055c04de5SPatil, Rachna if (z <= MAX_12BIT) { 29155c04de5SPatil, Rachna input_report_abs(input_dev, ABS_X, x); 29255c04de5SPatil, Rachna input_report_abs(input_dev, ABS_Y, y); 29355c04de5SPatil, Rachna input_report_abs(input_dev, ABS_PRESSURE, z); 29455c04de5SPatil, Rachna input_report_key(input_dev, BTN_TOUCH, 1); 29555c04de5SPatil, Rachna input_sync(input_dev); 29655c04de5SPatil, Rachna } 29755c04de5SPatil, Rachna } 29855c04de5SPatil, Rachna irqclr |= IRQENB_FIFO0THRES; 29955c04de5SPatil, Rachna } 30055c04de5SPatil, Rachna 30155c04de5SPatil, Rachna /* 30255c04de5SPatil, Rachna * Time for sequencer to settle, to read 30355c04de5SPatil, Rachna * correct state of the sequencer. 30455c04de5SPatil, Rachna */ 30555c04de5SPatil, Rachna udelay(SEQ_SETTLE); 30655c04de5SPatil, Rachna 30755c04de5SPatil, Rachna status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); 30855c04de5SPatil, Rachna if (status & IRQENB_PENUP) { 30955c04de5SPatil, Rachna /* Pen up event */ 31055c04de5SPatil, Rachna fsm = titsc_readl(ts_dev, REG_ADCFSM); 31155c04de5SPatil, Rachna if (fsm == ADCFSM_STEPID) { 31255c04de5SPatil, Rachna ts_dev->pen_down = false; 31355c04de5SPatil, Rachna input_report_key(input_dev, BTN_TOUCH, 0); 31455c04de5SPatil, Rachna input_report_abs(input_dev, ABS_PRESSURE, 0); 31555c04de5SPatil, Rachna input_sync(input_dev); 31655c04de5SPatil, Rachna } else { 31755c04de5SPatil, Rachna ts_dev->pen_down = true; 31855c04de5SPatil, Rachna } 31955c04de5SPatil, Rachna irqclr |= IRQENB_PENUP; 32055c04de5SPatil, Rachna } 32155c04de5SPatil, Rachna 32200789e5dSSebastian Andrzej Siewior if (status & IRQENB_HW_PEN) { 32355c04de5SPatil, Rachna 32400789e5dSSebastian Andrzej Siewior titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); 32500789e5dSSebastian Andrzej Siewior titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); 32600789e5dSSebastian Andrzej Siewior } 32700789e5dSSebastian Andrzej Siewior 3289a28b883SSebastian Andrzej Siewior if (irqclr) { 32955c04de5SPatil, Rachna titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); 3307e170c6eSSebastian Andrzej Siewior am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); 33155c04de5SPatil, Rachna return IRQ_HANDLED; 33255c04de5SPatil, Rachna } 3339a28b883SSebastian Andrzej Siewior return IRQ_NONE; 3349a28b883SSebastian Andrzej Siewior } 33555c04de5SPatil, Rachna 3360396310bSPatil, Rachna static int titsc_parse_dt(struct platform_device *pdev, 3370396310bSPatil, Rachna struct titsc *ts_dev) 3380396310bSPatil, Rachna { 3390396310bSPatil, Rachna struct device_node *node = pdev->dev.of_node; 3400396310bSPatil, Rachna int err; 3410396310bSPatil, Rachna 3420396310bSPatil, Rachna if (!node) 3430396310bSPatil, Rachna return -EINVAL; 3440396310bSPatil, Rachna 3450396310bSPatil, Rachna err = of_property_read_u32(node, "ti,wires", &ts_dev->wires); 3460396310bSPatil, Rachna if (err < 0) 3470396310bSPatil, Rachna return err; 3480396310bSPatil, Rachna switch (ts_dev->wires) { 3490396310bSPatil, Rachna case 4: 3500396310bSPatil, Rachna case 5: 3510396310bSPatil, Rachna case 8: 3520396310bSPatil, Rachna break; 3530396310bSPatil, Rachna default: 3540396310bSPatil, Rachna return -EINVAL; 3550396310bSPatil, Rachna } 3560396310bSPatil, Rachna 3570396310bSPatil, Rachna err = of_property_read_u32(node, "ti,x-plate-resistance", 3580396310bSPatil, Rachna &ts_dev->x_plate_resistance); 3590396310bSPatil, Rachna if (err < 0) 3600396310bSPatil, Rachna return err; 3610396310bSPatil, Rachna 362c9aeb249SFelipe Balbi /* 363c9aeb249SFelipe Balbi * Try with the new binding first. If it fails, try again with 364c9aeb249SFelipe Balbi * bogus, miss-spelled version. 365c9aeb249SFelipe Balbi */ 366c9aeb249SFelipe Balbi err = of_property_read_u32(node, "ti,coordinate-readouts", 367c9aeb249SFelipe Balbi &ts_dev->coordinate_readouts); 36831972f6eSFelipe Balbi if (err < 0) { 36931972f6eSFelipe Balbi dev_warn(&pdev->dev, "please use 'ti,coordinate-readouts' instead\n"); 3700396310bSPatil, Rachna err = of_property_read_u32(node, "ti,coordiante-readouts", 3710396310bSPatil, Rachna &ts_dev->coordinate_readouts); 37231972f6eSFelipe Balbi } 37331972f6eSFelipe Balbi 3740396310bSPatil, Rachna if (err < 0) 3750396310bSPatil, Rachna return err; 3760396310bSPatil, Rachna 3770396310bSPatil, Rachna return of_property_read_u32_array(node, "ti,wire-config", 3780396310bSPatil, Rachna ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp)); 3790396310bSPatil, Rachna } 38055c04de5SPatil, Rachna 38155c04de5SPatil, Rachna /* 38255c04de5SPatil, Rachna * The functions for inserting/removing driver as a module. 38355c04de5SPatil, Rachna */ 38455c04de5SPatil, Rachna 38531564cbdSLinus Torvalds static int titsc_probe(struct platform_device *pdev) 38655c04de5SPatil, Rachna { 38755c04de5SPatil, Rachna struct titsc *ts_dev; 38855c04de5SPatil, Rachna struct input_dev *input_dev; 389a9bce1b0SSebastian Andrzej Siewior struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev); 39055c04de5SPatil, Rachna int err; 3912b99bafaSPatil, Rachna 39255c04de5SPatil, Rachna /* Allocate memory for device */ 39355c04de5SPatil, Rachna ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); 39455c04de5SPatil, Rachna input_dev = input_allocate_device(); 39555c04de5SPatil, Rachna if (!ts_dev || !input_dev) { 39655c04de5SPatil, Rachna dev_err(&pdev->dev, "failed to allocate memory.\n"); 39755c04de5SPatil, Rachna err = -ENOMEM; 39855c04de5SPatil, Rachna goto err_free_mem; 39955c04de5SPatil, Rachna } 40055c04de5SPatil, Rachna 4012b99bafaSPatil, Rachna tscadc_dev->tsc = ts_dev; 4022b99bafaSPatil, Rachna ts_dev->mfd_tscadc = tscadc_dev; 40355c04de5SPatil, Rachna ts_dev->input = input_dev; 4042b99bafaSPatil, Rachna ts_dev->irq = tscadc_dev->irq; 4050396310bSPatil, Rachna 4060396310bSPatil, Rachna err = titsc_parse_dt(pdev, ts_dev); 4070396310bSPatil, Rachna if (err) { 4080396310bSPatil, Rachna dev_err(&pdev->dev, "Could not find valid DT data.\n"); 4090396310bSPatil, Rachna goto err_free_mem; 4100396310bSPatil, Rachna } 41155c04de5SPatil, Rachna 41255c04de5SPatil, Rachna err = request_irq(ts_dev->irq, titsc_irq, 413baee5399SZubair Lutfullah IRQF_SHARED, pdev->dev.driver->name, ts_dev); 41455c04de5SPatil, Rachna if (err) { 41555c04de5SPatil, Rachna dev_err(&pdev->dev, "failed to allocate irq.\n"); 4162b99bafaSPatil, Rachna goto err_free_mem; 41755c04de5SPatil, Rachna } 41855c04de5SPatil, Rachna 41955c04de5SPatil, Rachna titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); 420bb76dc09SPatil, Rachna err = titsc_config_wires(ts_dev); 421bb76dc09SPatil, Rachna if (err) { 422bb76dc09SPatil, Rachna dev_err(&pdev->dev, "wrong i/p wire configuration\n"); 423bb76dc09SPatil, Rachna goto err_free_irq; 424bb76dc09SPatil, Rachna } 42555c04de5SPatil, Rachna titsc_step_config(ts_dev); 4268c896308SSebastian Andrzej Siewior titsc_writel(ts_dev, REG_FIFO0THR, 4278c896308SSebastian Andrzej Siewior ts_dev->coordinate_readouts * 2 + 2 - 1); 42855c04de5SPatil, Rachna 4292b99bafaSPatil, Rachna input_dev->name = "ti-tsc"; 43055c04de5SPatil, Rachna input_dev->dev.parent = &pdev->dev; 43155c04de5SPatil, Rachna 43255c04de5SPatil, Rachna input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 43355c04de5SPatil, Rachna input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 43455c04de5SPatil, Rachna 43555c04de5SPatil, Rachna input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); 43655c04de5SPatil, Rachna input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); 43755c04de5SPatil, Rachna input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); 43855c04de5SPatil, Rachna 43955c04de5SPatil, Rachna /* register to the input system */ 44055c04de5SPatil, Rachna err = input_register_device(input_dev); 44155c04de5SPatil, Rachna if (err) 4422b99bafaSPatil, Rachna goto err_free_irq; 44355c04de5SPatil, Rachna 44455c04de5SPatil, Rachna platform_set_drvdata(pdev, ts_dev); 44555c04de5SPatil, Rachna return 0; 44655c04de5SPatil, Rachna 44755c04de5SPatil, Rachna err_free_irq: 44855c04de5SPatil, Rachna free_irq(ts_dev->irq, ts_dev); 44955c04de5SPatil, Rachna err_free_mem: 45055c04de5SPatil, Rachna input_free_device(input_dev); 45155c04de5SPatil, Rachna kfree(ts_dev); 45255c04de5SPatil, Rachna return err; 45355c04de5SPatil, Rachna } 45455c04de5SPatil, Rachna 45531564cbdSLinus Torvalds static int titsc_remove(struct platform_device *pdev) 45655c04de5SPatil, Rachna { 457a9bce1b0SSebastian Andrzej Siewior struct titsc *ts_dev = platform_get_drvdata(pdev); 458a9bce1b0SSebastian Andrzej Siewior u32 steps; 45955c04de5SPatil, Rachna 46055c04de5SPatil, Rachna free_irq(ts_dev->irq, ts_dev); 46155c04de5SPatil, Rachna 462abeccee4SPatil, Rachna /* total steps followed by the enable mask */ 4630396310bSPatil, Rachna steps = 2 * ts_dev->coordinate_readouts + 2; 464abeccee4SPatil, Rachna steps = (1 << steps) - 1; 465abeccee4SPatil, Rachna am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps); 466abeccee4SPatil, Rachna 46755c04de5SPatil, Rachna input_unregister_device(ts_dev->input); 46855c04de5SPatil, Rachna 4692b99bafaSPatil, Rachna kfree(ts_dev); 47055c04de5SPatil, Rachna return 0; 47155c04de5SPatil, Rachna } 47255c04de5SPatil, Rachna 4732b99bafaSPatil, Rachna #ifdef CONFIG_PM 4742b99bafaSPatil, Rachna static int titsc_suspend(struct device *dev) 4752b99bafaSPatil, Rachna { 476a9bce1b0SSebastian Andrzej Siewior struct titsc *ts_dev = dev_get_drvdata(dev); 477a9bce1b0SSebastian Andrzej Siewior struct ti_tscadc_dev *tscadc_dev; 4782b99bafaSPatil, Rachna unsigned int idle; 4792b99bafaSPatil, Rachna 480a9bce1b0SSebastian Andrzej Siewior tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); 4812b99bafaSPatil, Rachna if (device_may_wakeup(tscadc_dev->dev)) { 4822b99bafaSPatil, Rachna idle = titsc_readl(ts_dev, REG_IRQENABLE); 4832b99bafaSPatil, Rachna titsc_writel(ts_dev, REG_IRQENABLE, 4842b99bafaSPatil, Rachna (idle | IRQENB_HW_PEN)); 4852b99bafaSPatil, Rachna titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); 4862b99bafaSPatil, Rachna } 4872b99bafaSPatil, Rachna return 0; 4882b99bafaSPatil, Rachna } 4892b99bafaSPatil, Rachna 4902b99bafaSPatil, Rachna static int titsc_resume(struct device *dev) 4912b99bafaSPatil, Rachna { 492a9bce1b0SSebastian Andrzej Siewior struct titsc *ts_dev = dev_get_drvdata(dev); 493a9bce1b0SSebastian Andrzej Siewior struct ti_tscadc_dev *tscadc_dev; 4942b99bafaSPatil, Rachna 495a9bce1b0SSebastian Andrzej Siewior tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); 4962b99bafaSPatil, Rachna if (device_may_wakeup(tscadc_dev->dev)) { 4972b99bafaSPatil, Rachna titsc_writel(ts_dev, REG_IRQWAKEUP, 4982b99bafaSPatil, Rachna 0x00); 4992b99bafaSPatil, Rachna titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); 5002b99bafaSPatil, Rachna } 5012b99bafaSPatil, Rachna titsc_step_config(ts_dev); 5022b99bafaSPatil, Rachna titsc_writel(ts_dev, REG_FIFO0THR, 5038c896308SSebastian Andrzej Siewior ts_dev->coordinate_readouts * 2 + 2 - 1); 5042b99bafaSPatil, Rachna return 0; 5052b99bafaSPatil, Rachna } 5062b99bafaSPatil, Rachna 5072b99bafaSPatil, Rachna static const struct dev_pm_ops titsc_pm_ops = { 5082b99bafaSPatil, Rachna .suspend = titsc_suspend, 5092b99bafaSPatil, Rachna .resume = titsc_resume, 5102b99bafaSPatil, Rachna }; 5112b99bafaSPatil, Rachna #define TITSC_PM_OPS (&titsc_pm_ops) 5122b99bafaSPatil, Rachna #else 5132b99bafaSPatil, Rachna #define TITSC_PM_OPS NULL 5142b99bafaSPatil, Rachna #endif 5152b99bafaSPatil, Rachna 5160396310bSPatil, Rachna static const struct of_device_id ti_tsc_dt_ids[] = { 5170396310bSPatil, Rachna { .compatible = "ti,am3359-tsc", }, 5180396310bSPatil, Rachna { } 5190396310bSPatil, Rachna }; 5200396310bSPatil, Rachna MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids); 5210396310bSPatil, Rachna 52255c04de5SPatil, Rachna static struct platform_driver ti_tsc_driver = { 52355c04de5SPatil, Rachna .probe = titsc_probe, 52431564cbdSLinus Torvalds .remove = titsc_remove, 52555c04de5SPatil, Rachna .driver = { 5265f184e63SSebastian Andrzej Siewior .name = "TI-am335x-tsc", 5272b99bafaSPatil, Rachna .pm = TITSC_PM_OPS, 5288e6146bfSSachin Kamat .of_match_table = ti_tsc_dt_ids, 52955c04de5SPatil, Rachna }, 53055c04de5SPatil, Rachna }; 53155c04de5SPatil, Rachna module_platform_driver(ti_tsc_driver); 53255c04de5SPatil, Rachna 53355c04de5SPatil, Rachna MODULE_DESCRIPTION("TI touchscreen controller driver"); 53455c04de5SPatil, Rachna MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); 53555c04de5SPatil, Rachna MODULE_LICENSE("GPL"); 536