18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ADS7846 based touchscreen and sensor driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2005 David Brownell 68c2ecf20Sopenharmony_ci * Copyright (c) 2006 Nokia Corporation 78c2ecf20Sopenharmony_ci * Various changes: Imre Deak <imre.deak@nokia.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Using code from: 108c2ecf20Sopenharmony_ci * - corgi_ts.c 118c2ecf20Sopenharmony_ci * Copyright (C) 2004-2005 Richard Purdie 128c2ecf20Sopenharmony_ci * - omap_ts.[hc], ads7846.h, ts_osk.c 138c2ecf20Sopenharmony_ci * Copyright (C) 2002 MontaVista Software 148c2ecf20Sopenharmony_ci * Copyright (C) 2004 Texas Instruments 158c2ecf20Sopenharmony_ci * Copyright (C) 2005 Dirk Behme 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/sched.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/input.h> 238c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/pm.h> 278c2ecf20Sopenharmony_ci#include <linux/of.h> 288c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 298c2ecf20Sopenharmony_ci#include <linux/of_device.h> 308c2ecf20Sopenharmony_ci#include <linux/gpio.h> 318c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 328c2ecf20Sopenharmony_ci#include <linux/spi/ads7846.h> 338c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 348c2ecf20Sopenharmony_ci#include <linux/module.h> 358c2ecf20Sopenharmony_ci#include <asm/irq.h> 368c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * This code has been heavily tested on a Nokia 770, and lightly 408c2ecf20Sopenharmony_ci * tested on other ads7846 devices (OSK/Mistral, Lubbock, Spitz). 418c2ecf20Sopenharmony_ci * TSC2046 is just newer ads7846 silicon. 428c2ecf20Sopenharmony_ci * Support for ads7843 tested on Atmel at91sam926x-EK. 438c2ecf20Sopenharmony_ci * Support for ads7845 has only been stubbed in. 448c2ecf20Sopenharmony_ci * Support for Analog Devices AD7873 and AD7843 tested. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * IRQ handling needs a workaround because of a shortcoming in handling 478c2ecf20Sopenharmony_ci * edge triggered IRQs on some platforms like the OMAP1/2. These 488c2ecf20Sopenharmony_ci * platforms don't handle the ARM lazy IRQ disabling properly, thus we 498c2ecf20Sopenharmony_ci * have to maintain our own SW IRQ disabled status. This should be 508c2ecf20Sopenharmony_ci * removed as soon as the affected platform's IRQ handling is fixed. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * App note sbaa036 talks in more detail about accurate sampling... 538c2ecf20Sopenharmony_ci * that ought to help in situations like LCDs inducing noise (which 548c2ecf20Sopenharmony_ci * can also be helped by using synch signals) and more generally. 558c2ecf20Sopenharmony_ci * This driver tries to utilize the measures described in the app 568c2ecf20Sopenharmony_ci * note. The strength of filtering can be set in the board-* specific 578c2ecf20Sopenharmony_ci * files. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define TS_POLL_DELAY 1 /* ms delay before the first sample */ 618c2ecf20Sopenharmony_ci#define TS_POLL_PERIOD 5 /* ms delay between samples */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* this driver doesn't aim at the peak continuous sample rate */ 648c2ecf20Sopenharmony_ci#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct ads7846_buf { 678c2ecf20Sopenharmony_ci u8 cmd; 688c2ecf20Sopenharmony_ci __be16 data; 698c2ecf20Sopenharmony_ci} __packed; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct ads7846_buf_layout { 728c2ecf20Sopenharmony_ci unsigned int offset; 738c2ecf20Sopenharmony_ci unsigned int count; 748c2ecf20Sopenharmony_ci unsigned int skip; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * We allocate this separately to avoid cache line sharing issues when 798c2ecf20Sopenharmony_ci * driver is used with DMA-based SPI controllers (like atmel_spi) on 808c2ecf20Sopenharmony_ci * systems where main memory is not DMA-coherent (most non-x86 boards). 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistruct ads7846_packet { 838c2ecf20Sopenharmony_ci unsigned int count; 848c2ecf20Sopenharmony_ci unsigned int count_skip; 858c2ecf20Sopenharmony_ci unsigned int cmds; 868c2ecf20Sopenharmony_ci unsigned int last_cmd_idx; 878c2ecf20Sopenharmony_ci struct ads7846_buf_layout l[5]; 888c2ecf20Sopenharmony_ci struct ads7846_buf *rx; 898c2ecf20Sopenharmony_ci struct ads7846_buf *tx; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci struct ads7846_buf pwrdown_cmd; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci bool ignore; 948c2ecf20Sopenharmony_ci u16 x, y, z1, z2; 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistruct ads7846 { 988c2ecf20Sopenharmony_ci struct input_dev *input; 998c2ecf20Sopenharmony_ci char phys[32]; 1008c2ecf20Sopenharmony_ci char name[32]; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci struct spi_device *spi; 1038c2ecf20Sopenharmony_ci struct regulator *reg; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_HWMON) 1068c2ecf20Sopenharmony_ci struct device *hwmon; 1078c2ecf20Sopenharmony_ci#endif 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci u16 model; 1108c2ecf20Sopenharmony_ci u16 vref_mv; 1118c2ecf20Sopenharmony_ci u16 vref_delay_usecs; 1128c2ecf20Sopenharmony_ci u16 x_plate_ohms; 1138c2ecf20Sopenharmony_ci u16 pressure_max; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci bool swap_xy; 1168c2ecf20Sopenharmony_ci bool use_internal; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci struct ads7846_packet *packet; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci struct spi_transfer xfer[18]; 1218c2ecf20Sopenharmony_ci struct spi_message msg[5]; 1228c2ecf20Sopenharmony_ci int msg_count; 1238c2ecf20Sopenharmony_ci wait_queue_head_t wait; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci bool pendown; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci int read_cnt; 1288c2ecf20Sopenharmony_ci int read_rep; 1298c2ecf20Sopenharmony_ci int last_read; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci u16 debounce_max; 1328c2ecf20Sopenharmony_ci u16 debounce_tol; 1338c2ecf20Sopenharmony_ci u16 debounce_rep; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci u16 penirq_recheck_delay_usecs; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci struct touchscreen_properties core_prop; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci struct mutex lock; 1408c2ecf20Sopenharmony_ci bool stopped; /* P: lock */ 1418c2ecf20Sopenharmony_ci bool disabled; /* P: lock */ 1428c2ecf20Sopenharmony_ci bool suspended; /* P: lock */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci int (*filter)(void *data, int data_idx, int *val); 1458c2ecf20Sopenharmony_ci void *filter_data; 1468c2ecf20Sopenharmony_ci void (*filter_cleanup)(void *data); 1478c2ecf20Sopenharmony_ci int (*get_pendown_state)(void); 1488c2ecf20Sopenharmony_ci int gpio_pendown; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci void (*wait_for_sync)(void); 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* leave chip selected when we're done, for quicker re-select? */ 1548c2ecf20Sopenharmony_ci#if 0 1558c2ecf20Sopenharmony_ci#define CS_CHANGE(xfer) ((xfer).cs_change = 1) 1568c2ecf20Sopenharmony_ci#else 1578c2ecf20Sopenharmony_ci#define CS_CHANGE(xfer) ((xfer).cs_change = 0) 1588c2ecf20Sopenharmony_ci#endif 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* The ADS7846 has touchscreen and other sensors. 1638c2ecf20Sopenharmony_ci * Earlier ads784x chips are somewhat compatible. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci#define ADS_START (1 << 7) 1668c2ecf20Sopenharmony_ci#define ADS_A2A1A0_d_y (1 << 4) /* differential */ 1678c2ecf20Sopenharmony_ci#define ADS_A2A1A0_d_z1 (3 << 4) /* differential */ 1688c2ecf20Sopenharmony_ci#define ADS_A2A1A0_d_z2 (4 << 4) /* differential */ 1698c2ecf20Sopenharmony_ci#define ADS_A2A1A0_d_x (5 << 4) /* differential */ 1708c2ecf20Sopenharmony_ci#define ADS_A2A1A0_temp0 (0 << 4) /* non-differential */ 1718c2ecf20Sopenharmony_ci#define ADS_A2A1A0_vbatt (2 << 4) /* non-differential */ 1728c2ecf20Sopenharmony_ci#define ADS_A2A1A0_vaux (6 << 4) /* non-differential */ 1738c2ecf20Sopenharmony_ci#define ADS_A2A1A0_temp1 (7 << 4) /* non-differential */ 1748c2ecf20Sopenharmony_ci#define ADS_8_BIT (1 << 3) 1758c2ecf20Sopenharmony_ci#define ADS_12_BIT (0 << 3) 1768c2ecf20Sopenharmony_ci#define ADS_SER (1 << 2) /* non-differential */ 1778c2ecf20Sopenharmony_ci#define ADS_DFR (0 << 2) /* differential */ 1788c2ecf20Sopenharmony_ci#define ADS_PD10_PDOWN (0 << 0) /* low power mode + penirq */ 1798c2ecf20Sopenharmony_ci#define ADS_PD10_ADC_ON (1 << 0) /* ADC on */ 1808c2ecf20Sopenharmony_ci#define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */ 1818c2ecf20Sopenharmony_ci#define ADS_PD10_ALL_ON (3 << 0) /* ADC + vREF on */ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define MAX_12BIT ((1<<12)-1) 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* leave ADC powered up (disables penirq) between differential samples */ 1868c2ecf20Sopenharmony_ci#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \ 1878c2ecf20Sopenharmony_ci | ADS_12_BIT | ADS_DFR | \ 1888c2ecf20Sopenharmony_ci (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0)) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref)) 1918c2ecf20Sopenharmony_ci#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref)) 1928c2ecf20Sopenharmony_ci#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref)) 1938c2ecf20Sopenharmony_ci#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref)) 1948c2ecf20Sopenharmony_ci#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* single-ended samples need to first power up reference voltage; 1978c2ecf20Sopenharmony_ci * we leave both ADC and VREF powered 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci#define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \ 2008c2ecf20Sopenharmony_ci | ADS_12_BIT | ADS_SER) 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci#define REF_ON (READ_12BIT_DFR(x, 1, 1)) 2038c2ecf20Sopenharmony_ci#define REF_OFF (READ_12BIT_DFR(y, 0, 0)) 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* Order commands in the most optimal way to reduce Vref switching and 2068c2ecf20Sopenharmony_ci * settling time: 2078c2ecf20Sopenharmony_ci * Measure: X; Vref: X+, X-; IN: Y+ 2088c2ecf20Sopenharmony_ci * Measure: Y; Vref: Y+, Y-; IN: X+ 2098c2ecf20Sopenharmony_ci * Measure: Z1; Vref: Y+, X-; IN: X+ 2108c2ecf20Sopenharmony_ci * Measure: Z2; Vref: Y+, X-; IN: Y- 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cienum ads7846_cmds { 2138c2ecf20Sopenharmony_ci ADS7846_X, 2148c2ecf20Sopenharmony_ci ADS7846_Y, 2158c2ecf20Sopenharmony_ci ADS7846_Z1, 2168c2ecf20Sopenharmony_ci ADS7846_Z2, 2178c2ecf20Sopenharmony_ci ADS7846_PWDOWN, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int get_pendown_state(struct ads7846 *ts) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci if (ts->get_pendown_state) 2238c2ecf20Sopenharmony_ci return ts->get_pendown_state(); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return !gpio_get_value(ts->gpio_pendown); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void ads7846_report_pen_up(struct ads7846 *ts) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci input_report_key(input, BTN_TOUCH, 0); 2338c2ecf20Sopenharmony_ci input_report_abs(input, ABS_PRESSURE, 0); 2348c2ecf20Sopenharmony_ci input_sync(input); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ts->pendown = false; 2378c2ecf20Sopenharmony_ci dev_vdbg(&ts->spi->dev, "UP\n"); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* Must be called with ts->lock held */ 2418c2ecf20Sopenharmony_cistatic void ads7846_stop(struct ads7846 *ts) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci if (!ts->disabled && !ts->suspended) { 2448c2ecf20Sopenharmony_ci /* Signal IRQ thread to stop polling and disable the handler. */ 2458c2ecf20Sopenharmony_ci ts->stopped = true; 2468c2ecf20Sopenharmony_ci mb(); 2478c2ecf20Sopenharmony_ci wake_up(&ts->wait); 2488c2ecf20Sopenharmony_ci disable_irq(ts->spi->irq); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* Must be called with ts->lock held */ 2538c2ecf20Sopenharmony_cistatic void ads7846_restart(struct ads7846 *ts) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci if (!ts->disabled && !ts->suspended) { 2568c2ecf20Sopenharmony_ci /* Check if pen was released since last stop */ 2578c2ecf20Sopenharmony_ci if (ts->pendown && !get_pendown_state(ts)) 2588c2ecf20Sopenharmony_ci ads7846_report_pen_up(ts); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Tell IRQ thread that it may poll the device. */ 2618c2ecf20Sopenharmony_ci ts->stopped = false; 2628c2ecf20Sopenharmony_ci mb(); 2638c2ecf20Sopenharmony_ci enable_irq(ts->spi->irq); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Must be called with ts->lock held */ 2688c2ecf20Sopenharmony_cistatic void __ads7846_disable(struct ads7846 *ts) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci ads7846_stop(ts); 2718c2ecf20Sopenharmony_ci regulator_disable(ts->reg); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * We know the chip's in low power mode since we always 2758c2ecf20Sopenharmony_ci * leave it that way after every request 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* Must be called with ts->lock held */ 2808c2ecf20Sopenharmony_cistatic void __ads7846_enable(struct ads7846 *ts) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci int error; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci error = regulator_enable(ts->reg); 2858c2ecf20Sopenharmony_ci if (error != 0) 2868c2ecf20Sopenharmony_ci dev_err(&ts->spi->dev, "Failed to enable supply: %d\n", error); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ads7846_restart(ts); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void ads7846_disable(struct ads7846 *ts) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci mutex_lock(&ts->lock); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!ts->disabled) { 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (!ts->suspended) 2988c2ecf20Sopenharmony_ci __ads7846_disable(ts); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ts->disabled = true; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci mutex_unlock(&ts->lock); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void ads7846_enable(struct ads7846 *ts) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci mutex_lock(&ts->lock); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (ts->disabled) { 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ts->disabled = false; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!ts->suspended) 3158c2ecf20Sopenharmony_ci __ads7846_enable(ts); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci mutex_unlock(&ts->lock); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/ 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* 3248c2ecf20Sopenharmony_ci * Non-touchscreen sensors only use single-ended conversions. 3258c2ecf20Sopenharmony_ci * The range is GND..vREF. The ads7843 and ads7835 must use external vREF; 3268c2ecf20Sopenharmony_ci * ads7846 lets that pin be unconnected, to use internal vREF. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistruct ser_req { 3308c2ecf20Sopenharmony_ci u8 ref_on; 3318c2ecf20Sopenharmony_ci u8 command; 3328c2ecf20Sopenharmony_ci u8 ref_off; 3338c2ecf20Sopenharmony_ci u16 scratch; 3348c2ecf20Sopenharmony_ci struct spi_message msg; 3358c2ecf20Sopenharmony_ci struct spi_transfer xfer[6]; 3368c2ecf20Sopenharmony_ci /* 3378c2ecf20Sopenharmony_ci * DMA (thus cache coherency maintenance) requires the 3388c2ecf20Sopenharmony_ci * transfer buffers to live in their own cache lines. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci __be16 sample ____cacheline_aligned; 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistruct ads7845_ser_req { 3448c2ecf20Sopenharmony_ci u8 command[3]; 3458c2ecf20Sopenharmony_ci struct spi_message msg; 3468c2ecf20Sopenharmony_ci struct spi_transfer xfer[2]; 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * DMA (thus cache coherency maintenance) requires the 3498c2ecf20Sopenharmony_ci * transfer buffers to live in their own cache lines. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci u8 sample[3] ____cacheline_aligned; 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int ads7846_read12_ser(struct device *dev, unsigned command) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 3578c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 3588c2ecf20Sopenharmony_ci struct ser_req *req; 3598c2ecf20Sopenharmony_ci int status; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci req = kzalloc(sizeof *req, GFP_KERNEL); 3628c2ecf20Sopenharmony_ci if (!req) 3638c2ecf20Sopenharmony_ci return -ENOMEM; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci spi_message_init(&req->msg); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* maybe turn on internal vREF, and let it settle */ 3688c2ecf20Sopenharmony_ci if (ts->use_internal) { 3698c2ecf20Sopenharmony_ci req->ref_on = REF_ON; 3708c2ecf20Sopenharmony_ci req->xfer[0].tx_buf = &req->ref_on; 3718c2ecf20Sopenharmony_ci req->xfer[0].len = 1; 3728c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[0], &req->msg); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci req->xfer[1].rx_buf = &req->scratch; 3758c2ecf20Sopenharmony_ci req->xfer[1].len = 2; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* for 1uF, settle for 800 usec; no cap, 100 usec. */ 3788c2ecf20Sopenharmony_ci req->xfer[1].delay.value = ts->vref_delay_usecs; 3798c2ecf20Sopenharmony_ci req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS; 3808c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[1], &req->msg); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Enable reference voltage */ 3838c2ecf20Sopenharmony_ci command |= ADS_PD10_REF_ON; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Enable ADC in every case */ 3878c2ecf20Sopenharmony_ci command |= ADS_PD10_ADC_ON; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* take sample */ 3908c2ecf20Sopenharmony_ci req->command = (u8) command; 3918c2ecf20Sopenharmony_ci req->xfer[2].tx_buf = &req->command; 3928c2ecf20Sopenharmony_ci req->xfer[2].len = 1; 3938c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[2], &req->msg); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci req->xfer[3].rx_buf = &req->sample; 3968c2ecf20Sopenharmony_ci req->xfer[3].len = 2; 3978c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[3], &req->msg); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* REVISIT: take a few more samples, and compare ... */ 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* converter in low power mode & enable PENIRQ */ 4028c2ecf20Sopenharmony_ci req->ref_off = PWRDOWN; 4038c2ecf20Sopenharmony_ci req->xfer[4].tx_buf = &req->ref_off; 4048c2ecf20Sopenharmony_ci req->xfer[4].len = 1; 4058c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[4], &req->msg); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci req->xfer[5].rx_buf = &req->scratch; 4088c2ecf20Sopenharmony_ci req->xfer[5].len = 2; 4098c2ecf20Sopenharmony_ci CS_CHANGE(req->xfer[5]); 4108c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[5], &req->msg); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci mutex_lock(&ts->lock); 4138c2ecf20Sopenharmony_ci ads7846_stop(ts); 4148c2ecf20Sopenharmony_ci status = spi_sync(spi, &req->msg); 4158c2ecf20Sopenharmony_ci ads7846_restart(ts); 4168c2ecf20Sopenharmony_ci mutex_unlock(&ts->lock); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (status == 0) { 4198c2ecf20Sopenharmony_ci /* on-wire is a must-ignore bit, a BE12 value, then padding */ 4208c2ecf20Sopenharmony_ci status = be16_to_cpu(req->sample); 4218c2ecf20Sopenharmony_ci status = status >> 3; 4228c2ecf20Sopenharmony_ci status &= 0x0fff; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci kfree(req); 4268c2ecf20Sopenharmony_ci return status; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int ads7845_read12_ser(struct device *dev, unsigned command) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4328c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 4338c2ecf20Sopenharmony_ci struct ads7845_ser_req *req; 4348c2ecf20Sopenharmony_ci int status; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci req = kzalloc(sizeof *req, GFP_KERNEL); 4378c2ecf20Sopenharmony_ci if (!req) 4388c2ecf20Sopenharmony_ci return -ENOMEM; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spi_message_init(&req->msg); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci req->command[0] = (u8) command; 4438c2ecf20Sopenharmony_ci req->xfer[0].tx_buf = req->command; 4448c2ecf20Sopenharmony_ci req->xfer[0].rx_buf = req->sample; 4458c2ecf20Sopenharmony_ci req->xfer[0].len = 3; 4468c2ecf20Sopenharmony_ci spi_message_add_tail(&req->xfer[0], &req->msg); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci mutex_lock(&ts->lock); 4498c2ecf20Sopenharmony_ci ads7846_stop(ts); 4508c2ecf20Sopenharmony_ci status = spi_sync(spi, &req->msg); 4518c2ecf20Sopenharmony_ci ads7846_restart(ts); 4528c2ecf20Sopenharmony_ci mutex_unlock(&ts->lock); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (status == 0) { 4558c2ecf20Sopenharmony_ci /* BE12 value, then padding */ 4568c2ecf20Sopenharmony_ci status = get_unaligned_be16(&req->sample[1]); 4578c2ecf20Sopenharmony_ci status = status >> 3; 4588c2ecf20Sopenharmony_ci status &= 0x0fff; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci kfree(req); 4628c2ecf20Sopenharmony_ci return status; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_HWMON) 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci#define SHOW(name, var, adjust) static ssize_t \ 4688c2ecf20Sopenharmony_ciname ## _show(struct device *dev, struct device_attribute *attr, char *buf) \ 4698c2ecf20Sopenharmony_ci{ \ 4708c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); \ 4718c2ecf20Sopenharmony_ci ssize_t v = ads7846_read12_ser(&ts->spi->dev, \ 4728c2ecf20Sopenharmony_ci READ_12BIT_SER(var)); \ 4738c2ecf20Sopenharmony_ci if (v < 0) \ 4748c2ecf20Sopenharmony_ci return v; \ 4758c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", adjust(ts, v)); \ 4768c2ecf20Sopenharmony_ci} \ 4778c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci/* Sysfs conventions report temperatures in millidegrees Celsius. 4818c2ecf20Sopenharmony_ci * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high 4828c2ecf20Sopenharmony_ci * accuracy scheme without calibration data. For now we won't try either; 4838c2ecf20Sopenharmony_ci * userspace sees raw sensor values, and must scale/calibrate appropriately. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_cistatic inline unsigned null_adjust(struct ads7846 *ts, ssize_t v) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci return v; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ciSHOW(temp0, temp0, null_adjust) /* temp1_input */ 4918c2ecf20Sopenharmony_ciSHOW(temp1, temp1, null_adjust) /* temp2_input */ 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* sysfs conventions report voltages in millivolts. We can convert voltages 4958c2ecf20Sopenharmony_ci * if we know vREF. userspace may need to scale vAUX to match the board's 4968c2ecf20Sopenharmony_ci * external resistors; we assume that vBATT only uses the internal ones. 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_cistatic inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci unsigned retval = v; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* external resistors may scale vAUX into 0..vREF */ 5038c2ecf20Sopenharmony_ci retval *= ts->vref_mv; 5048c2ecf20Sopenharmony_ci retval = retval >> 12; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return retval; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci unsigned retval = vaux_adjust(ts, v); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* ads7846 has a resistor ladder to scale this signal down */ 5148c2ecf20Sopenharmony_ci if (ts->model == 7846) 5158c2ecf20Sopenharmony_ci retval *= 4; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return retval; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ciSHOW(in0_input, vaux, vaux_adjust) 5218c2ecf20Sopenharmony_ciSHOW(in1_input, vbatt, vbatt_adjust) 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr, 5248c2ecf20Sopenharmony_ci int index) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 5278c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (ts->model == 7843 && index < 2) /* in0, in1 */ 5308c2ecf20Sopenharmony_ci return 0; 5318c2ecf20Sopenharmony_ci if (ts->model == 7845 && index != 2) /* in0 */ 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return attr->mode; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic struct attribute *ads7846_attributes[] = { 5388c2ecf20Sopenharmony_ci &dev_attr_temp0.attr, /* 0 */ 5398c2ecf20Sopenharmony_ci &dev_attr_temp1.attr, /* 1 */ 5408c2ecf20Sopenharmony_ci &dev_attr_in0_input.attr, /* 2 */ 5418c2ecf20Sopenharmony_ci &dev_attr_in1_input.attr, /* 3 */ 5428c2ecf20Sopenharmony_ci NULL, 5438c2ecf20Sopenharmony_ci}; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic const struct attribute_group ads7846_attr_group = { 5468c2ecf20Sopenharmony_ci .attrs = ads7846_attributes, 5478c2ecf20Sopenharmony_ci .is_visible = ads7846_is_visible, 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_ci__ATTRIBUTE_GROUPS(ads7846_attr); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci /* hwmon sensors need a reference voltage */ 5548c2ecf20Sopenharmony_ci switch (ts->model) { 5558c2ecf20Sopenharmony_ci case 7846: 5568c2ecf20Sopenharmony_ci if (!ts->vref_mv) { 5578c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n"); 5588c2ecf20Sopenharmony_ci ts->vref_mv = 2500; 5598c2ecf20Sopenharmony_ci ts->use_internal = true; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case 7845: 5638c2ecf20Sopenharmony_ci case 7843: 5648c2ecf20Sopenharmony_ci if (!ts->vref_mv) { 5658c2ecf20Sopenharmony_ci dev_warn(&spi->dev, 5668c2ecf20Sopenharmony_ci "external vREF for ADS%d not specified\n", 5678c2ecf20Sopenharmony_ci ts->model); 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias, 5748c2ecf20Sopenharmony_ci ts, ads7846_attr_groups); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(ts->hwmon); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic void ads784x_hwmon_unregister(struct spi_device *spi, 5808c2ecf20Sopenharmony_ci struct ads7846 *ts) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci if (ts->hwmon) 5838c2ecf20Sopenharmony_ci hwmon_device_unregister(ts->hwmon); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci#else 5878c2ecf20Sopenharmony_cistatic inline int ads784x_hwmon_register(struct spi_device *spi, 5888c2ecf20Sopenharmony_ci struct ads7846 *ts) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic inline void ads784x_hwmon_unregister(struct spi_device *spi, 5948c2ecf20Sopenharmony_ci struct ads7846 *ts) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci#endif 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic ssize_t ads7846_pen_down_show(struct device *dev, 6008c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", ts->pendown); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic ssize_t ads7846_disable_show(struct device *dev, 6108c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", ts->disabled); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic ssize_t ads7846_disable_store(struct device *dev, 6188c2ecf20Sopenharmony_ci struct device_attribute *attr, 6198c2ecf20Sopenharmony_ci const char *buf, size_t count) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 6228c2ecf20Sopenharmony_ci unsigned int i; 6238c2ecf20Sopenharmony_ci int err; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci err = kstrtouint(buf, 10, &i); 6268c2ecf20Sopenharmony_ci if (err) 6278c2ecf20Sopenharmony_ci return err; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (i) 6308c2ecf20Sopenharmony_ci ads7846_disable(ts); 6318c2ecf20Sopenharmony_ci else 6328c2ecf20Sopenharmony_ci ads7846_enable(ts); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return count; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic struct attribute *ads784x_attributes[] = { 6408c2ecf20Sopenharmony_ci &dev_attr_pen_down.attr, 6418c2ecf20Sopenharmony_ci &dev_attr_disable.attr, 6428c2ecf20Sopenharmony_ci NULL, 6438c2ecf20Sopenharmony_ci}; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic const struct attribute_group ads784x_attr_group = { 6468c2ecf20Sopenharmony_ci .attrs = ads784x_attributes, 6478c2ecf20Sopenharmony_ci}; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/ 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void null_wait_for_sync(void) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int ads7846_debounce_filter(void *ads, int data_idx, int *val) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct ads7846 *ts = ads; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) { 6608c2ecf20Sopenharmony_ci /* Start over collecting consistent readings. */ 6618c2ecf20Sopenharmony_ci ts->read_rep = 0; 6628c2ecf20Sopenharmony_ci /* 6638c2ecf20Sopenharmony_ci * Repeat it, if this was the first read or the read 6648c2ecf20Sopenharmony_ci * wasn't consistent enough. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci if (ts->read_cnt < ts->debounce_max) { 6678c2ecf20Sopenharmony_ci ts->last_read = *val; 6688c2ecf20Sopenharmony_ci ts->read_cnt++; 6698c2ecf20Sopenharmony_ci return ADS7846_FILTER_REPEAT; 6708c2ecf20Sopenharmony_ci } else { 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * Maximum number of debouncing reached and still 6738c2ecf20Sopenharmony_ci * not enough number of consistent readings. Abort 6748c2ecf20Sopenharmony_ci * the whole sample, repeat it in the next sampling 6758c2ecf20Sopenharmony_ci * period. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci ts->read_cnt = 0; 6788c2ecf20Sopenharmony_ci return ADS7846_FILTER_IGNORE; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci if (++ts->read_rep > ts->debounce_rep) { 6828c2ecf20Sopenharmony_ci /* 6838c2ecf20Sopenharmony_ci * Got a good reading for this coordinate, 6848c2ecf20Sopenharmony_ci * go for the next one. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci ts->read_cnt = 0; 6878c2ecf20Sopenharmony_ci ts->read_rep = 0; 6888c2ecf20Sopenharmony_ci return ADS7846_FILTER_OK; 6898c2ecf20Sopenharmony_ci } else { 6908c2ecf20Sopenharmony_ci /* Read more values that are consistent. */ 6918c2ecf20Sopenharmony_ci ts->read_cnt++; 6928c2ecf20Sopenharmony_ci return ADS7846_FILTER_REPEAT; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic int ads7846_no_filter(void *ads, int data_idx, int *val) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci return ADS7846_FILTER_OK; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int ads7846_get_value(struct ads7846_buf *buf) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci int value; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci value = be16_to_cpup(&buf->data); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* enforce ADC output is 12 bits width */ 7098c2ecf20Sopenharmony_ci return (value >> 3) & 0xfff; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx, 7138c2ecf20Sopenharmony_ci u16 val) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct ads7846_packet *packet = ts->packet; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci switch (cmd_idx) { 7188c2ecf20Sopenharmony_ci case ADS7846_Y: 7198c2ecf20Sopenharmony_ci packet->y = val; 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci case ADS7846_X: 7228c2ecf20Sopenharmony_ci packet->x = val; 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci case ADS7846_Z1: 7258c2ecf20Sopenharmony_ci packet->z1 = val; 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci case ADS7846_Z2: 7288c2ecf20Sopenharmony_ci packet->z2 = val; 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci default: 7318c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci switch (cmd_idx) { 7388c2ecf20Sopenharmony_ci case ADS7846_Y: 7398c2ecf20Sopenharmony_ci return READ_Y(vref); 7408c2ecf20Sopenharmony_ci case ADS7846_X: 7418c2ecf20Sopenharmony_ci return READ_X(vref); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* 7846 specific commands */ 7448c2ecf20Sopenharmony_ci case ADS7846_Z1: 7458c2ecf20Sopenharmony_ci return READ_Z1(vref); 7468c2ecf20Sopenharmony_ci case ADS7846_Z2: 7478c2ecf20Sopenharmony_ci return READ_Z2(vref); 7488c2ecf20Sopenharmony_ci case ADS7846_PWDOWN: 7498c2ecf20Sopenharmony_ci return PWRDOWN; 7508c2ecf20Sopenharmony_ci default: 7518c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci return 0; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci switch (cmd_idx) { 7608c2ecf20Sopenharmony_ci case ADS7846_X: 7618c2ecf20Sopenharmony_ci case ADS7846_Y: 7628c2ecf20Sopenharmony_ci case ADS7846_Z1: 7638c2ecf20Sopenharmony_ci case ADS7846_Z2: 7648c2ecf20Sopenharmony_ci return true; 7658c2ecf20Sopenharmony_ci case ADS7846_PWDOWN: 7668c2ecf20Sopenharmony_ci return false; 7678c2ecf20Sopenharmony_ci default: 7688c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return false; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int ads7846_filter(struct ads7846 *ts) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci struct ads7846_packet *packet = ts->packet; 7778c2ecf20Sopenharmony_ci int action; 7788c2ecf20Sopenharmony_ci int val; 7798c2ecf20Sopenharmony_ci unsigned int cmd_idx, b; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci packet->ignore = false; 7828c2ecf20Sopenharmony_ci for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) { 7838c2ecf20Sopenharmony_ci struct ads7846_buf_layout *l = &packet->l[cmd_idx]; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci packet->last_cmd_idx = cmd_idx; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci for (b = l->skip; b < l->count; b++) { 7888c2ecf20Sopenharmony_ci val = ads7846_get_value(&packet->rx[l->offset + b]); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci action = ts->filter(ts->filter_data, cmd_idx, &val); 7918c2ecf20Sopenharmony_ci if (action == ADS7846_FILTER_REPEAT) { 7928c2ecf20Sopenharmony_ci if (b == l->count - 1) 7938c2ecf20Sopenharmony_ci return -EAGAIN; 7948c2ecf20Sopenharmony_ci } else if (action == ADS7846_FILTER_OK) { 7958c2ecf20Sopenharmony_ci ads7846_set_cmd_val(ts, cmd_idx, val); 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci } else { 7988c2ecf20Sopenharmony_ci packet->ignore = true; 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic void ads7846_read_state(struct ads7846 *ts) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct ads7846_packet *packet = ts->packet; 8108c2ecf20Sopenharmony_ci struct spi_message *m; 8118c2ecf20Sopenharmony_ci int msg_idx = 0; 8128c2ecf20Sopenharmony_ci int error; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci packet->last_cmd_idx = 0; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci while (true) { 8178c2ecf20Sopenharmony_ci ts->wait_for_sync(); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci m = &ts->msg[msg_idx]; 8208c2ecf20Sopenharmony_ci error = spi_sync(ts->spi, m); 8218c2ecf20Sopenharmony_ci if (error) { 8228c2ecf20Sopenharmony_ci dev_err(&ts->spi->dev, "spi_sync --> %d\n", error); 8238c2ecf20Sopenharmony_ci packet->ignore = true; 8248c2ecf20Sopenharmony_ci return; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci error = ads7846_filter(ts); 8288c2ecf20Sopenharmony_ci if (error) 8298c2ecf20Sopenharmony_ci continue; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic void ads7846_report_state(struct ads7846 *ts) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct ads7846_packet *packet = ts->packet; 8388c2ecf20Sopenharmony_ci unsigned int Rt; 8398c2ecf20Sopenharmony_ci u16 x, y, z1, z2; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci x = packet->x; 8428c2ecf20Sopenharmony_ci y = packet->y; 8438c2ecf20Sopenharmony_ci if (ts->model == 7845) { 8448c2ecf20Sopenharmony_ci z1 = 0; 8458c2ecf20Sopenharmony_ci z2 = 0; 8468c2ecf20Sopenharmony_ci } else { 8478c2ecf20Sopenharmony_ci z1 = packet->z1; 8488c2ecf20Sopenharmony_ci z2 = packet->z2; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* range filtering */ 8528c2ecf20Sopenharmony_ci if (x == MAX_12BIT) 8538c2ecf20Sopenharmony_ci x = 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (ts->model == 7843 || ts->model == 7845) { 8568c2ecf20Sopenharmony_ci Rt = ts->pressure_max / 2; 8578c2ecf20Sopenharmony_ci } else if (likely(x && z1)) { 8588c2ecf20Sopenharmony_ci /* compute touch pressure resistance using equation #2 */ 8598c2ecf20Sopenharmony_ci Rt = z2; 8608c2ecf20Sopenharmony_ci Rt -= z1; 8618c2ecf20Sopenharmony_ci Rt *= ts->x_plate_ohms; 8628c2ecf20Sopenharmony_ci Rt = DIV_ROUND_CLOSEST(Rt, 16); 8638c2ecf20Sopenharmony_ci Rt *= x; 8648c2ecf20Sopenharmony_ci Rt /= z1; 8658c2ecf20Sopenharmony_ci Rt = DIV_ROUND_CLOSEST(Rt, 256); 8668c2ecf20Sopenharmony_ci } else { 8678c2ecf20Sopenharmony_ci Rt = 0; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* 8718c2ecf20Sopenharmony_ci * Sample found inconsistent by debouncing or pressure is beyond 8728c2ecf20Sopenharmony_ci * the maximum. Don't report it to user space, repeat at least 8738c2ecf20Sopenharmony_ci * once more the measurement 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_ci if (packet->ignore || Rt > ts->pressure_max) { 8768c2ecf20Sopenharmony_ci dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n", 8778c2ecf20Sopenharmony_ci packet->ignore, Rt); 8788c2ecf20Sopenharmony_ci return; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * Maybe check the pendown state before reporting. This discards 8838c2ecf20Sopenharmony_ci * false readings when the pen is lifted. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci if (ts->penirq_recheck_delay_usecs) { 8868c2ecf20Sopenharmony_ci udelay(ts->penirq_recheck_delay_usecs); 8878c2ecf20Sopenharmony_ci if (!get_pendown_state(ts)) 8888c2ecf20Sopenharmony_ci Rt = 0; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* 8928c2ecf20Sopenharmony_ci * NOTE: We can't rely on the pressure to determine the pen down 8938c2ecf20Sopenharmony_ci * state, even this controller has a pressure sensor. The pressure 8948c2ecf20Sopenharmony_ci * value can fluctuate for quite a while after lifting the pen and 8958c2ecf20Sopenharmony_ci * in some cases may not even settle at the expected value. 8968c2ecf20Sopenharmony_ci * 8978c2ecf20Sopenharmony_ci * The only safe way to check for the pen up condition is in the 8988c2ecf20Sopenharmony_ci * timer by reading the pen signal state (it's a GPIO _and_ IRQ). 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci if (Rt) { 9018c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (!ts->pendown) { 9048c2ecf20Sopenharmony_ci input_report_key(input, BTN_TOUCH, 1); 9058c2ecf20Sopenharmony_ci ts->pendown = true; 9068c2ecf20Sopenharmony_ci dev_vdbg(&ts->spi->dev, "DOWN\n"); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci touchscreen_report_pos(input, &ts->core_prop, x, y, false); 9108c2ecf20Sopenharmony_ci input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci input_sync(input); 9138c2ecf20Sopenharmony_ci dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic irqreturn_t ads7846_hard_irq(int irq, void *handle) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct ads7846 *ts = handle; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci return get_pendown_state(ts) ? IRQ_WAKE_THREAD : IRQ_HANDLED; 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic irqreturn_t ads7846_irq(int irq, void *handle) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct ads7846 *ts = handle; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* Start with a small delay before checking pendown state */ 9308c2ecf20Sopenharmony_ci msleep(TS_POLL_DELAY); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci while (!ts->stopped && get_pendown_state(ts)) { 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* pen is down, continue with the measurement */ 9358c2ecf20Sopenharmony_ci ads7846_read_state(ts); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (!ts->stopped) 9388c2ecf20Sopenharmony_ci ads7846_report_state(ts); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci wait_event_timeout(ts->wait, ts->stopped, 9418c2ecf20Sopenharmony_ci msecs_to_jiffies(TS_POLL_PERIOD)); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (ts->pendown && !ts->stopped) 9458c2ecf20Sopenharmony_ci ads7846_report_pen_up(ts); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int __maybe_unused ads7846_suspend(struct device *dev) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci mutex_lock(&ts->lock); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!ts->suspended) { 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (!ts->disabled) 9598c2ecf20Sopenharmony_ci __ads7846_disable(ts); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (device_may_wakeup(&ts->spi->dev)) 9628c2ecf20Sopenharmony_ci enable_irq_wake(ts->spi->irq); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci ts->suspended = true; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci mutex_unlock(&ts->lock); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci return 0; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic int __maybe_unused ads7846_resume(struct device *dev) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct ads7846 *ts = dev_get_drvdata(dev); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci mutex_lock(&ts->lock); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (ts->suspended) { 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci ts->suspended = false; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (device_may_wakeup(&ts->spi->dev)) 9838c2ecf20Sopenharmony_ci disable_irq_wake(ts->spi->irq); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (!ts->disabled) 9868c2ecf20Sopenharmony_ci __ads7846_enable(ts); 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci mutex_unlock(&ts->lock); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci return 0; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic int ads7846_setup_pendown(struct spi_device *spi, 9978c2ecf20Sopenharmony_ci struct ads7846 *ts, 9988c2ecf20Sopenharmony_ci const struct ads7846_platform_data *pdata) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci int err; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* 10038c2ecf20Sopenharmony_ci * REVISIT when the irq can be triggered active-low, or if for some 10048c2ecf20Sopenharmony_ci * reason the touchscreen isn't hooked up, we don't need to access 10058c2ecf20Sopenharmony_ci * the pendown state. 10068c2ecf20Sopenharmony_ci */ 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (pdata->get_pendown_state) { 10098c2ecf20Sopenharmony_ci ts->get_pendown_state = pdata->get_pendown_state; 10108c2ecf20Sopenharmony_ci } else if (gpio_is_valid(pdata->gpio_pendown)) { 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN, 10138c2ecf20Sopenharmony_ci "ads7846_pendown"); 10148c2ecf20Sopenharmony_ci if (err) { 10158c2ecf20Sopenharmony_ci dev_err(&spi->dev, 10168c2ecf20Sopenharmony_ci "failed to request/setup pendown GPIO%d: %d\n", 10178c2ecf20Sopenharmony_ci pdata->gpio_pendown, err); 10188c2ecf20Sopenharmony_ci return err; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci ts->gpio_pendown = pdata->gpio_pendown; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (pdata->gpio_pendown_debounce) 10248c2ecf20Sopenharmony_ci gpio_set_debounce(pdata->gpio_pendown, 10258c2ecf20Sopenharmony_ci pdata->gpio_pendown_debounce); 10268c2ecf20Sopenharmony_ci } else { 10278c2ecf20Sopenharmony_ci dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); 10288c2ecf20Sopenharmony_ci return -EINVAL; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci/* 10358c2ecf20Sopenharmony_ci * Set up the transfers to read touchscreen state; this assumes we 10368c2ecf20Sopenharmony_ci * use formula #2 for pressure, not #3. 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_cistatic int ads7846_setup_spi_msg(struct ads7846 *ts, 10398c2ecf20Sopenharmony_ci const struct ads7846_platform_data *pdata) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct spi_message *m = &ts->msg[0]; 10428c2ecf20Sopenharmony_ci struct spi_transfer *x = ts->xfer; 10438c2ecf20Sopenharmony_ci struct ads7846_packet *packet = ts->packet; 10448c2ecf20Sopenharmony_ci int vref = pdata->keep_vref_on; 10458c2ecf20Sopenharmony_ci unsigned int count, offset = 0; 10468c2ecf20Sopenharmony_ci unsigned int cmd_idx, b; 10478c2ecf20Sopenharmony_ci unsigned long time; 10488c2ecf20Sopenharmony_ci size_t size = 0; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* time per bit */ 10518c2ecf20Sopenharmony_ci time = NSEC_PER_SEC / ts->spi->max_speed_hz; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci count = pdata->settle_delay_usecs * NSEC_PER_USEC / time; 10548c2ecf20Sopenharmony_ci packet->count_skip = DIV_ROUND_UP(count, 24); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (ts->debounce_max && ts->debounce_rep) 10578c2ecf20Sopenharmony_ci /* ads7846_debounce_filter() is making ts->debounce_rep + 2 10588c2ecf20Sopenharmony_ci * reads. So we need to get all samples for normal case. */ 10598c2ecf20Sopenharmony_ci packet->count = ts->debounce_rep + 2; 10608c2ecf20Sopenharmony_ci else 10618c2ecf20Sopenharmony_ci packet->count = 1; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (ts->model == 7846) 10648c2ecf20Sopenharmony_ci packet->cmds = 5; /* x, y, z1, z2, pwdown */ 10658c2ecf20Sopenharmony_ci else 10668c2ecf20Sopenharmony_ci packet->cmds = 3; /* x, y, pwdown */ 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { 10698c2ecf20Sopenharmony_ci struct ads7846_buf_layout *l = &packet->l[cmd_idx]; 10708c2ecf20Sopenharmony_ci unsigned int max_count; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (cmd_idx == packet->cmds - 1) 10738c2ecf20Sopenharmony_ci cmd_idx = ADS7846_PWDOWN; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (ads7846_cmd_need_settle(cmd_idx)) 10768c2ecf20Sopenharmony_ci max_count = packet->count + packet->count_skip; 10778c2ecf20Sopenharmony_ci else 10788c2ecf20Sopenharmony_ci max_count = packet->count; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci l->offset = offset; 10818c2ecf20Sopenharmony_ci offset += max_count; 10828c2ecf20Sopenharmony_ci l->count = max_count; 10838c2ecf20Sopenharmony_ci l->skip = packet->count_skip; 10848c2ecf20Sopenharmony_ci size += sizeof(*packet->tx) * max_count; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL); 10888c2ecf20Sopenharmony_ci if (!packet->tx) 10898c2ecf20Sopenharmony_ci return -ENOMEM; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL); 10928c2ecf20Sopenharmony_ci if (!packet->rx) 10938c2ecf20Sopenharmony_ci return -ENOMEM; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (ts->model == 7873) { 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * The AD7873 is almost identical to the ADS7846 10988c2ecf20Sopenharmony_ci * keep VREF off during differential/ratiometric 10998c2ecf20Sopenharmony_ci * conversion modes. 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_ci ts->model = 7846; 11028c2ecf20Sopenharmony_ci vref = 0; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci ts->msg_count = 1; 11068c2ecf20Sopenharmony_ci spi_message_init(m); 11078c2ecf20Sopenharmony_ci m->context = ts; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { 11108c2ecf20Sopenharmony_ci struct ads7846_buf_layout *l = &packet->l[cmd_idx]; 11118c2ecf20Sopenharmony_ci u8 cmd; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (cmd_idx == packet->cmds - 1) 11148c2ecf20Sopenharmony_ci cmd_idx = ADS7846_PWDOWN; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci cmd = ads7846_get_cmd(cmd_idx, vref); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci for (b = 0; b < l->count; b++) 11198c2ecf20Sopenharmony_ci packet->tx[l->offset + b].cmd = cmd; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci x->tx_buf = packet->tx; 11238c2ecf20Sopenharmony_ci x->rx_buf = packet->rx; 11248c2ecf20Sopenharmony_ci x->len = size; 11258c2ecf20Sopenharmony_ci spi_message_add_tail(x, m); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return 0; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 11318c2ecf20Sopenharmony_cistatic const struct of_device_id ads7846_dt_ids[] = { 11328c2ecf20Sopenharmony_ci { .compatible = "ti,tsc2046", .data = (void *) 7846 }, 11338c2ecf20Sopenharmony_ci { .compatible = "ti,ads7843", .data = (void *) 7843 }, 11348c2ecf20Sopenharmony_ci { .compatible = "ti,ads7845", .data = (void *) 7845 }, 11358c2ecf20Sopenharmony_ci { .compatible = "ti,ads7846", .data = (void *) 7846 }, 11368c2ecf20Sopenharmony_ci { .compatible = "ti,ads7873", .data = (void *) 7873 }, 11378c2ecf20Sopenharmony_ci { } 11388c2ecf20Sopenharmony_ci}; 11398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ads7846_dt_ids); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci struct ads7846_platform_data *pdata; 11448c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 11458c2ecf20Sopenharmony_ci const struct of_device_id *match; 11468c2ecf20Sopenharmony_ci u32 value; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (!node) { 11498c2ecf20Sopenharmony_ci dev_err(dev, "Device does not have associated DT data\n"); 11508c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci match = of_match_device(ads7846_dt_ids, dev); 11548c2ecf20Sopenharmony_ci if (!match) { 11558c2ecf20Sopenharmony_ci dev_err(dev, "Unknown device model\n"); 11568c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 11608c2ecf20Sopenharmony_ci if (!pdata) 11618c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci pdata->model = (unsigned long)match->data; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,vref-delay-usecs", 11668c2ecf20Sopenharmony_ci &pdata->vref_delay_usecs); 11678c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,vref-mv", &pdata->vref_mv); 11688c2ecf20Sopenharmony_ci pdata->keep_vref_on = of_property_read_bool(node, "ti,keep-vref-on"); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci pdata->swap_xy = of_property_read_bool(node, "ti,swap-xy"); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,settle-delay-usec", 11738c2ecf20Sopenharmony_ci &pdata->settle_delay_usecs); 11748c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,penirq-recheck-delay-usecs", 11758c2ecf20Sopenharmony_ci &pdata->penirq_recheck_delay_usecs); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,x-plate-ohms", &pdata->x_plate_ohms); 11788c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,y-plate-ohms", &pdata->y_plate_ohms); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,x-min", &pdata->x_min); 11818c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,y-min", &pdata->y_min); 11828c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,x-max", &pdata->x_max); 11838c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,y-max", &pdata->y_max); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* 11868c2ecf20Sopenharmony_ci * touchscreen-max-pressure gets parsed during 11878c2ecf20Sopenharmony_ci * touchscreen_parse_properties() 11888c2ecf20Sopenharmony_ci */ 11898c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min); 11908c2ecf20Sopenharmony_ci if (!of_property_read_u32(node, "touchscreen-min-pressure", &value)) 11918c2ecf20Sopenharmony_ci pdata->pressure_min = (u16) value; 11928c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max); 11958c2ecf20Sopenharmony_ci if (!of_property_read_u32(node, "touchscreen-average-samples", &value)) 11968c2ecf20Sopenharmony_ci pdata->debounce_max = (u16) value; 11978c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol); 11988c2ecf20Sopenharmony_ci of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci of_property_read_u32(node, "ti,pendown-gpio-debounce", 12018c2ecf20Sopenharmony_ci &pdata->gpio_pendown_debounce); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci pdata->wakeup = of_property_read_bool(node, "wakeup-source") || 12048c2ecf20Sopenharmony_ci of_property_read_bool(node, "linux,wakeup"); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return pdata; 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci#else 12118c2ecf20Sopenharmony_cistatic const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci dev_err(dev, "no platform data defined\n"); 12148c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci#endif 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistatic int ads7846_probe(struct spi_device *spi) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci const struct ads7846_platform_data *pdata; 12218c2ecf20Sopenharmony_ci struct ads7846 *ts; 12228c2ecf20Sopenharmony_ci struct ads7846_packet *packet; 12238c2ecf20Sopenharmony_ci struct input_dev *input_dev; 12248c2ecf20Sopenharmony_ci unsigned long irq_flags; 12258c2ecf20Sopenharmony_ci int err; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (!spi->irq) { 12288c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "no IRQ?\n"); 12298c2ecf20Sopenharmony_ci return -EINVAL; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci /* don't exceed max specified sample rate */ 12338c2ecf20Sopenharmony_ci if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) { 12348c2ecf20Sopenharmony_ci dev_err(&spi->dev, "f(sample) %d KHz?\n", 12358c2ecf20Sopenharmony_ci (spi->max_speed_hz/SAMPLE_BITS)/1000); 12368c2ecf20Sopenharmony_ci return -EINVAL; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* 12408c2ecf20Sopenharmony_ci * We'd set TX word size 8 bits and RX word size to 13 bits ... except 12418c2ecf20Sopenharmony_ci * that even if the hardware can do that, the SPI controller driver 12428c2ecf20Sopenharmony_ci * may not. So we stick to very-portable 8 bit words, both RX and TX. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_ci spi->bits_per_word = 8; 12458c2ecf20Sopenharmony_ci spi->mode = SPI_MODE_0; 12468c2ecf20Sopenharmony_ci err = spi_setup(spi); 12478c2ecf20Sopenharmony_ci if (err < 0) 12488c2ecf20Sopenharmony_ci return err; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); 12518c2ecf20Sopenharmony_ci packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL); 12528c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 12538c2ecf20Sopenharmony_ci if (!ts || !packet || !input_dev) { 12548c2ecf20Sopenharmony_ci err = -ENOMEM; 12558c2ecf20Sopenharmony_ci goto err_free_mem; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci spi_set_drvdata(spi, ts); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci ts->packet = packet; 12618c2ecf20Sopenharmony_ci ts->spi = spi; 12628c2ecf20Sopenharmony_ci ts->input = input_dev; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci mutex_init(&ts->lock); 12658c2ecf20Sopenharmony_ci init_waitqueue_head(&ts->wait); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&spi->dev); 12688c2ecf20Sopenharmony_ci if (!pdata) { 12698c2ecf20Sopenharmony_ci pdata = ads7846_probe_dt(&spi->dev); 12708c2ecf20Sopenharmony_ci if (IS_ERR(pdata)) { 12718c2ecf20Sopenharmony_ci err = PTR_ERR(pdata); 12728c2ecf20Sopenharmony_ci goto err_free_mem; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci ts->model = pdata->model ? : 7846; 12778c2ecf20Sopenharmony_ci ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; 12788c2ecf20Sopenharmony_ci ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; 12798c2ecf20Sopenharmony_ci ts->vref_mv = pdata->vref_mv; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (pdata->filter != NULL) { 12828c2ecf20Sopenharmony_ci if (pdata->filter_init != NULL) { 12838c2ecf20Sopenharmony_ci err = pdata->filter_init(pdata, &ts->filter_data); 12848c2ecf20Sopenharmony_ci if (err < 0) 12858c2ecf20Sopenharmony_ci goto err_free_mem; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci ts->filter = pdata->filter; 12888c2ecf20Sopenharmony_ci ts->filter_cleanup = pdata->filter_cleanup; 12898c2ecf20Sopenharmony_ci } else if (pdata->debounce_max) { 12908c2ecf20Sopenharmony_ci ts->debounce_max = pdata->debounce_max; 12918c2ecf20Sopenharmony_ci if (ts->debounce_max < 2) 12928c2ecf20Sopenharmony_ci ts->debounce_max = 2; 12938c2ecf20Sopenharmony_ci ts->debounce_tol = pdata->debounce_tol; 12948c2ecf20Sopenharmony_ci ts->debounce_rep = pdata->debounce_rep; 12958c2ecf20Sopenharmony_ci ts->filter = ads7846_debounce_filter; 12968c2ecf20Sopenharmony_ci ts->filter_data = ts; 12978c2ecf20Sopenharmony_ci } else { 12988c2ecf20Sopenharmony_ci ts->filter = ads7846_no_filter; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci err = ads7846_setup_pendown(spi, ts, pdata); 13028c2ecf20Sopenharmony_ci if (err) 13038c2ecf20Sopenharmony_ci goto err_cleanup_filter; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (pdata->penirq_recheck_delay_usecs) 13068c2ecf20Sopenharmony_ci ts->penirq_recheck_delay_usecs = 13078c2ecf20Sopenharmony_ci pdata->penirq_recheck_delay_usecs; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); 13128c2ecf20Sopenharmony_ci snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci input_dev->name = ts->name; 13158c2ecf20Sopenharmony_ci input_dev->phys = ts->phys; 13168c2ecf20Sopenharmony_ci input_dev->dev.parent = &spi->dev; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 13198c2ecf20Sopenharmony_ci input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 13208c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, 13218c2ecf20Sopenharmony_ci pdata->x_min ? : 0, 13228c2ecf20Sopenharmony_ci pdata->x_max ? : MAX_12BIT, 13238c2ecf20Sopenharmony_ci 0, 0); 13248c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, 13258c2ecf20Sopenharmony_ci pdata->y_min ? : 0, 13268c2ecf20Sopenharmony_ci pdata->y_max ? : MAX_12BIT, 13278c2ecf20Sopenharmony_ci 0, 0); 13288c2ecf20Sopenharmony_ci if (ts->model != 7845) 13298c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_PRESSURE, 13308c2ecf20Sopenharmony_ci pdata->pressure_min, pdata->pressure_max, 0, 0); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* 13338c2ecf20Sopenharmony_ci * Parse common framework properties. Must be done here to ensure the 13348c2ecf20Sopenharmony_ci * correct behaviour in case of using the legacy vendor bindings. The 13358c2ecf20Sopenharmony_ci * general binding value overrides the vendor specific one. 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_ci touchscreen_parse_properties(ts->input, false, &ts->core_prop); 13388c2ecf20Sopenharmony_ci ts->pressure_max = input_abs_get_max(input_dev, ABS_PRESSURE) ? : ~0; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* 13418c2ecf20Sopenharmony_ci * Check if legacy ti,swap-xy binding is used instead of 13428c2ecf20Sopenharmony_ci * touchscreen-swapped-x-y 13438c2ecf20Sopenharmony_ci */ 13448c2ecf20Sopenharmony_ci if (!ts->core_prop.swap_x_y && pdata->swap_xy) { 13458c2ecf20Sopenharmony_ci swap(input_dev->absinfo[ABS_X], input_dev->absinfo[ABS_Y]); 13468c2ecf20Sopenharmony_ci ts->core_prop.swap_x_y = true; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci ads7846_setup_spi_msg(ts, pdata); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci ts->reg = regulator_get(&spi->dev, "vcc"); 13528c2ecf20Sopenharmony_ci if (IS_ERR(ts->reg)) { 13538c2ecf20Sopenharmony_ci err = PTR_ERR(ts->reg); 13548c2ecf20Sopenharmony_ci dev_err(&spi->dev, "unable to get regulator: %d\n", err); 13558c2ecf20Sopenharmony_ci goto err_free_gpio; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci err = regulator_enable(ts->reg); 13598c2ecf20Sopenharmony_ci if (err) { 13608c2ecf20Sopenharmony_ci dev_err(&spi->dev, "unable to enable regulator: %d\n", err); 13618c2ecf20Sopenharmony_ci goto err_put_regulator; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING; 13658c2ecf20Sopenharmony_ci irq_flags |= IRQF_ONESHOT; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq, 13688c2ecf20Sopenharmony_ci irq_flags, spi->dev.driver->name, ts); 13698c2ecf20Sopenharmony_ci if (err && !pdata->irq_flags) { 13708c2ecf20Sopenharmony_ci dev_info(&spi->dev, 13718c2ecf20Sopenharmony_ci "trying pin change workaround on irq %d\n", spi->irq); 13728c2ecf20Sopenharmony_ci irq_flags |= IRQF_TRIGGER_RISING; 13738c2ecf20Sopenharmony_ci err = request_threaded_irq(spi->irq, 13748c2ecf20Sopenharmony_ci ads7846_hard_irq, ads7846_irq, 13758c2ecf20Sopenharmony_ci irq_flags, spi->dev.driver->name, ts); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (err) { 13798c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); 13808c2ecf20Sopenharmony_ci goto err_disable_regulator; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci err = ads784x_hwmon_register(spi, ts); 13848c2ecf20Sopenharmony_ci if (err) 13858c2ecf20Sopenharmony_ci goto err_free_irq; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* 13908c2ecf20Sopenharmony_ci * Take a first sample, leaving nPENIRQ active and vREF off; avoid 13918c2ecf20Sopenharmony_ci * the touchscreen, in case it's not connected. 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci if (ts->model == 7845) 13948c2ecf20Sopenharmony_ci ads7845_read12_ser(&spi->dev, PWRDOWN); 13958c2ecf20Sopenharmony_ci else 13968c2ecf20Sopenharmony_ci (void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux)); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); 13998c2ecf20Sopenharmony_ci if (err) 14008c2ecf20Sopenharmony_ci goto err_remove_hwmon; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci err = input_register_device(input_dev); 14038c2ecf20Sopenharmony_ci if (err) 14048c2ecf20Sopenharmony_ci goto err_remove_attr_group; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci device_init_wakeup(&spi->dev, pdata->wakeup); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* 14098c2ecf20Sopenharmony_ci * If device does not carry platform data we must have allocated it 14108c2ecf20Sopenharmony_ci * when parsing DT data. 14118c2ecf20Sopenharmony_ci */ 14128c2ecf20Sopenharmony_ci if (!dev_get_platdata(&spi->dev)) 14138c2ecf20Sopenharmony_ci devm_kfree(&spi->dev, (void *)pdata); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci return 0; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci err_remove_attr_group: 14188c2ecf20Sopenharmony_ci sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); 14198c2ecf20Sopenharmony_ci err_remove_hwmon: 14208c2ecf20Sopenharmony_ci ads784x_hwmon_unregister(spi, ts); 14218c2ecf20Sopenharmony_ci err_free_irq: 14228c2ecf20Sopenharmony_ci free_irq(spi->irq, ts); 14238c2ecf20Sopenharmony_ci err_disable_regulator: 14248c2ecf20Sopenharmony_ci regulator_disable(ts->reg); 14258c2ecf20Sopenharmony_ci err_put_regulator: 14268c2ecf20Sopenharmony_ci regulator_put(ts->reg); 14278c2ecf20Sopenharmony_ci err_free_gpio: 14288c2ecf20Sopenharmony_ci if (!ts->get_pendown_state) 14298c2ecf20Sopenharmony_ci gpio_free(ts->gpio_pendown); 14308c2ecf20Sopenharmony_ci err_cleanup_filter: 14318c2ecf20Sopenharmony_ci if (ts->filter_cleanup) 14328c2ecf20Sopenharmony_ci ts->filter_cleanup(ts->filter_data); 14338c2ecf20Sopenharmony_ci err_free_mem: 14348c2ecf20Sopenharmony_ci input_free_device(input_dev); 14358c2ecf20Sopenharmony_ci kfree(packet); 14368c2ecf20Sopenharmony_ci kfree(ts); 14378c2ecf20Sopenharmony_ci return err; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic int ads7846_remove(struct spi_device *spi) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct ads7846 *ts = spi_get_drvdata(spi); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci ads7846_disable(ts); 14478c2ecf20Sopenharmony_ci free_irq(ts->spi->irq, ts); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci input_unregister_device(ts->input); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci ads784x_hwmon_unregister(spi, ts); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci regulator_put(ts->reg); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if (!ts->get_pendown_state) { 14568c2ecf20Sopenharmony_ci /* 14578c2ecf20Sopenharmony_ci * If we are not using specialized pendown method we must 14588c2ecf20Sopenharmony_ci * have been relying on gpio we set up ourselves. 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_ci gpio_free(ts->gpio_pendown); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (ts->filter_cleanup) 14648c2ecf20Sopenharmony_ci ts->filter_cleanup(ts->filter_data); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci kfree(ts->packet); 14678c2ecf20Sopenharmony_ci kfree(ts); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "unregistered touchscreen\n"); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci return 0; 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic struct spi_driver ads7846_driver = { 14758c2ecf20Sopenharmony_ci .driver = { 14768c2ecf20Sopenharmony_ci .name = "ads7846", 14778c2ecf20Sopenharmony_ci .pm = &ads7846_pm, 14788c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ads7846_dt_ids), 14798c2ecf20Sopenharmony_ci }, 14808c2ecf20Sopenharmony_ci .probe = ads7846_probe, 14818c2ecf20Sopenharmony_ci .remove = ads7846_remove, 14828c2ecf20Sopenharmony_ci}; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cimodule_spi_driver(ads7846_driver); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ADS7846 TouchScreen Driver"); 14878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 14888c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:ads7846"); 1489