1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ffa458c1SDavid Brownell /*
3ffa458c1SDavid Brownell * ADS7846 based touchscreen and sensor driver
4ffa458c1SDavid Brownell *
5ffa458c1SDavid Brownell * Copyright (c) 2005 David Brownell
67de90a8cSImre Deak * Copyright (c) 2006 Nokia Corporation
77de90a8cSImre Deak * Various changes: Imre Deak <imre.deak@nokia.com>
8ffa458c1SDavid Brownell *
9ffa458c1SDavid Brownell * Using code from:
10ffa458c1SDavid Brownell * - corgi_ts.c
11ffa458c1SDavid Brownell * Copyright (C) 2004-2005 Richard Purdie
12ffa458c1SDavid Brownell * - omap_ts.[hc], ads7846.h, ts_osk.c
13ffa458c1SDavid Brownell * Copyright (C) 2002 MontaVista Software
14ffa458c1SDavid Brownell * Copyright (C) 2004 Texas Instruments
15ffa458c1SDavid Brownell * Copyright (C) 2005 Dirk Behme
16ffa458c1SDavid Brownell */
172991a1caSJason Wang #include <linux/types.h>
182c8dc071SDavid Brownell #include <linux/hwmon.h>
192c8dc071SDavid Brownell #include <linux/err.h>
202991a1caSJason Wang #include <linux/sched.h>
21ffa458c1SDavid Brownell #include <linux/delay.h>
22ffa458c1SDavid Brownell #include <linux/input.h>
23a2f99330SMarco Felsch #include <linux/input/touchscreen.h>
24ffa458c1SDavid Brownell #include <linux/interrupt.h>
25ffa458c1SDavid Brownell #include <linux/slab.h>
263c36e719SMark Brown #include <linux/pm.h>
27767d8336SLinus Walleij #include <linux/property.h>
280e685c3eSArnd Bergmann #include <linux/gpio/consumer.h>
29ffa458c1SDavid Brownell #include <linux/spi/spi.h>
30ffa458c1SDavid Brownell #include <linux/spi/ads7846.h>
3191143379SGrazvydas Ignotas #include <linux/regulator/consumer.h>
32d2d8442dSPaul Gortmaker #include <linux/module.h>
3303e2c9c7SDmitry Torokhov #include <asm/unaligned.h>
34ffa458c1SDavid Brownell
35ffa458c1SDavid Brownell /*
369084533eSDavid Brownell * This code has been heavily tested on a Nokia 770, and lightly
3752ce4eaaSPavel Machek * tested on other ads7846 devices (OSK/Mistral, Lubbock, Spitz).
38bff0de5fSDavid Brownell * TSC2046 is just newer ads7846 silicon.
39969111e9SNicolas Ferre * Support for ads7843 tested on Atmel at91sam926x-EK.
40969111e9SNicolas Ferre * Support for ads7845 has only been stubbed in.
4106a09124SMichael Hennerich * Support for Analog Devices AD7873 and AD7843 tested.
42ffa458c1SDavid Brownell *
437de90a8cSImre Deak * IRQ handling needs a workaround because of a shortcoming in handling
447de90a8cSImre Deak * edge triggered IRQs on some platforms like the OMAP1/2. These
457de90a8cSImre Deak * platforms don't handle the ARM lazy IRQ disabling properly, thus we
467de90a8cSImre Deak * have to maintain our own SW IRQ disabled status. This should be
477de90a8cSImre Deak * removed as soon as the affected platform's IRQ handling is fixed.
487de90a8cSImre Deak *
4952ce4eaaSPavel Machek * App note sbaa036 talks in more detail about accurate sampling...
50ffa458c1SDavid Brownell * that ought to help in situations like LCDs inducing noise (which
51ffa458c1SDavid Brownell * can also be helped by using synch signals) and more generally.
527de90a8cSImre Deak * This driver tries to utilize the measures described in the app
537de90a8cSImre Deak * note. The strength of filtering can be set in the board-* specific
547de90a8cSImre Deak * files.
55ffa458c1SDavid Brownell */
56ffa458c1SDavid Brownell
572991a1caSJason Wang #define TS_POLL_DELAY 1 /* ms delay before the first sample */
582991a1caSJason Wang #define TS_POLL_PERIOD 5 /* ms delay between samples */
59ffa458c1SDavid Brownell
60d93f70b2SDavid Brownell /* this driver doesn't aim at the peak continuous sample rate */
61d93f70b2SDavid Brownell #define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
62d93f70b2SDavid Brownell
639c950971SOleksij Rempel struct ads7846_buf {
649c950971SOleksij Rempel u8 cmd;
656965eeceSOleksij Rempel __be16 data;
669c950971SOleksij Rempel } __packed;
679c950971SOleksij Rempel
686965eeceSOleksij Rempel struct ads7846_buf_layout {
696965eeceSOleksij Rempel unsigned int offset;
706965eeceSOleksij Rempel unsigned int count;
716965eeceSOleksij Rempel unsigned int skip;
72ffa458c1SDavid Brownell };
73ffa458c1SDavid Brownell
74e8f462d2SDmitry Torokhov /*
75e8f462d2SDmitry Torokhov * We allocate this separately to avoid cache line sharing issues when
76e8f462d2SDmitry Torokhov * driver is used with DMA-based SPI controllers (like atmel_spi) on
77e8f462d2SDmitry Torokhov * systems where main memory is not DMA-coherent (most non-x86 boards).
78e8f462d2SDmitry Torokhov */
79e8f462d2SDmitry Torokhov struct ads7846_packet {
806965eeceSOleksij Rempel unsigned int count;
816965eeceSOleksij Rempel unsigned int count_skip;
826965eeceSOleksij Rempel unsigned int cmds;
836965eeceSOleksij Rempel unsigned int last_cmd_idx;
846965eeceSOleksij Rempel struct ads7846_buf_layout l[5];
856965eeceSOleksij Rempel struct ads7846_buf *rx;
866965eeceSOleksij Rempel struct ads7846_buf *tx;
876965eeceSOleksij Rempel
889c950971SOleksij Rempel struct ads7846_buf pwrdown_cmd;
896965eeceSOleksij Rempel
906965eeceSOleksij Rempel bool ignore;
916965eeceSOleksij Rempel u16 x, y, z1, z2;
92e8f462d2SDmitry Torokhov };
93e8f462d2SDmitry Torokhov
94ffa458c1SDavid Brownell struct ads7846 {
95a90f7e98SDmitry Torokhov struct input_dev *input;
96ffa458c1SDavid Brownell char phys[32];
97b58895f8SMichael Roth char name[32];
98ffa458c1SDavid Brownell
99ffa458c1SDavid Brownell struct spi_device *spi;
10091143379SGrazvydas Ignotas struct regulator *reg;
1012c8dc071SDavid Brownell
102ffa458c1SDavid Brownell u16 model;
1037c6d0ee1SDavid Brownell u16 vref_mv;
104ffa458c1SDavid Brownell u16 vref_delay_usecs;
105ffa458c1SDavid Brownell u16 x_plate_ohms;
106d5b415c9SImre Deak u16 pressure_max;
107ffa458c1SDavid Brownell
10886579a4cSMichael Roth bool swap_xy;
109ebcaaad9SAlexander Stein bool use_internal;
11086579a4cSMichael Roth
111e8f462d2SDmitry Torokhov struct ads7846_packet *packet;
112ffa458c1SDavid Brownell
113e4f48861SSemih Hazar struct spi_transfer xfer[18];
1140b7018aaSImre Deak struct spi_message msg[5];
1152991a1caSJason Wang int msg_count;
1162991a1caSJason Wang wait_queue_head_t wait;
1172991a1caSJason Wang
1182991a1caSJason Wang bool pendown;
1192991a1caSJason Wang
1200b7018aaSImre Deak int read_cnt;
121d5b415c9SImre Deak int read_rep;
1220b7018aaSImre Deak int last_read;
1230b7018aaSImre Deak
1240b7018aaSImre Deak u16 debounce_max;
1250b7018aaSImre Deak u16 debounce_tol;
126d5b415c9SImre Deak u16 debounce_rep;
127ffa458c1SDavid Brownell
1281d25891fSSemih Hazar u16 penirq_recheck_delay_usecs;
1291d25891fSSemih Hazar
130a2f99330SMarco Felsch struct touchscreen_properties core_prop;
131a2f99330SMarco Felsch
1322991a1caSJason Wang struct mutex lock;
1332991a1caSJason Wang bool stopped; /* P: lock */
1342991a1caSJason Wang bool disabled; /* P: lock */
1352991a1caSJason Wang bool suspended; /* P: lock */
136c9e617a5SImre Deak
137da970e69SImre Deak int (*filter)(void *data, int data_idx, int *val);
138da970e69SImre Deak void *filter_data;
139c9e617a5SImre Deak int (*get_pendown_state)(void);
140767d8336SLinus Walleij struct gpio_desc *gpio_pendown;
141fd746d54SEric Miao
142fd746d54SEric Miao void (*wait_for_sync)(void);
143ffa458c1SDavid Brownell };
144ffa458c1SDavid Brownell
145937f5d5eSDaniel Mack enum ads7846_filter {
146937f5d5eSDaniel Mack ADS7846_FILTER_OK,
147937f5d5eSDaniel Mack ADS7846_FILTER_REPEAT,
148937f5d5eSDaniel Mack ADS7846_FILTER_IGNORE,
149937f5d5eSDaniel Mack };
150937f5d5eSDaniel Mack
151ffa458c1SDavid Brownell /* leave chip selected when we're done, for quicker re-select? */
152ffa458c1SDavid Brownell #if 0
153ffa458c1SDavid Brownell #define CS_CHANGE(xfer) ((xfer).cs_change = 1)
154ffa458c1SDavid Brownell #else
155ffa458c1SDavid Brownell #define CS_CHANGE(xfer) ((xfer).cs_change = 0)
156ffa458c1SDavid Brownell #endif
157ffa458c1SDavid Brownell
158ffa458c1SDavid Brownell /*--------------------------------------------------------------------------*/
159ffa458c1SDavid Brownell
160ffa458c1SDavid Brownell /* The ADS7846 has touchscreen and other sensors.
161ffa458c1SDavid Brownell * Earlier ads784x chips are somewhat compatible.
162ffa458c1SDavid Brownell */
163ffa458c1SDavid Brownell #define ADS_START (1 << 7)
164ffa458c1SDavid Brownell #define ADS_A2A1A0_d_y (1 << 4) /* differential */
165ffa458c1SDavid Brownell #define ADS_A2A1A0_d_z1 (3 << 4) /* differential */
166ffa458c1SDavid Brownell #define ADS_A2A1A0_d_z2 (4 << 4) /* differential */
167ffa458c1SDavid Brownell #define ADS_A2A1A0_d_x (5 << 4) /* differential */
168ffa458c1SDavid Brownell #define ADS_A2A1A0_temp0 (0 << 4) /* non-differential */
169ffa458c1SDavid Brownell #define ADS_A2A1A0_vbatt (2 << 4) /* non-differential */
170ffa458c1SDavid Brownell #define ADS_A2A1A0_vaux (6 << 4) /* non-differential */
171ffa458c1SDavid Brownell #define ADS_A2A1A0_temp1 (7 << 4) /* non-differential */
172ffa458c1SDavid Brownell #define ADS_8_BIT (1 << 3)
173ffa458c1SDavid Brownell #define ADS_12_BIT (0 << 3)
174ffa458c1SDavid Brownell #define ADS_SER (1 << 2) /* non-differential */
175ffa458c1SDavid Brownell #define ADS_DFR (0 << 2) /* differential */
176ffa458c1SDavid Brownell #define ADS_PD10_PDOWN (0 << 0) /* low power mode + penirq */
177ffa458c1SDavid Brownell #define ADS_PD10_ADC_ON (1 << 0) /* ADC on */
178ffa458c1SDavid Brownell #define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */
179ffa458c1SDavid Brownell #define ADS_PD10_ALL_ON (3 << 0) /* ADC + vREF on */
180ffa458c1SDavid Brownell
181ffa458c1SDavid Brownell #define MAX_12BIT ((1<<12)-1)
182ffa458c1SDavid Brownell
183ffa458c1SDavid Brownell /* leave ADC powered up (disables penirq) between differential samples */
184de2defd9SImre Deak #define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
185de2defd9SImre Deak | ADS_12_BIT | ADS_DFR | \
186de2defd9SImre Deak (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
187ffa458c1SDavid Brownell
188de2defd9SImre Deak #define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
189de2defd9SImre Deak #define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
190de2defd9SImre Deak #define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
191de2defd9SImre Deak #define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
192de2defd9SImre Deak #define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
193ffa458c1SDavid Brownell
194ffa458c1SDavid Brownell /* single-ended samples need to first power up reference voltage;
195ffa458c1SDavid Brownell * we leave both ADC and VREF powered
196ffa458c1SDavid Brownell */
197ffa458c1SDavid Brownell #define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
198ffa458c1SDavid Brownell | ADS_12_BIT | ADS_SER)
199ffa458c1SDavid Brownell
200de2defd9SImre Deak #define REF_ON (READ_12BIT_DFR(x, 1, 1))
201de2defd9SImre Deak #define REF_OFF (READ_12BIT_DFR(y, 0, 0))
202ffa458c1SDavid Brownell
2036965eeceSOleksij Rempel /* Order commands in the most optimal way to reduce Vref switching and
2046965eeceSOleksij Rempel * settling time:
2056965eeceSOleksij Rempel * Measure: X; Vref: X+, X-; IN: Y+
2066965eeceSOleksij Rempel * Measure: Y; Vref: Y+, Y-; IN: X+
2076965eeceSOleksij Rempel * Measure: Z1; Vref: Y+, X-; IN: X+
2086965eeceSOleksij Rempel * Measure: Z2; Vref: Y+, X-; IN: Y-
2096965eeceSOleksij Rempel */
2106965eeceSOleksij Rempel enum ads7846_cmds {
2116965eeceSOleksij Rempel ADS7846_X,
2126965eeceSOleksij Rempel ADS7846_Y,
2136965eeceSOleksij Rempel ADS7846_Z1,
2146965eeceSOleksij Rempel ADS7846_Z2,
2156965eeceSOleksij Rempel ADS7846_PWDOWN,
2166965eeceSOleksij Rempel };
2176965eeceSOleksij Rempel
get_pendown_state(struct ads7846 * ts)218e52cd628SDavid Jander static int get_pendown_state(struct ads7846 *ts)
219e52cd628SDavid Jander {
220e52cd628SDavid Jander if (ts->get_pendown_state)
221e52cd628SDavid Jander return ts->get_pendown_state();
222e52cd628SDavid Jander
223767d8336SLinus Walleij return gpiod_get_value(ts->gpio_pendown);
224e52cd628SDavid Jander }
225e52cd628SDavid Jander
ads7846_report_pen_up(struct ads7846 * ts)226e52cd628SDavid Jander static void ads7846_report_pen_up(struct ads7846 *ts)
227e52cd628SDavid Jander {
228e52cd628SDavid Jander struct input_dev *input = ts->input;
229e52cd628SDavid Jander
230e52cd628SDavid Jander input_report_key(input, BTN_TOUCH, 0);
231e52cd628SDavid Jander input_report_abs(input, ABS_PRESSURE, 0);
232e52cd628SDavid Jander input_sync(input);
233e52cd628SDavid Jander
234e52cd628SDavid Jander ts->pendown = false;
235e52cd628SDavid Jander dev_vdbg(&ts->spi->dev, "UP\n");
236e52cd628SDavid Jander }
237e52cd628SDavid Jander
2382991a1caSJason Wang /* Must be called with ts->lock held */
ads7846_stop(struct ads7846 * ts)2392991a1caSJason Wang static void ads7846_stop(struct ads7846 *ts)
2402991a1caSJason Wang {
2412991a1caSJason Wang if (!ts->disabled && !ts->suspended) {
2422991a1caSJason Wang /* Signal IRQ thread to stop polling and disable the handler. */
2432991a1caSJason Wang ts->stopped = true;
2442991a1caSJason Wang mb();
2452991a1caSJason Wang wake_up(&ts->wait);
2462991a1caSJason Wang disable_irq(ts->spi->irq);
2472991a1caSJason Wang }
2482991a1caSJason Wang }
2492991a1caSJason Wang
2502991a1caSJason Wang /* Must be called with ts->lock held */
ads7846_restart(struct ads7846 * ts)2512991a1caSJason Wang static void ads7846_restart(struct ads7846 *ts)
2522991a1caSJason Wang {
2532991a1caSJason Wang if (!ts->disabled && !ts->suspended) {
254e52cd628SDavid Jander /* Check if pen was released since last stop */
255e52cd628SDavid Jander if (ts->pendown && !get_pendown_state(ts))
256e52cd628SDavid Jander ads7846_report_pen_up(ts);
257e52cd628SDavid Jander
2582991a1caSJason Wang /* Tell IRQ thread that it may poll the device. */
2592991a1caSJason Wang ts->stopped = false;
2602991a1caSJason Wang mb();
2612991a1caSJason Wang enable_irq(ts->spi->irq);
2622991a1caSJason Wang }
2632991a1caSJason Wang }
2642991a1caSJason Wang
2652991a1caSJason Wang /* Must be called with ts->lock held */
__ads7846_disable(struct ads7846 * ts)2662991a1caSJason Wang static void __ads7846_disable(struct ads7846 *ts)
2672991a1caSJason Wang {
2682991a1caSJason Wang ads7846_stop(ts);
2692991a1caSJason Wang regulator_disable(ts->reg);
2702991a1caSJason Wang
2712991a1caSJason Wang /*
2722991a1caSJason Wang * We know the chip's in low power mode since we always
2732991a1caSJason Wang * leave it that way after every request
2742991a1caSJason Wang */
2752991a1caSJason Wang }
2762991a1caSJason Wang
2772991a1caSJason Wang /* Must be called with ts->lock held */
__ads7846_enable(struct ads7846 * ts)2782991a1caSJason Wang static void __ads7846_enable(struct ads7846 *ts)
2792991a1caSJason Wang {
280f94352f8SMark Brown int error;
281f94352f8SMark Brown
282f94352f8SMark Brown error = regulator_enable(ts->reg);
283f94352f8SMark Brown if (error != 0)
284f94352f8SMark Brown dev_err(&ts->spi->dev, "Failed to enable supply: %d\n", error);
285f94352f8SMark Brown
2862991a1caSJason Wang ads7846_restart(ts);
2872991a1caSJason Wang }
2882991a1caSJason Wang
ads7846_disable(struct ads7846 * ts)2892991a1caSJason Wang static void ads7846_disable(struct ads7846 *ts)
2902991a1caSJason Wang {
2912991a1caSJason Wang mutex_lock(&ts->lock);
2922991a1caSJason Wang
2932991a1caSJason Wang if (!ts->disabled) {
2942991a1caSJason Wang
2952991a1caSJason Wang if (!ts->suspended)
2962991a1caSJason Wang __ads7846_disable(ts);
2972991a1caSJason Wang
2982991a1caSJason Wang ts->disabled = true;
2992991a1caSJason Wang }
3002991a1caSJason Wang
3012991a1caSJason Wang mutex_unlock(&ts->lock);
3022991a1caSJason Wang }
3032991a1caSJason Wang
ads7846_enable(struct ads7846 * ts)3042991a1caSJason Wang static void ads7846_enable(struct ads7846 *ts)
3052991a1caSJason Wang {
3062991a1caSJason Wang mutex_lock(&ts->lock);
3072991a1caSJason Wang
3082991a1caSJason Wang if (ts->disabled) {
3092991a1caSJason Wang
3102991a1caSJason Wang ts->disabled = false;
3112991a1caSJason Wang
3122991a1caSJason Wang if (!ts->suspended)
3132991a1caSJason Wang __ads7846_enable(ts);
3142991a1caSJason Wang }
3152991a1caSJason Wang
3162991a1caSJason Wang mutex_unlock(&ts->lock);
3172991a1caSJason Wang }
3182991a1caSJason Wang
319ffa458c1SDavid Brownell /*--------------------------------------------------------------------------*/
320ffa458c1SDavid Brownell
321ffa458c1SDavid Brownell /*
322ffa458c1SDavid Brownell * Non-touchscreen sensors only use single-ended conversions.
3232c8dc071SDavid Brownell * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
3242c8dc071SDavid Brownell * ads7846 lets that pin be unconnected, to use internal vREF.
325ffa458c1SDavid Brownell */
326ffa458c1SDavid Brownell
327ffa458c1SDavid Brownell struct ser_req {
328d93f70b2SDavid Brownell u8 ref_on;
329ffa458c1SDavid Brownell u8 command;
330d93f70b2SDavid Brownell u8 ref_off;
331ffa458c1SDavid Brownell u16 scratch;
332ffa458c1SDavid Brownell struct spi_message msg;
333ffa458c1SDavid Brownell struct spi_transfer xfer[6];
3341dbe7dadSAlexander Stein /*
3351dbe7dadSAlexander Stein * DMA (thus cache coherency maintenance) requires the
3361dbe7dadSAlexander Stein * transfer buffers to live in their own cache lines.
3371dbe7dadSAlexander Stein */
3381dbe7dadSAlexander Stein __be16 sample ____cacheline_aligned;
339ffa458c1SDavid Brownell };
340ffa458c1SDavid Brownell
3413eac5c7eSAnatolij Gustschin struct ads7845_ser_req {
3423eac5c7eSAnatolij Gustschin u8 command[3];
3433eac5c7eSAnatolij Gustschin struct spi_message msg;
3443eac5c7eSAnatolij Gustschin struct spi_transfer xfer[2];
3451dbe7dadSAlexander Stein /*
3461dbe7dadSAlexander Stein * DMA (thus cache coherency maintenance) requires the
3471dbe7dadSAlexander Stein * transfer buffers to live in their own cache lines.
3481dbe7dadSAlexander Stein */
3491dbe7dadSAlexander Stein u8 sample[3] ____cacheline_aligned;
3503eac5c7eSAnatolij Gustschin };
3513eac5c7eSAnatolij Gustschin
ads7846_read12_ser(struct device * dev,unsigned command)352ffa458c1SDavid Brownell static int ads7846_read12_ser(struct device *dev, unsigned command)
353ffa458c1SDavid Brownell {
354ffa458c1SDavid Brownell struct spi_device *spi = to_spi_device(dev);
355ffa458c1SDavid Brownell struct ads7846 *ts = dev_get_drvdata(dev);
3562991a1caSJason Wang struct ser_req *req;
357ffa458c1SDavid Brownell int status;
358ffa458c1SDavid Brownell
3592991a1caSJason Wang req = kzalloc(sizeof *req, GFP_KERNEL);
360ffa458c1SDavid Brownell if (!req)
361ffa458c1SDavid Brownell return -ENOMEM;
362ffa458c1SDavid Brownell
3630b7018aaSImre Deak spi_message_init(&req->msg);
3648275c642SVitaly Wool
3652c8dc071SDavid Brownell /* maybe turn on internal vREF, and let it settle */
366ebcaaad9SAlexander Stein if (ts->use_internal) {
367d93f70b2SDavid Brownell req->ref_on = REF_ON;
368d93f70b2SDavid Brownell req->xfer[0].tx_buf = &req->ref_on;
369ffa458c1SDavid Brownell req->xfer[0].len = 1;
3702c8dc071SDavid Brownell spi_message_add_tail(&req->xfer[0], &req->msg);
3712c8dc071SDavid Brownell
372ffa458c1SDavid Brownell req->xfer[1].rx_buf = &req->scratch;
373ffa458c1SDavid Brownell req->xfer[1].len = 2;
374ffa458c1SDavid Brownell
3752c8dc071SDavid Brownell /* for 1uF, settle for 800 usec; no cap, 100 usec. */
3760dfed6dcSAlexandru Ardelean req->xfer[1].delay.value = ts->vref_delay_usecs;
3770dfed6dcSAlexandru Ardelean req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS;
3782c8dc071SDavid Brownell spi_message_add_tail(&req->xfer[1], &req->msg);
379ebcaaad9SAlexander Stein
380ebcaaad9SAlexander Stein /* Enable reference voltage */
381ebcaaad9SAlexander Stein command |= ADS_PD10_REF_ON;
3822c8dc071SDavid Brownell }
383ffa458c1SDavid Brownell
384ebcaaad9SAlexander Stein /* Enable ADC in every case */
385ebcaaad9SAlexander Stein command |= ADS_PD10_ADC_ON;
386ebcaaad9SAlexander Stein
387ffa458c1SDavid Brownell /* take sample */
388ffa458c1SDavid Brownell req->command = (u8) command;
389ffa458c1SDavid Brownell req->xfer[2].tx_buf = &req->command;
390ffa458c1SDavid Brownell req->xfer[2].len = 1;
3912c8dc071SDavid Brownell spi_message_add_tail(&req->xfer[2], &req->msg);
3922c8dc071SDavid Brownell
393ffa458c1SDavid Brownell req->xfer[3].rx_buf = &req->sample;
394ffa458c1SDavid Brownell req->xfer[3].len = 2;
3952c8dc071SDavid Brownell spi_message_add_tail(&req->xfer[3], &req->msg);
396ffa458c1SDavid Brownell
397ffa458c1SDavid Brownell /* REVISIT: take a few more samples, and compare ... */
398ffa458c1SDavid Brownell
399969111e9SNicolas Ferre /* converter in low power mode & enable PENIRQ */
400969111e9SNicolas Ferre req->ref_off = PWRDOWN;
401d93f70b2SDavid Brownell req->xfer[4].tx_buf = &req->ref_off;
402ffa458c1SDavid Brownell req->xfer[4].len = 1;
4032c8dc071SDavid Brownell spi_message_add_tail(&req->xfer[4], &req->msg);
4042c8dc071SDavid Brownell
405ffa458c1SDavid Brownell req->xfer[5].rx_buf = &req->scratch;
406ffa458c1SDavid Brownell req->xfer[5].len = 2;
407ffa458c1SDavid Brownell CS_CHANGE(req->xfer[5]);
4082c8dc071SDavid Brownell spi_message_add_tail(&req->xfer[5], &req->msg);
409ffa458c1SDavid Brownell
4102991a1caSJason Wang mutex_lock(&ts->lock);
4112991a1caSJason Wang ads7846_stop(ts);
412ffa458c1SDavid Brownell status = spi_sync(spi, &req->msg);
4132991a1caSJason Wang ads7846_restart(ts);
4142991a1caSJason Wang mutex_unlock(&ts->lock);
415ffa458c1SDavid Brownell
416c24b2602SMarc Pignat if (status == 0) {
4179084533eSDavid Brownell /* on-wire is a must-ignore bit, a BE12 value, then padding */
4187c6d0ee1SDavid Brownell status = be16_to_cpu(req->sample);
4197c6d0ee1SDavid Brownell status = status >> 3;
4207c6d0ee1SDavid Brownell status &= 0x0fff;
421c24b2602SMarc Pignat }
4229084533eSDavid Brownell
4239084533eSDavid Brownell kfree(req);
4247c6d0ee1SDavid Brownell return status;
425ffa458c1SDavid Brownell }
426ffa458c1SDavid Brownell
ads7845_read12_ser(struct device * dev,unsigned command)4273eac5c7eSAnatolij Gustschin static int ads7845_read12_ser(struct device *dev, unsigned command)
4283eac5c7eSAnatolij Gustschin {
4293eac5c7eSAnatolij Gustschin struct spi_device *spi = to_spi_device(dev);
4303eac5c7eSAnatolij Gustschin struct ads7846 *ts = dev_get_drvdata(dev);
4312991a1caSJason Wang struct ads7845_ser_req *req;
4323eac5c7eSAnatolij Gustschin int status;
4333eac5c7eSAnatolij Gustschin
4342991a1caSJason Wang req = kzalloc(sizeof *req, GFP_KERNEL);
4353eac5c7eSAnatolij Gustschin if (!req)
4363eac5c7eSAnatolij Gustschin return -ENOMEM;
4373eac5c7eSAnatolij Gustschin
4383eac5c7eSAnatolij Gustschin spi_message_init(&req->msg);
4393eac5c7eSAnatolij Gustschin
4403eac5c7eSAnatolij Gustschin req->command[0] = (u8) command;
4413eac5c7eSAnatolij Gustschin req->xfer[0].tx_buf = req->command;
4423eac5c7eSAnatolij Gustschin req->xfer[0].rx_buf = req->sample;
4433eac5c7eSAnatolij Gustschin req->xfer[0].len = 3;
4443eac5c7eSAnatolij Gustschin spi_message_add_tail(&req->xfer[0], &req->msg);
4453eac5c7eSAnatolij Gustschin
4462991a1caSJason Wang mutex_lock(&ts->lock);
4472991a1caSJason Wang ads7846_stop(ts);
4483eac5c7eSAnatolij Gustschin status = spi_sync(spi, &req->msg);
4492991a1caSJason Wang ads7846_restart(ts);
4502991a1caSJason Wang mutex_unlock(&ts->lock);
4513eac5c7eSAnatolij Gustschin
4523eac5c7eSAnatolij Gustschin if (status == 0) {
4533eac5c7eSAnatolij Gustschin /* BE12 value, then padding */
45403e2c9c7SDmitry Torokhov status = get_unaligned_be16(&req->sample[1]);
4553eac5c7eSAnatolij Gustschin status = status >> 3;
4563eac5c7eSAnatolij Gustschin status &= 0x0fff;
4573eac5c7eSAnatolij Gustschin }
4583eac5c7eSAnatolij Gustschin
4593eac5c7eSAnatolij Gustschin kfree(req);
4603eac5c7eSAnatolij Gustschin return status;
4613eac5c7eSAnatolij Gustschin }
4623eac5c7eSAnatolij Gustschin
463c52b4fc7SFabio Estevam #if IS_ENABLED(CONFIG_HWMON)
4642c8dc071SDavid Brownell
4652c8dc071SDavid Brownell #define SHOW(name, var, adjust) static ssize_t \
466ffa458c1SDavid Brownell name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
467ffa458c1SDavid Brownell { \
4682c8dc071SDavid Brownell struct ads7846 *ts = dev_get_drvdata(dev); \
4692fdf4cd9SAlexander Stein ssize_t v = ads7846_read12_ser(&ts->spi->dev, \
470ebcaaad9SAlexander Stein READ_12BIT_SER(var)); \
471ffa458c1SDavid Brownell if (v < 0) \
472ffa458c1SDavid Brownell return v; \
4732c8dc071SDavid Brownell return sprintf(buf, "%u\n", adjust(ts, v)); \
474ffa458c1SDavid Brownell } \
475ffa458c1SDavid Brownell static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
476ffa458c1SDavid Brownell
4772c8dc071SDavid Brownell
478b731d7b6SAdam Buchbinder /* Sysfs conventions report temperatures in millidegrees Celsius.
4792c8dc071SDavid Brownell * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
4802c8dc071SDavid Brownell * accuracy scheme without calibration data. For now we won't try either;
4812c8dc071SDavid Brownell * userspace sees raw sensor values, and must scale/calibrate appropriately.
4822c8dc071SDavid Brownell */
null_adjust(struct ads7846 * ts,ssize_t v)4832c8dc071SDavid Brownell static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
4842c8dc071SDavid Brownell {
4852c8dc071SDavid Brownell return v;
4862c8dc071SDavid Brownell }
4872c8dc071SDavid Brownell
SHOW(temp0,temp0,null_adjust)4882c8dc071SDavid Brownell SHOW(temp0, temp0, null_adjust) /* temp1_input */
4892c8dc071SDavid Brownell SHOW(temp1, temp1, null_adjust) /* temp2_input */
4902c8dc071SDavid Brownell
4912c8dc071SDavid Brownell
4922c8dc071SDavid Brownell /* sysfs conventions report voltages in millivolts. We can convert voltages
4932c8dc071SDavid Brownell * if we know vREF. userspace may need to scale vAUX to match the board's
4942c8dc071SDavid Brownell * external resistors; we assume that vBATT only uses the internal ones.
4952c8dc071SDavid Brownell */
4962c8dc071SDavid Brownell static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
4972c8dc071SDavid Brownell {
4982c8dc071SDavid Brownell unsigned retval = v;
4992c8dc071SDavid Brownell
5002c8dc071SDavid Brownell /* external resistors may scale vAUX into 0..vREF */
5017c6d0ee1SDavid Brownell retval *= ts->vref_mv;
5022c8dc071SDavid Brownell retval = retval >> 12;
5032991a1caSJason Wang
5042c8dc071SDavid Brownell return retval;
5052c8dc071SDavid Brownell }
5062c8dc071SDavid Brownell
vbatt_adjust(struct ads7846 * ts,ssize_t v)5072c8dc071SDavid Brownell static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
5082c8dc071SDavid Brownell {
5092c8dc071SDavid Brownell unsigned retval = vaux_adjust(ts, v);
5102c8dc071SDavid Brownell
5112c8dc071SDavid Brownell /* ads7846 has a resistor ladder to scale this signal down */
5122c8dc071SDavid Brownell if (ts->model == 7846)
5132c8dc071SDavid Brownell retval *= 4;
5142991a1caSJason Wang
5152c8dc071SDavid Brownell return retval;
5162c8dc071SDavid Brownell }
5172c8dc071SDavid Brownell
SHOW(in0_input,vaux,vaux_adjust)5182c8dc071SDavid Brownell SHOW(in0_input, vaux, vaux_adjust)
5192c8dc071SDavid Brownell SHOW(in1_input, vbatt, vbatt_adjust)
5202c8dc071SDavid Brownell
521e585c40bSGuenter Roeck static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr,
522e585c40bSGuenter Roeck int index)
523e585c40bSGuenter Roeck {
5243fe781f4SWang Qing struct device *dev = kobj_to_dev(kobj);
525e585c40bSGuenter Roeck struct ads7846 *ts = dev_get_drvdata(dev);
526e585c40bSGuenter Roeck
527e585c40bSGuenter Roeck if (ts->model == 7843 && index < 2) /* in0, in1 */
528e585c40bSGuenter Roeck return 0;
529e585c40bSGuenter Roeck if (ts->model == 7845 && index != 2) /* in0 */
530e585c40bSGuenter Roeck return 0;
531e585c40bSGuenter Roeck
532e585c40bSGuenter Roeck return attr->mode;
533e585c40bSGuenter Roeck }
534e585c40bSGuenter Roeck
5352c8dc071SDavid Brownell static struct attribute *ads7846_attributes[] = {
536e585c40bSGuenter Roeck &dev_attr_temp0.attr, /* 0 */
537e585c40bSGuenter Roeck &dev_attr_temp1.attr, /* 1 */
538e585c40bSGuenter Roeck &dev_attr_in0_input.attr, /* 2 */
539e585c40bSGuenter Roeck &dev_attr_in1_input.attr, /* 3 */
5402c8dc071SDavid Brownell NULL,
5412c8dc071SDavid Brownell };
5422c8dc071SDavid Brownell
5439e938decSArvind Yadav static const struct attribute_group ads7846_attr_group = {
5442c8dc071SDavid Brownell .attrs = ads7846_attributes,
545e585c40bSGuenter Roeck .is_visible = ads7846_is_visible,
5462c8dc071SDavid Brownell };
547e585c40bSGuenter Roeck __ATTRIBUTE_GROUPS(ads7846_attr);
5482c8dc071SDavid Brownell
ads784x_hwmon_register(struct spi_device * spi,struct ads7846 * ts)5492c8dc071SDavid Brownell static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
5502c8dc071SDavid Brownell {
551845ef3a7SDaniel Mack struct device *hwmon;
552845ef3a7SDaniel Mack
5532c8dc071SDavid Brownell /* hwmon sensors need a reference voltage */
5542c8dc071SDavid Brownell switch (ts->model) {
5552c8dc071SDavid Brownell case 7846:
5567c6d0ee1SDavid Brownell if (!ts->vref_mv) {
5572c8dc071SDavid Brownell dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
5587c6d0ee1SDavid Brownell ts->vref_mv = 2500;
559ebcaaad9SAlexander Stein ts->use_internal = true;
5602c8dc071SDavid Brownell }
5612c8dc071SDavid Brownell break;
5622c8dc071SDavid Brownell case 7845:
5632c8dc071SDavid Brownell case 7843:
5647c6d0ee1SDavid Brownell if (!ts->vref_mv) {
5652c8dc071SDavid Brownell dev_warn(&spi->dev,
5662c8dc071SDavid Brownell "external vREF for ADS%d not specified\n",
5672c8dc071SDavid Brownell ts->model);
5682c8dc071SDavid Brownell return 0;
5692c8dc071SDavid Brownell }
5702c8dc071SDavid Brownell break;
5712c8dc071SDavid Brownell }
5722c8dc071SDavid Brownell
573845ef3a7SDaniel Mack hwmon = devm_hwmon_device_register_with_groups(&spi->dev,
574845ef3a7SDaniel Mack spi->modalias, ts,
575845ef3a7SDaniel Mack ads7846_attr_groups);
5762c8dc071SDavid Brownell
577845ef3a7SDaniel Mack return PTR_ERR_OR_ZERO(hwmon);
5782c8dc071SDavid Brownell }
5792c8dc071SDavid Brownell
5802c8dc071SDavid Brownell #else
ads784x_hwmon_register(struct spi_device * spi,struct ads7846 * ts)5812c8dc071SDavid Brownell static inline int ads784x_hwmon_register(struct spi_device *spi,
5822c8dc071SDavid Brownell struct ads7846 *ts)
5832c8dc071SDavid Brownell {
5842c8dc071SDavid Brownell return 0;
5852c8dc071SDavid Brownell }
5862c8dc071SDavid Brownell #endif
587ffa458c1SDavid Brownell
ads7846_pen_down_show(struct device * dev,struct device_attribute * attr,char * buf)588438f2a74SImre Deak static ssize_t ads7846_pen_down_show(struct device *dev,
589438f2a74SImre Deak struct device_attribute *attr, char *buf)
590438f2a74SImre Deak {
5912991a1caSJason Wang struct ads7846 *ts = dev_get_drvdata(dev);
5922991a1caSJason Wang
5932991a1caSJason Wang return sprintf(buf, "%u\n", ts->pendown);
594438f2a74SImre Deak }
595438f2a74SImre Deak
596438f2a74SImre Deak static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
597438f2a74SImre Deak
ads7846_disable_show(struct device * dev,struct device_attribute * attr,char * buf)5987de90a8cSImre Deak static ssize_t ads7846_disable_show(struct device *dev,
5997de90a8cSImre Deak struct device_attribute *attr, char *buf)
6007de90a8cSImre Deak {
6017de90a8cSImre Deak struct ads7846 *ts = dev_get_drvdata(dev);
6027de90a8cSImre Deak
6037de90a8cSImre Deak return sprintf(buf, "%u\n", ts->disabled);
6047de90a8cSImre Deak }
6057de90a8cSImre Deak
ads7846_disable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)6067de90a8cSImre Deak static ssize_t ads7846_disable_store(struct device *dev,
6077de90a8cSImre Deak struct device_attribute *attr,
6087de90a8cSImre Deak const char *buf, size_t count)
6097de90a8cSImre Deak {
6107de90a8cSImre Deak struct ads7846 *ts = dev_get_drvdata(dev);
61176496e7aSJJ Ding unsigned int i;
61276496e7aSJJ Ding int err;
6137de90a8cSImre Deak
61476496e7aSJJ Ding err = kstrtouint(buf, 10, &i);
61576496e7aSJJ Ding if (err)
61676496e7aSJJ Ding return err;
617160f1fefSJoe Rouvier
6187de90a8cSImre Deak if (i)
6197de90a8cSImre Deak ads7846_disable(ts);
6207de90a8cSImre Deak else
6217de90a8cSImre Deak ads7846_enable(ts);
6227de90a8cSImre Deak
6237de90a8cSImre Deak return count;
6247de90a8cSImre Deak }
6257de90a8cSImre Deak
6267de90a8cSImre Deak static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
6277de90a8cSImre Deak
6282c8dc071SDavid Brownell static struct attribute *ads784x_attributes[] = {
6298dd51650SDmitry Torokhov &dev_attr_pen_down.attr,
6308dd51650SDmitry Torokhov &dev_attr_disable.attr,
6318dd51650SDmitry Torokhov NULL,
6328dd51650SDmitry Torokhov };
6338dd51650SDmitry Torokhov
6349e938decSArvind Yadav static const struct attribute_group ads784x_attr_group = {
6352c8dc071SDavid Brownell .attrs = ads784x_attributes,
6368dd51650SDmitry Torokhov };
6378dd51650SDmitry Torokhov
638ffa458c1SDavid Brownell /*--------------------------------------------------------------------------*/
639ffa458c1SDavid Brownell
null_wait_for_sync(void)640fd746d54SEric Miao static void null_wait_for_sync(void)
641fd746d54SEric Miao {
642fd746d54SEric Miao }
643fd746d54SEric Miao
ads7846_debounce_filter(void * ads,int data_idx,int * val)6442991a1caSJason Wang static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
645ffa458c1SDavid Brownell {
646ffa458c1SDavid Brownell struct ads7846 *ts = ads;
6472991a1caSJason Wang
6482991a1caSJason Wang if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
6492991a1caSJason Wang /* Start over collecting consistent readings. */
6502991a1caSJason Wang ts->read_rep = 0;
6512991a1caSJason Wang /*
6522991a1caSJason Wang * Repeat it, if this was the first read or the read
6532991a1caSJason Wang * wasn't consistent enough.
6542991a1caSJason Wang */
6552991a1caSJason Wang if (ts->read_cnt < ts->debounce_max) {
6562991a1caSJason Wang ts->last_read = *val;
6572991a1caSJason Wang ts->read_cnt++;
6582991a1caSJason Wang return ADS7846_FILTER_REPEAT;
6592991a1caSJason Wang } else {
6602991a1caSJason Wang /*
6612991a1caSJason Wang * Maximum number of debouncing reached and still
6622991a1caSJason Wang * not enough number of consistent readings. Abort
6632991a1caSJason Wang * the whole sample, repeat it in the next sampling
6642991a1caSJason Wang * period.
6652991a1caSJason Wang */
6662991a1caSJason Wang ts->read_cnt = 0;
6672991a1caSJason Wang return ADS7846_FILTER_IGNORE;
6682991a1caSJason Wang }
6692991a1caSJason Wang } else {
6702991a1caSJason Wang if (++ts->read_rep > ts->debounce_rep) {
6712991a1caSJason Wang /*
6722991a1caSJason Wang * Got a good reading for this coordinate,
6732991a1caSJason Wang * go for the next one.
6742991a1caSJason Wang */
6752991a1caSJason Wang ts->read_cnt = 0;
6762991a1caSJason Wang ts->read_rep = 0;
6772991a1caSJason Wang return ADS7846_FILTER_OK;
6782991a1caSJason Wang } else {
6792991a1caSJason Wang /* Read more values that are consistent. */
6802991a1caSJason Wang ts->read_cnt++;
6812991a1caSJason Wang return ADS7846_FILTER_REPEAT;
6822991a1caSJason Wang }
6832991a1caSJason Wang }
6842991a1caSJason Wang }
6852991a1caSJason Wang
ads7846_no_filter(void * ads,int data_idx,int * val)6862991a1caSJason Wang static int ads7846_no_filter(void *ads, int data_idx, int *val)
6872991a1caSJason Wang {
6882991a1caSJason Wang return ADS7846_FILTER_OK;
6892991a1caSJason Wang }
6902991a1caSJason Wang
ads7846_get_value(struct ads7846_buf * buf)6916965eeceSOleksij Rempel static int ads7846_get_value(struct ads7846_buf *buf)
6922991a1caSJason Wang {
693879f2feaSAndrey Gelman int value;
6942991a1caSJason Wang
6956965eeceSOleksij Rempel value = be16_to_cpup(&buf->data);
696879f2feaSAndrey Gelman
697879f2feaSAndrey Gelman /* enforce ADC output is 12 bits width */
698879f2feaSAndrey Gelman return (value >> 3) & 0xfff;
6992991a1caSJason Wang }
7002991a1caSJason Wang
ads7846_set_cmd_val(struct ads7846 * ts,enum ads7846_cmds cmd_idx,u16 val)7016965eeceSOleksij Rempel static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx,
7026965eeceSOleksij Rempel u16 val)
7032991a1caSJason Wang {
7046965eeceSOleksij Rempel struct ads7846_packet *packet = ts->packet;
7052991a1caSJason Wang
7066965eeceSOleksij Rempel switch (cmd_idx) {
7076965eeceSOleksij Rempel case ADS7846_Y:
7086965eeceSOleksij Rempel packet->y = val;
7096965eeceSOleksij Rempel break;
7106965eeceSOleksij Rempel case ADS7846_X:
7116965eeceSOleksij Rempel packet->x = val;
7126965eeceSOleksij Rempel break;
7136965eeceSOleksij Rempel case ADS7846_Z1:
7146965eeceSOleksij Rempel packet->z1 = val;
7156965eeceSOleksij Rempel break;
7166965eeceSOleksij Rempel case ADS7846_Z2:
7176965eeceSOleksij Rempel packet->z2 = val;
7186965eeceSOleksij Rempel break;
7196965eeceSOleksij Rempel default:
7206965eeceSOleksij Rempel WARN_ON_ONCE(1);
7216965eeceSOleksij Rempel }
7226965eeceSOleksij Rempel }
7236965eeceSOleksij Rempel
ads7846_get_cmd(enum ads7846_cmds cmd_idx,int vref)7246965eeceSOleksij Rempel static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref)
7256965eeceSOleksij Rempel {
7266965eeceSOleksij Rempel switch (cmd_idx) {
7276965eeceSOleksij Rempel case ADS7846_Y:
7286965eeceSOleksij Rempel return READ_Y(vref);
7296965eeceSOleksij Rempel case ADS7846_X:
7306965eeceSOleksij Rempel return READ_X(vref);
7316965eeceSOleksij Rempel
7326965eeceSOleksij Rempel /* 7846 specific commands */
7336965eeceSOleksij Rempel case ADS7846_Z1:
7346965eeceSOleksij Rempel return READ_Z1(vref);
7356965eeceSOleksij Rempel case ADS7846_Z2:
7366965eeceSOleksij Rempel return READ_Z2(vref);
7376965eeceSOleksij Rempel case ADS7846_PWDOWN:
7386965eeceSOleksij Rempel return PWRDOWN;
7396965eeceSOleksij Rempel default:
7406965eeceSOleksij Rempel WARN_ON_ONCE(1);
7416965eeceSOleksij Rempel }
7426965eeceSOleksij Rempel
7436965eeceSOleksij Rempel return 0;
7446965eeceSOleksij Rempel }
7456965eeceSOleksij Rempel
ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)7466965eeceSOleksij Rempel static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)
7476965eeceSOleksij Rempel {
7486965eeceSOleksij Rempel switch (cmd_idx) {
7496965eeceSOleksij Rempel case ADS7846_X:
7506965eeceSOleksij Rempel case ADS7846_Y:
7516965eeceSOleksij Rempel case ADS7846_Z1:
7526965eeceSOleksij Rempel case ADS7846_Z2:
7536965eeceSOleksij Rempel return true;
7546965eeceSOleksij Rempel case ADS7846_PWDOWN:
7556965eeceSOleksij Rempel return false;
7566965eeceSOleksij Rempel default:
7576965eeceSOleksij Rempel WARN_ON_ONCE(1);
7586965eeceSOleksij Rempel }
7596965eeceSOleksij Rempel
7606965eeceSOleksij Rempel return false;
7616965eeceSOleksij Rempel }
7626965eeceSOleksij Rempel
ads7846_filter(struct ads7846 * ts)7636965eeceSOleksij Rempel static int ads7846_filter(struct ads7846 *ts)
7646965eeceSOleksij Rempel {
7656965eeceSOleksij Rempel struct ads7846_packet *packet = ts->packet;
7666965eeceSOleksij Rempel int action;
7676965eeceSOleksij Rempel int val;
7686965eeceSOleksij Rempel unsigned int cmd_idx, b;
7696965eeceSOleksij Rempel
7706965eeceSOleksij Rempel packet->ignore = false;
7716965eeceSOleksij Rempel for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) {
7726965eeceSOleksij Rempel struct ads7846_buf_layout *l = &packet->l[cmd_idx];
7736965eeceSOleksij Rempel
7746965eeceSOleksij Rempel packet->last_cmd_idx = cmd_idx;
7756965eeceSOleksij Rempel
7766965eeceSOleksij Rempel for (b = l->skip; b < l->count; b++) {
7776965eeceSOleksij Rempel val = ads7846_get_value(&packet->rx[l->offset + b]);
7786965eeceSOleksij Rempel
7796965eeceSOleksij Rempel action = ts->filter(ts->filter_data, cmd_idx, &val);
7806965eeceSOleksij Rempel if (action == ADS7846_FILTER_REPEAT) {
7816965eeceSOleksij Rempel if (b == l->count - 1)
7826965eeceSOleksij Rempel return -EAGAIN;
7836965eeceSOleksij Rempel } else if (action == ADS7846_FILTER_OK) {
7846965eeceSOleksij Rempel ads7846_set_cmd_val(ts, cmd_idx, val);
7856965eeceSOleksij Rempel break;
7866965eeceSOleksij Rempel } else {
7876965eeceSOleksij Rempel packet->ignore = true;
7886965eeceSOleksij Rempel return 0;
7896965eeceSOleksij Rempel }
7906965eeceSOleksij Rempel }
7916965eeceSOleksij Rempel }
7926965eeceSOleksij Rempel
7936965eeceSOleksij Rempel return 0;
7942991a1caSJason Wang }
7952991a1caSJason Wang
ads7846_read_state(struct ads7846 * ts)7962991a1caSJason Wang static void ads7846_read_state(struct ads7846 *ts)
7972991a1caSJason Wang {
798e8f462d2SDmitry Torokhov struct ads7846_packet *packet = ts->packet;
7992991a1caSJason Wang struct spi_message *m;
8002991a1caSJason Wang int msg_idx = 0;
8012991a1caSJason Wang int error;
8022991a1caSJason Wang
8036965eeceSOleksij Rempel packet->last_cmd_idx = 0;
8042991a1caSJason Wang
8056965eeceSOleksij Rempel while (true) {
8062991a1caSJason Wang ts->wait_for_sync();
8072991a1caSJason Wang
8082991a1caSJason Wang m = &ts->msg[msg_idx];
8092991a1caSJason Wang error = spi_sync(ts->spi, m);
8102991a1caSJason Wang if (error) {
811c8986208SMark Brown dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
8126965eeceSOleksij Rempel packet->ignore = true;
8132991a1caSJason Wang return;
8142991a1caSJason Wang }
8152991a1caSJason Wang
8166965eeceSOleksij Rempel error = ads7846_filter(ts);
8176965eeceSOleksij Rempel if (error)
8182991a1caSJason Wang continue;
8192991a1caSJason Wang
8206965eeceSOleksij Rempel return;
8212991a1caSJason Wang }
8222991a1caSJason Wang }
8232991a1caSJason Wang
ads7846_report_state(struct ads7846 * ts)8242991a1caSJason Wang static void ads7846_report_state(struct ads7846 *ts)
8252991a1caSJason Wang {
8262991a1caSJason Wang struct ads7846_packet *packet = ts->packet;
8272991a1caSJason Wang unsigned int Rt;
828ffa458c1SDavid Brownell u16 x, y, z1, z2;
829ffa458c1SDavid Brownell
8306965eeceSOleksij Rempel x = packet->x;
8316965eeceSOleksij Rempel y = packet->y;
8323eac5c7eSAnatolij Gustschin if (ts->model == 7845) {
8333eac5c7eSAnatolij Gustschin z1 = 0;
8343eac5c7eSAnatolij Gustschin z2 = 0;
8353eac5c7eSAnatolij Gustschin } else {
8366965eeceSOleksij Rempel z1 = packet->z1;
8376965eeceSOleksij Rempel z2 = packet->z2;
8383eac5c7eSAnatolij Gustschin }
839ffa458c1SDavid Brownell
840ffa458c1SDavid Brownell /* range filtering */
841ffa458c1SDavid Brownell if (x == MAX_12BIT)
842ffa458c1SDavid Brownell x = 0;
843ffa458c1SDavid Brownell
844fa9f4275SLuca Ellero if (ts->model == 7843 || ts->model == 7845) {
8459460b652SHans-Christian Egtvedt Rt = ts->pressure_max / 2;
8469460b652SHans-Christian Egtvedt } else if (likely(x && z1)) {
847ffa458c1SDavid Brownell /* compute touch pressure resistance using equation #2 */
848ffa458c1SDavid Brownell Rt = z2;
849ffa458c1SDavid Brownell Rt -= z1;
850ffa458c1SDavid Brownell Rt *= ts->x_plate_ohms;
851820830ecSOleksij Rempel Rt = DIV_ROUND_CLOSEST(Rt, 16);
852820830ecSOleksij Rempel Rt *= x;
853ffa458c1SDavid Brownell Rt /= z1;
854820830ecSOleksij Rempel Rt = DIV_ROUND_CLOSEST(Rt, 256);
8559460b652SHans-Christian Egtvedt } else {
856ffa458c1SDavid Brownell Rt = 0;
8579460b652SHans-Christian Egtvedt }
858969111e9SNicolas Ferre
8592991a1caSJason Wang /*
8602991a1caSJason Wang * Sample found inconsistent by debouncing or pressure is beyond
861d5b415c9SImre Deak * the maximum. Don't report it to user space, repeat at least
8621936d590SImre Deak * once more the measurement
8631936d590SImre Deak */
8646965eeceSOleksij Rempel if (packet->ignore || Rt > ts->pressure_max) {
86552ce4eaaSPavel Machek dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
8666965eeceSOleksij Rempel packet->ignore, Rt);
867d5b415c9SImre Deak return;
868d5b415c9SImre Deak }
869d5b415c9SImre Deak
8702991a1caSJason Wang /*
8712991a1caSJason Wang * Maybe check the pendown state before reporting. This discards
8721d25891fSSemih Hazar * false readings when the pen is lifted.
8731d25891fSSemih Hazar */
8741d25891fSSemih Hazar if (ts->penirq_recheck_delay_usecs) {
8751d25891fSSemih Hazar udelay(ts->penirq_recheck_delay_usecs);
8764d5975e5SEric Miao if (!get_pendown_state(ts))
8771d25891fSSemih Hazar Rt = 0;
8781d25891fSSemih Hazar }
8791d25891fSSemih Hazar
8802991a1caSJason Wang /*
8812991a1caSJason Wang * NOTE: We can't rely on the pressure to determine the pen down
88215e3589eSImre Deak * state, even this controller has a pressure sensor. The pressure
88315e3589eSImre Deak * value can fluctuate for quite a while after lifting the pen and
88415e3589eSImre Deak * in some cases may not even settle at the expected value.
885ffa458c1SDavid Brownell *
88615e3589eSImre Deak * The only safe way to check for the pen up condition is in the
88715e3589eSImre Deak * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
888ffa458c1SDavid Brownell */
889ffa458c1SDavid Brownell if (Rt) {
89015e3589eSImre Deak struct input_dev *input = ts->input;
891ae82d5abSImre Deak
8922991a1caSJason Wang if (!ts->pendown) {
8932991a1caSJason Wang input_report_key(input, BTN_TOUCH, 1);
8942991a1caSJason Wang ts->pendown = true;
8952991a1caSJason Wang dev_vdbg(&ts->spi->dev, "DOWN\n");
8962991a1caSJason Wang }
8972991a1caSJason Wang
898a2f99330SMarco Felsch touchscreen_report_pos(input, &ts->core_prop, x, y, false);
89930ad7ba0SPavel Machek input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
900ffa458c1SDavid Brownell
90115e3589eSImre Deak input_sync(input);
90252ce4eaaSPavel Machek dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
90315e3589eSImre Deak }
904ffa458c1SDavid Brownell }
905ffa458c1SDavid Brownell
ads7846_hard_irq(int irq,void * handle)9062991a1caSJason Wang static irqreturn_t ads7846_hard_irq(int irq, void *handle)
907ffa458c1SDavid Brownell {
9082991a1caSJason Wang struct ads7846 *ts = handle;
909ffa458c1SDavid Brownell
9102991a1caSJason Wang return get_pendown_state(ts) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
911da970e69SImre Deak }
912da970e69SImre Deak
9132991a1caSJason Wang
ads7846_irq(int irq,void * handle)9142991a1caSJason Wang static irqreturn_t ads7846_irq(int irq, void *handle)
915da970e69SImre Deak {
9162991a1caSJason Wang struct ads7846 *ts = handle;
9172991a1caSJason Wang
9182991a1caSJason Wang /* Start with a small delay before checking pendown state */
9192991a1caSJason Wang msleep(TS_POLL_DELAY);
9202991a1caSJason Wang
9212991a1caSJason Wang while (!ts->stopped && get_pendown_state(ts)) {
9222991a1caSJason Wang
9232991a1caSJason Wang /* pen is down, continue with the measurement */
9242991a1caSJason Wang ads7846_read_state(ts);
9252991a1caSJason Wang
9262991a1caSJason Wang if (!ts->stopped)
9272991a1caSJason Wang ads7846_report_state(ts);
9282991a1caSJason Wang
9292991a1caSJason Wang wait_event_timeout(ts->wait, ts->stopped,
9302991a1caSJason Wang msecs_to_jiffies(TS_POLL_PERIOD));
931da970e69SImre Deak }
932da970e69SImre Deak
933e52cd628SDavid Jander if (ts->pendown && !ts->stopped)
934e52cd628SDavid Jander ads7846_report_pen_up(ts);
93515e3589eSImre Deak
9367de90a8cSImre Deak return IRQ_HANDLED;
937ffa458c1SDavid Brownell }
938ffa458c1SDavid Brownell
ads7846_suspend(struct device * dev)939f8909d9aSJonathan Cameron static int ads7846_suspend(struct device *dev)
9407de90a8cSImre Deak {
9413c36e719SMark Brown struct ads7846 *ts = dev_get_drvdata(dev);
9427de90a8cSImre Deak
9432991a1caSJason Wang mutex_lock(&ts->lock);
9447de90a8cSImre Deak
9452991a1caSJason Wang if (!ts->suspended) {
9467de90a8cSImre Deak
9472991a1caSJason Wang if (!ts->disabled)
9482991a1caSJason Wang __ads7846_disable(ts);
9497de90a8cSImre Deak
950fdba2bb1SRanjith Lohithakshan if (device_may_wakeup(&ts->spi->dev))
951fdba2bb1SRanjith Lohithakshan enable_irq_wake(ts->spi->irq);
952fdba2bb1SRanjith Lohithakshan
9532991a1caSJason Wang ts->suspended = true;
9542991a1caSJason Wang }
9557de90a8cSImre Deak
9562991a1caSJason Wang mutex_unlock(&ts->lock);
9572991a1caSJason Wang
9582991a1caSJason Wang return 0;
959ffa458c1SDavid Brownell }
960ffa458c1SDavid Brownell
ads7846_resume(struct device * dev)961f8909d9aSJonathan Cameron static int ads7846_resume(struct device *dev)
962ffa458c1SDavid Brownell {
9633c36e719SMark Brown struct ads7846 *ts = dev_get_drvdata(dev);
964ffa458c1SDavid Brownell
9652991a1caSJason Wang mutex_lock(&ts->lock);
9662991a1caSJason Wang
9672991a1caSJason Wang if (ts->suspended) {
9682991a1caSJason Wang
9692991a1caSJason Wang ts->suspended = false;
9702991a1caSJason Wang
971fdba2bb1SRanjith Lohithakshan if (device_may_wakeup(&ts->spi->dev))
972fdba2bb1SRanjith Lohithakshan disable_irq_wake(ts->spi->irq);
973fdba2bb1SRanjith Lohithakshan
9742991a1caSJason Wang if (!ts->disabled)
9752991a1caSJason Wang __ads7846_enable(ts);
9762991a1caSJason Wang }
9777de90a8cSImre Deak
9782991a1caSJason Wang mutex_unlock(&ts->lock);
9797de90a8cSImre Deak
980ffa458c1SDavid Brownell return 0;
981ffa458c1SDavid Brownell }
9823c36e719SMark Brown
983f8909d9aSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
984ffa458c1SDavid Brownell
ads7846_setup_pendown(struct spi_device * spi,struct ads7846 * ts,const struct ads7846_platform_data * pdata)9855298cc4cSBill Pemberton static int ads7846_setup_pendown(struct spi_device *spi,
98657691a1eSDmitry Torokhov struct ads7846 *ts,
98757691a1eSDmitry Torokhov const struct ads7846_platform_data *pdata)
9884d5975e5SEric Miao {
9890fbc9fdbSDmitry Torokhov /*
9900fbc9fdbSDmitry Torokhov * REVISIT when the irq can be triggered active-low, or if for some
9914d5975e5SEric Miao * reason the touchscreen isn't hooked up, we don't need to access
9924d5975e5SEric Miao * the pendown state.
9934d5975e5SEric Miao */
9944d5975e5SEric Miao
9954d5975e5SEric Miao if (pdata->get_pendown_state) {
9964d5975e5SEric Miao ts->get_pendown_state = pdata->get_pendown_state;
9970fbc9fdbSDmitry Torokhov } else {
998767d8336SLinus Walleij ts->gpio_pendown = gpiod_get(&spi->dev, "pendown", GPIOD_IN);
999767d8336SLinus Walleij if (IS_ERR(ts->gpio_pendown)) {
1000767d8336SLinus Walleij dev_err(&spi->dev, "failed to request pendown GPIO\n");
1001767d8336SLinus Walleij return PTR_ERR(ts->gpio_pendown);
1002767d8336SLinus Walleij }
1003767d8336SLinus Walleij if (pdata->gpio_pendown_debounce)
1004767d8336SLinus Walleij gpiod_set_debounce(ts->gpio_pendown,
1005767d8336SLinus Walleij pdata->gpio_pendown_debounce);
10060fbc9fdbSDmitry Torokhov }
10070fbc9fdbSDmitry Torokhov
10084d5975e5SEric Miao return 0;
10094d5975e5SEric Miao }
10104d5975e5SEric Miao
10112991a1caSJason Wang /*
10122991a1caSJason Wang * Set up the transfers to read touchscreen state; this assumes we
10132991a1caSJason Wang * use formula #2 for pressure, not #3.
10142991a1caSJason Wang */
ads7846_setup_spi_msg(struct ads7846 * ts,const struct ads7846_platform_data * pdata)10156965eeceSOleksij Rempel static int ads7846_setup_spi_msg(struct ads7846 *ts,
10162991a1caSJason Wang const struct ads7846_platform_data *pdata)
10172991a1caSJason Wang {
10182991a1caSJason Wang struct spi_message *m = &ts->msg[0];
10192991a1caSJason Wang struct spi_transfer *x = ts->xfer;
10202991a1caSJason Wang struct ads7846_packet *packet = ts->packet;
10212991a1caSJason Wang int vref = pdata->keep_vref_on;
10226965eeceSOleksij Rempel unsigned int count, offset = 0;
10236965eeceSOleksij Rempel unsigned int cmd_idx, b;
10246965eeceSOleksij Rempel unsigned long time;
10256965eeceSOleksij Rempel size_t size = 0;
10266965eeceSOleksij Rempel
10276965eeceSOleksij Rempel /* time per bit */
10286965eeceSOleksij Rempel time = NSEC_PER_SEC / ts->spi->max_speed_hz;
10296965eeceSOleksij Rempel
10306965eeceSOleksij Rempel count = pdata->settle_delay_usecs * NSEC_PER_USEC / time;
10316965eeceSOleksij Rempel packet->count_skip = DIV_ROUND_UP(count, 24);
10326965eeceSOleksij Rempel
10336965eeceSOleksij Rempel if (ts->debounce_max && ts->debounce_rep)
10346965eeceSOleksij Rempel /* ads7846_debounce_filter() is making ts->debounce_rep + 2
10356965eeceSOleksij Rempel * reads. So we need to get all samples for normal case. */
10366965eeceSOleksij Rempel packet->count = ts->debounce_rep + 2;
10376965eeceSOleksij Rempel else
10386965eeceSOleksij Rempel packet->count = 1;
10396965eeceSOleksij Rempel
10406965eeceSOleksij Rempel if (ts->model == 7846)
10416965eeceSOleksij Rempel packet->cmds = 5; /* x, y, z1, z2, pwdown */
10426965eeceSOleksij Rempel else
10436965eeceSOleksij Rempel packet->cmds = 3; /* x, y, pwdown */
10446965eeceSOleksij Rempel
10456965eeceSOleksij Rempel for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
10466965eeceSOleksij Rempel struct ads7846_buf_layout *l = &packet->l[cmd_idx];
10476965eeceSOleksij Rempel unsigned int max_count;
10486965eeceSOleksij Rempel
104913f82ca3SLuca Ellero if (cmd_idx == packet->cmds - 1)
105013f82ca3SLuca Ellero cmd_idx = ADS7846_PWDOWN;
105113f82ca3SLuca Ellero
10526965eeceSOleksij Rempel if (ads7846_cmd_need_settle(cmd_idx))
10536965eeceSOleksij Rempel max_count = packet->count + packet->count_skip;
10546965eeceSOleksij Rempel else
10556965eeceSOleksij Rempel max_count = packet->count;
10566965eeceSOleksij Rempel
10576965eeceSOleksij Rempel l->offset = offset;
10586965eeceSOleksij Rempel offset += max_count;
10596965eeceSOleksij Rempel l->count = max_count;
10606965eeceSOleksij Rempel l->skip = packet->count_skip;
10616965eeceSOleksij Rempel size += sizeof(*packet->tx) * max_count;
10626965eeceSOleksij Rempel }
10636965eeceSOleksij Rempel
10646965eeceSOleksij Rempel packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
10656965eeceSOleksij Rempel if (!packet->tx)
10666965eeceSOleksij Rempel return -ENOMEM;
10676965eeceSOleksij Rempel
10686965eeceSOleksij Rempel packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
10696965eeceSOleksij Rempel if (!packet->rx)
10706965eeceSOleksij Rempel return -ENOMEM;
10712991a1caSJason Wang
10722991a1caSJason Wang if (ts->model == 7873) {
10732991a1caSJason Wang /*
10742991a1caSJason Wang * The AD7873 is almost identical to the ADS7846
10752991a1caSJason Wang * keep VREF off during differential/ratiometric
10762991a1caSJason Wang * conversion modes.
10772991a1caSJason Wang */
10782991a1caSJason Wang ts->model = 7846;
10792991a1caSJason Wang vref = 0;
10802991a1caSJason Wang }
10812991a1caSJason Wang
10822991a1caSJason Wang ts->msg_count = 1;
10832991a1caSJason Wang spi_message_init(m);
10842991a1caSJason Wang m->context = ts;
10852991a1caSJason Wang
10866965eeceSOleksij Rempel for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
10876965eeceSOleksij Rempel struct ads7846_buf_layout *l = &packet->l[cmd_idx];
108813f82ca3SLuca Ellero u8 cmd;
108913f82ca3SLuca Ellero
109013f82ca3SLuca Ellero if (cmd_idx == packet->cmds - 1)
109113f82ca3SLuca Ellero cmd_idx = ADS7846_PWDOWN;
109213f82ca3SLuca Ellero
109313f82ca3SLuca Ellero cmd = ads7846_get_cmd(cmd_idx, vref);
10942991a1caSJason Wang
10956965eeceSOleksij Rempel for (b = 0; b < l->count; b++)
10966965eeceSOleksij Rempel packet->tx[l->offset + b].cmd = cmd;
10972991a1caSJason Wang }
10982991a1caSJason Wang
10996965eeceSOleksij Rempel x->tx_buf = packet->tx;
11006965eeceSOleksij Rempel x->rx_buf = packet->rx;
11016965eeceSOleksij Rempel x->len = size;
11022991a1caSJason Wang spi_message_add_tail(x, m);
11032991a1caSJason Wang
11046965eeceSOleksij Rempel return 0;
11052991a1caSJason Wang }
11062991a1caSJason Wang
1107a608026eSDaniel Mack static const struct of_device_id ads7846_dt_ids[] = {
1108a608026eSDaniel Mack { .compatible = "ti,tsc2046", .data = (void *) 7846 },
1109a608026eSDaniel Mack { .compatible = "ti,ads7843", .data = (void *) 7843 },
1110a608026eSDaniel Mack { .compatible = "ti,ads7845", .data = (void *) 7845 },
1111a608026eSDaniel Mack { .compatible = "ti,ads7846", .data = (void *) 7846 },
1112a608026eSDaniel Mack { .compatible = "ti,ads7873", .data = (void *) 7873 },
1113a608026eSDaniel Mack { }
1114a608026eSDaniel Mack };
1115a608026eSDaniel Mack MODULE_DEVICE_TABLE(of, ads7846_dt_ids);
1116a608026eSDaniel Mack
ads7846_get_props(struct device * dev)1117767d8336SLinus Walleij static const struct ads7846_platform_data *ads7846_get_props(struct device *dev)
1118a608026eSDaniel Mack {
1119a608026eSDaniel Mack struct ads7846_platform_data *pdata;
1120a2f99330SMarco Felsch u32 value;
1121a608026eSDaniel Mack
1122a608026eSDaniel Mack pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1123a608026eSDaniel Mack if (!pdata)
1124a608026eSDaniel Mack return ERR_PTR(-ENOMEM);
1125a608026eSDaniel Mack
1126*11ca6056SArnd Bergmann pdata->model = (uintptr_t)device_get_match_data(dev);
1127a608026eSDaniel Mack
1128767d8336SLinus Walleij device_property_read_u16(dev, "ti,vref-delay-usecs",
1129a608026eSDaniel Mack &pdata->vref_delay_usecs);
1130767d8336SLinus Walleij device_property_read_u16(dev, "ti,vref-mv", &pdata->vref_mv);
1131767d8336SLinus Walleij pdata->keep_vref_on = device_property_read_bool(dev, "ti,keep-vref-on");
1132a608026eSDaniel Mack
1133767d8336SLinus Walleij pdata->swap_xy = device_property_read_bool(dev, "ti,swap-xy");
1134a608026eSDaniel Mack
1135767d8336SLinus Walleij device_property_read_u16(dev, "ti,settle-delay-usec",
1136a608026eSDaniel Mack &pdata->settle_delay_usecs);
1137767d8336SLinus Walleij device_property_read_u16(dev, "ti,penirq-recheck-delay-usecs",
1138a608026eSDaniel Mack &pdata->penirq_recheck_delay_usecs);
1139a608026eSDaniel Mack
1140767d8336SLinus Walleij device_property_read_u16(dev, "ti,x-plate-ohms", &pdata->x_plate_ohms);
1141767d8336SLinus Walleij device_property_read_u16(dev, "ti,y-plate-ohms", &pdata->y_plate_ohms);
1142a608026eSDaniel Mack
1143767d8336SLinus Walleij device_property_read_u16(dev, "ti,x-min", &pdata->x_min);
1144767d8336SLinus Walleij device_property_read_u16(dev, "ti,y-min", &pdata->y_min);
1145767d8336SLinus Walleij device_property_read_u16(dev, "ti,x-max", &pdata->x_max);
1146767d8336SLinus Walleij device_property_read_u16(dev, "ti,y-max", &pdata->y_max);
1147a608026eSDaniel Mack
1148a2f99330SMarco Felsch /*
1149a2f99330SMarco Felsch * touchscreen-max-pressure gets parsed during
1150a2f99330SMarco Felsch * touchscreen_parse_properties()
1151a2f99330SMarco Felsch */
1152767d8336SLinus Walleij device_property_read_u16(dev, "ti,pressure-min", &pdata->pressure_min);
1153767d8336SLinus Walleij if (!device_property_read_u32(dev, "touchscreen-min-pressure", &value))
1154a2f99330SMarco Felsch pdata->pressure_min = (u16) value;
1155767d8336SLinus Walleij device_property_read_u16(dev, "ti,pressure-max", &pdata->pressure_max);
1156a608026eSDaniel Mack
1157767d8336SLinus Walleij device_property_read_u16(dev, "ti,debounce-max", &pdata->debounce_max);
1158767d8336SLinus Walleij if (!device_property_read_u32(dev, "touchscreen-average-samples", &value))
1159a2f99330SMarco Felsch pdata->debounce_max = (u16) value;
1160767d8336SLinus Walleij device_property_read_u16(dev, "ti,debounce-tol", &pdata->debounce_tol);
1161767d8336SLinus Walleij device_property_read_u16(dev, "ti,debounce-rep", &pdata->debounce_rep);
1162a608026eSDaniel Mack
1163767d8336SLinus Walleij device_property_read_u32(dev, "ti,pendown-gpio-debounce",
1164a608026eSDaniel Mack &pdata->gpio_pendown_debounce);
1165a608026eSDaniel Mack
1166767d8336SLinus Walleij pdata->wakeup = device_property_read_bool(dev, "wakeup-source") ||
1167767d8336SLinus Walleij device_property_read_bool(dev, "linux,wakeup");
1168a608026eSDaniel Mack
1169a608026eSDaniel Mack return pdata;
1170a608026eSDaniel Mack }
1171a608026eSDaniel Mack
ads7846_regulator_disable(void * regulator)1172845ef3a7SDaniel Mack static void ads7846_regulator_disable(void *regulator)
1173845ef3a7SDaniel Mack {
1174845ef3a7SDaniel Mack regulator_disable(regulator);
1175845ef3a7SDaniel Mack }
1176845ef3a7SDaniel Mack
ads7846_probe(struct spi_device * spi)11775298cc4cSBill Pemberton static int ads7846_probe(struct spi_device *spi)
1178ffa458c1SDavid Brownell {
1179a608026eSDaniel Mack const struct ads7846_platform_data *pdata;
1180ffa458c1SDavid Brownell struct ads7846 *ts;
1181de609b56SDaniel Mack struct device *dev = &spi->dev;
1182e8f462d2SDmitry Torokhov struct ads7846_packet *packet;
1183a90f7e98SDmitry Torokhov struct input_dev *input_dev;
11840f622bf4SDmitry Torokhov unsigned long irq_flags;
1185a90f7e98SDmitry Torokhov int err;
1186ffa458c1SDavid Brownell
1187ffa458c1SDavid Brownell if (!spi->irq) {
1188de609b56SDaniel Mack dev_dbg(dev, "no IRQ?\n");
1189a608026eSDaniel Mack return -EINVAL;
1190ffa458c1SDavid Brownell }
1191ffa458c1SDavid Brownell
1192ffa458c1SDavid Brownell /* don't exceed max specified sample rate */
1193d93f70b2SDavid Brownell if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
1194de609b56SDaniel Mack dev_err(dev, "f(sample) %d KHz?\n",
1195d93f70b2SDavid Brownell (spi->max_speed_hz/SAMPLE_BITS)/1000);
1196ffa458c1SDavid Brownell return -EINVAL;
1197ffa458c1SDavid Brownell }
1198ffa458c1SDavid Brownell
1199a608026eSDaniel Mack /*
1200a608026eSDaniel Mack * We'd set TX word size 8 bits and RX word size to 13 bits ... except
12019084533eSDavid Brownell * that even if the hardware can do that, the SPI controller driver
12029084533eSDavid Brownell * may not. So we stick to very-portable 8 bit words, both RX and TX.
1203ffa458c1SDavid Brownell */
12049084533eSDavid Brownell spi->bits_per_word = 8;
1205376ccca8SOleksij Rempel spi->mode &= ~SPI_MODE_X_MASK;
1206376ccca8SOleksij Rempel spi->mode |= SPI_MODE_0;
12077937e86aSImre Deak err = spi_setup(spi);
12087937e86aSImre Deak if (err < 0)
12097937e86aSImre Deak return err;
1210ffa458c1SDavid Brownell
1211845ef3a7SDaniel Mack ts = devm_kzalloc(dev, sizeof(struct ads7846), GFP_KERNEL);
1212845ef3a7SDaniel Mack if (!ts)
1213845ef3a7SDaniel Mack return -ENOMEM;
1214845ef3a7SDaniel Mack
1215845ef3a7SDaniel Mack packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL);
1216845ef3a7SDaniel Mack if (!packet)
1217845ef3a7SDaniel Mack return -ENOMEM;
1218845ef3a7SDaniel Mack
1219845ef3a7SDaniel Mack input_dev = devm_input_allocate_device(dev);
1220845ef3a7SDaniel Mack if (!input_dev)
1221845ef3a7SDaniel Mack return -ENOMEM;
1222ffa458c1SDavid Brownell
1223c12454faSJingoo Han spi_set_drvdata(spi, ts);
1224ffa458c1SDavid Brownell
1225e8f462d2SDmitry Torokhov ts->packet = packet;
1226ffa458c1SDavid Brownell ts->spi = spi;
1227a90f7e98SDmitry Torokhov ts->input = input_dev;
1228ffa458c1SDavid Brownell
12292991a1caSJason Wang mutex_init(&ts->lock);
12302991a1caSJason Wang init_waitqueue_head(&ts->wait);
12317de90a8cSImre Deak
1232de609b56SDaniel Mack pdata = dev_get_platdata(dev);
1233a608026eSDaniel Mack if (!pdata) {
1234767d8336SLinus Walleij pdata = ads7846_get_props(dev);
1235845ef3a7SDaniel Mack if (IS_ERR(pdata))
1236845ef3a7SDaniel Mack return PTR_ERR(pdata);
1237a608026eSDaniel Mack }
1238a608026eSDaniel Mack
1239ffa458c1SDavid Brownell ts->model = pdata->model ? : 7846;
1240ffa458c1SDavid Brownell ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
1241ffa458c1SDavid Brownell ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
1242a608026eSDaniel Mack ts->vref_mv = pdata->vref_mv;
1243a608026eSDaniel Mack
1244937f5d5eSDaniel Mack if (pdata->debounce_max) {
1245d5b415c9SImre Deak ts->debounce_max = pdata->debounce_max;
1246da970e69SImre Deak if (ts->debounce_max < 2)
1247da970e69SImre Deak ts->debounce_max = 2;
1248d5b415c9SImre Deak ts->debounce_tol = pdata->debounce_tol;
1249d5b415c9SImre Deak ts->debounce_rep = pdata->debounce_rep;
12502991a1caSJason Wang ts->filter = ads7846_debounce_filter;
1251da970e69SImre Deak ts->filter_data = ts;
12522991a1caSJason Wang } else {
1253da970e69SImre Deak ts->filter = ads7846_no_filter;
12542991a1caSJason Wang }
12554d5975e5SEric Miao
125657691a1eSDmitry Torokhov err = ads7846_setup_pendown(spi, ts, pdata);
12574d5975e5SEric Miao if (err)
1258845ef3a7SDaniel Mack return err;
1259ffa458c1SDavid Brownell
12601d25891fSSemih Hazar if (pdata->penirq_recheck_delay_usecs)
12611d25891fSSemih Hazar ts->penirq_recheck_delay_usecs =
12621d25891fSSemih Hazar pdata->penirq_recheck_delay_usecs;
12631d25891fSSemih Hazar
1264fd746d54SEric Miao ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
1265fd746d54SEric Miao
1266de609b56SDaniel Mack snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
1267b58895f8SMichael Roth snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
1268ffa458c1SDavid Brownell
1269b58895f8SMichael Roth input_dev->name = ts->name;
1270a90f7e98SDmitry Torokhov input_dev->phys = ts->phys;
1271ffa458c1SDavid Brownell
12729271cda2SDmitry Torokhov input_dev->id.bustype = BUS_SPI;
12739271cda2SDmitry Torokhov input_dev->id.product = pdata->model;
12749271cda2SDmitry Torokhov
1275ccd66139SDmitry Torokhov input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
1276a90f7e98SDmitry Torokhov input_set_abs_params(input_dev, ABS_X,
1277ffa458c1SDavid Brownell pdata->x_min ? : 0,
1278ffa458c1SDavid Brownell pdata->x_max ? : MAX_12BIT,
1279ffa458c1SDavid Brownell 0, 0);
1280a90f7e98SDmitry Torokhov input_set_abs_params(input_dev, ABS_Y,
1281ffa458c1SDavid Brownell pdata->y_min ? : 0,
1282ffa458c1SDavid Brownell pdata->y_max ? : MAX_12BIT,
1283ffa458c1SDavid Brownell 0, 0);
1284d50584d7SLuca Ellero if (ts->model != 7845)
1285a90f7e98SDmitry Torokhov input_set_abs_params(input_dev, ABS_PRESSURE,
1286ffa458c1SDavid Brownell pdata->pressure_min, pdata->pressure_max, 0, 0);
1287ffa458c1SDavid Brownell
1288a2f99330SMarco Felsch /*
1289a2f99330SMarco Felsch * Parse common framework properties. Must be done here to ensure the
1290a2f99330SMarco Felsch * correct behaviour in case of using the legacy vendor bindings. The
1291a2f99330SMarco Felsch * general binding value overrides the vendor specific one.
1292a2f99330SMarco Felsch */
1293a2f99330SMarco Felsch touchscreen_parse_properties(ts->input, false, &ts->core_prop);
1294a2f99330SMarco Felsch ts->pressure_max = input_abs_get_max(input_dev, ABS_PRESSURE) ? : ~0;
1295a2f99330SMarco Felsch
1296a2f99330SMarco Felsch /*
1297a2f99330SMarco Felsch * Check if legacy ti,swap-xy binding is used instead of
1298a2f99330SMarco Felsch * touchscreen-swapped-x-y
1299a2f99330SMarco Felsch */
1300a2f99330SMarco Felsch if (!ts->core_prop.swap_x_y && pdata->swap_xy) {
1301a2f99330SMarco Felsch swap(input_dev->absinfo[ABS_X], input_dev->absinfo[ABS_Y]);
1302a2f99330SMarco Felsch ts->core_prop.swap_x_y = true;
1303a2f99330SMarco Felsch }
1304a2f99330SMarco Felsch
13052991a1caSJason Wang ads7846_setup_spi_msg(ts, pdata);
1306d5b415c9SImre Deak
1307845ef3a7SDaniel Mack ts->reg = devm_regulator_get(dev, "vcc");
130891143379SGrazvydas Ignotas if (IS_ERR(ts->reg)) {
1309067fb2f6SKevin Hilman err = PTR_ERR(ts->reg);
1310de609b56SDaniel Mack dev_err(dev, "unable to get regulator: %d\n", err);
1311845ef3a7SDaniel Mack return err;
131291143379SGrazvydas Ignotas }
131391143379SGrazvydas Ignotas
131491143379SGrazvydas Ignotas err = regulator_enable(ts->reg);
131591143379SGrazvydas Ignotas if (err) {
1316de609b56SDaniel Mack dev_err(dev, "unable to enable regulator: %d\n", err);
1317845ef3a7SDaniel Mack return err;
131891143379SGrazvydas Ignotas }
131991143379SGrazvydas Ignotas
1320845ef3a7SDaniel Mack err = devm_add_action_or_reset(dev, ads7846_regulator_disable, ts->reg);
1321845ef3a7SDaniel Mack if (err)
1322845ef3a7SDaniel Mack return err;
1323845ef3a7SDaniel Mack
13240f622bf4SDmitry Torokhov irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
13252991a1caSJason Wang irq_flags |= IRQF_ONESHOT;
13267804302bSAnatolij Gustschin
1327845ef3a7SDaniel Mack err = devm_request_threaded_irq(dev, spi->irq,
1328845ef3a7SDaniel Mack ads7846_hard_irq, ads7846_irq,
1329de609b56SDaniel Mack irq_flags, dev->driver->name, ts);
133036fc5437SDmitry Torokhov if (err && err != -EPROBE_DEFER && !pdata->irq_flags) {
1331de609b56SDaniel Mack dev_info(dev,
1332c57c0a2aSMichael Roth "trying pin change workaround on irq %d\n", spi->irq);
13332991a1caSJason Wang irq_flags |= IRQF_TRIGGER_RISING;
1334845ef3a7SDaniel Mack err = devm_request_threaded_irq(dev, spi->irq,
13352991a1caSJason Wang ads7846_hard_irq, ads7846_irq,
1336845ef3a7SDaniel Mack irq_flags, dev->driver->name,
1337845ef3a7SDaniel Mack ts);
13380f622bf4SDmitry Torokhov }
13390f622bf4SDmitry Torokhov
1340c57c0a2aSMichael Roth if (err) {
1341de609b56SDaniel Mack dev_dbg(dev, "irq %d busy?\n", spi->irq);
1342845ef3a7SDaniel Mack return err;
1343ffa458c1SDavid Brownell }
1344ffa458c1SDavid Brownell
13452c8dc071SDavid Brownell err = ads784x_hwmon_register(spi, ts);
13462c8dc071SDavid Brownell if (err)
1347845ef3a7SDaniel Mack return err;
13482c8dc071SDavid Brownell
1349de609b56SDaniel Mack dev_info(dev, "touchscreen, irq %d\n", spi->irq);
1350ffa458c1SDavid Brownell
13512991a1caSJason Wang /*
13522991a1caSJason Wang * Take a first sample, leaving nPENIRQ active and vREF off; avoid
1353ffa458c1SDavid Brownell * the touchscreen, in case it's not connected.
1354ffa458c1SDavid Brownell */
13553eac5c7eSAnatolij Gustschin if (ts->model == 7845)
1356de609b56SDaniel Mack ads7845_read12_ser(dev, PWRDOWN);
13573eac5c7eSAnatolij Gustschin else
1358de609b56SDaniel Mack (void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux));
1359ffa458c1SDavid Brownell
1360845ef3a7SDaniel Mack err = devm_device_add_group(dev, &ads784x_attr_group);
13618dd51650SDmitry Torokhov if (err)
1362845ef3a7SDaniel Mack return err;
13637de90a8cSImre Deak
1364a90f7e98SDmitry Torokhov err = input_register_device(input_dev);
1365a90f7e98SDmitry Torokhov if (err)
1366845ef3a7SDaniel Mack return err;
1367a90f7e98SDmitry Torokhov
1368de609b56SDaniel Mack device_init_wakeup(dev, pdata->wakeup);
1369fdba2bb1SRanjith Lohithakshan
1370a608026eSDaniel Mack /*
1371a608026eSDaniel Mack * If device does not carry platform data we must have allocated it
1372a608026eSDaniel Mack * when parsing DT data.
1373a608026eSDaniel Mack */
1374de609b56SDaniel Mack if (!dev_get_platdata(dev))
1375de609b56SDaniel Mack devm_kfree(dev, (void *)pdata);
1376a608026eSDaniel Mack
1377ffa458c1SDavid Brownell return 0;
1378ffa458c1SDavid Brownell }
1379ffa458c1SDavid Brownell
ads7846_remove(struct spi_device * spi)1380a0386bbaSUwe Kleine-König static void ads7846_remove(struct spi_device *spi)
1381ffa458c1SDavid Brownell {
1382c12454faSJingoo Han struct ads7846 *ts = spi_get_drvdata(spi);
1383ffa458c1SDavid Brownell
1384845ef3a7SDaniel Mack ads7846_stop(ts);
1385ffa458c1SDavid Brownell }
1386ffa458c1SDavid Brownell
13872e5a7bd9SDavid Brownell static struct spi_driver ads7846_driver = {
13882e5a7bd9SDavid Brownell .driver = {
1389ffa458c1SDavid Brownell .name = "ads7846",
1390f8909d9aSJonathan Cameron .pm = pm_sleep_ptr(&ads7846_pm),
1391767d8336SLinus Walleij .of_match_table = ads7846_dt_ids,
13922e5a7bd9SDavid Brownell },
1393ffa458c1SDavid Brownell .probe = ads7846_probe,
13941cb0aa88SBill Pemberton .remove = ads7846_remove,
1395ffa458c1SDavid Brownell };
1396ffa458c1SDavid Brownell
1397ca83922eSAxel Lin module_spi_driver(ads7846_driver);
1398ffa458c1SDavid Brownell
1399ffa458c1SDavid Brownell MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
1400ffa458c1SDavid Brownell MODULE_LICENSE("GPL");
1401e0626e38SAnton Vorontsov MODULE_ALIAS("spi:ads7846");
1402