18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC. 68c2ecf20Sopenharmony_ci * Author: Liam Girdwood <lrg@slimlogic.co.uk> 78c2ecf20Sopenharmony_ci * Parts Copyright : Ian Molton <spyro@f2s.com> 88c2ecf20Sopenharmony_ci * Andrew Zabolotny <zap@homelink.ru> 98c2ecf20Sopenharmony_ci * Russell King <rmk@arm.linux.org.uk> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/input.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/bitops.h> 188c2ecf20Sopenharmony_ci#include <linux/wm97xx.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define TS_NAME "wm97xx" 218c2ecf20Sopenharmony_ci#define WM9713_VERSION "1.00" 228c2ecf20Sopenharmony_ci#define DEFAULT_PRESSURE 0xb0c0 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Module parameters 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Set internal pull up for pen detect. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive) 328c2ecf20Sopenharmony_ci * i.e. pull up resistance = 64k Ohms / rpu. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Adjust this value if you are having problems with pen detect not 358c2ecf20Sopenharmony_ci * detecting any down event. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic int rpu = 8; 388c2ecf20Sopenharmony_cimodule_param(rpu, int, 0); 398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rpu, "Set internal pull up resistor for pen detect."); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Set current used for pressure measurement. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Set pil = 2 to use 400uA 458c2ecf20Sopenharmony_ci * pil = 1 to use 200uA and 468c2ecf20Sopenharmony_ci * pil = 0 to disable pressure measurement. 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * This is used to increase the range of values returned by the adc 498c2ecf20Sopenharmony_ci * when measureing touchpanel pressure. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic int pil; 528c2ecf20Sopenharmony_cimodule_param(pil, int, 0); 538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pil, "Set current used for pressure measurement."); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Set threshold for pressure measurement. 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * Pen down pressure below threshold is ignored. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_cistatic int pressure = DEFAULT_PRESSURE & 0xfff; 618c2ecf20Sopenharmony_cimodule_param(pressure, int, 0); 628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pressure, "Set threshold for pressure measurement."); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * Set adc sample delay. 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * For accurate touchpanel measurements, some settling time may be 688c2ecf20Sopenharmony_ci * required between the switch matrix applying a voltage across the 698c2ecf20Sopenharmony_ci * touchpanel plate and the ADC sampling the signal. 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * This delay can be set by setting delay = n, where n is the array 728c2ecf20Sopenharmony_ci * position of the delay in the array delay_table below. 738c2ecf20Sopenharmony_ci * Long delays > 1ms are supported for completeness, but are not 748c2ecf20Sopenharmony_ci * recommended. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic int delay = 4; 778c2ecf20Sopenharmony_cimodule_param(delay, int, 0); 788c2ecf20Sopenharmony_ciMODULE_PARM_DESC(delay, "Set adc sample delay."); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Set five_wire = 1 to use a 5 wire touchscreen. 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * NOTE: Five wire mode does not allow for readback of pressure. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic int five_wire; 868c2ecf20Sopenharmony_cimodule_param(five_wire, int, 0); 878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen."); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Set adc mask function. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * Sources of glitch noise, such as signals driving an LCD display, may feed 938c2ecf20Sopenharmony_ci * through to the touch screen plates and affect measurement accuracy. In 948c2ecf20Sopenharmony_ci * order to minimise this, a signal may be applied to the MASK pin to delay or 958c2ecf20Sopenharmony_ci * synchronise the sampling. 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * 0 = No delay or sync 988c2ecf20Sopenharmony_ci * 1 = High on pin stops conversions 998c2ecf20Sopenharmony_ci * 2 = Edge triggered, edge on pin delays conversion by delay param (above) 1008c2ecf20Sopenharmony_ci * 3 = Edge triggered, edge on pin starts conversion after delay param 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic int mask; 1038c2ecf20Sopenharmony_cimodule_param(mask, int, 0); 1048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mask, "Set adc mask function."); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * Coordinate Polling Enable. 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together 1108c2ecf20Sopenharmony_ci * for every poll. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_cistatic int coord; 1138c2ecf20Sopenharmony_cimodule_param(coord, int, 0); 1148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(coord, "Polling coordinate mode"); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * ADC sample delay times in uS 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic const int delay_table[] = { 1208c2ecf20Sopenharmony_ci 21, /* 1 AC97 Link frames */ 1218c2ecf20Sopenharmony_ci 42, /* 2 */ 1228c2ecf20Sopenharmony_ci 84, /* 4 */ 1238c2ecf20Sopenharmony_ci 167, /* 8 */ 1248c2ecf20Sopenharmony_ci 333, /* 16 */ 1258c2ecf20Sopenharmony_ci 667, /* 32 */ 1268c2ecf20Sopenharmony_ci 1000, /* 48 */ 1278c2ecf20Sopenharmony_ci 1333, /* 64 */ 1288c2ecf20Sopenharmony_ci 2000, /* 96 */ 1298c2ecf20Sopenharmony_ci 2667, /* 128 */ 1308c2ecf20Sopenharmony_ci 3333, /* 160 */ 1318c2ecf20Sopenharmony_ci 4000, /* 192 */ 1328c2ecf20Sopenharmony_ci 4667, /* 224 */ 1338c2ecf20Sopenharmony_ci 5333, /* 256 */ 1348c2ecf20Sopenharmony_ci 6000, /* 288 */ 1358c2ecf20Sopenharmony_ci 0 /* No delay, switch matrix always on */ 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * Delay after issuing a POLL command. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * The delay is 3 AC97 link frames + the touchpanel settling delay 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic inline void poll_delay(int d) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci udelay(3 * AC97_LINK_FRAME + delay_table[d]); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* 1498c2ecf20Sopenharmony_ci * set up the physical settings of the WM9713 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic void wm9713_phy_init(struct wm97xx *wm) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci u16 dig1 = 0, dig2, dig3; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* default values */ 1568c2ecf20Sopenharmony_ci dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5); 1578c2ecf20Sopenharmony_ci dig3 = WM9712_RPU(1); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* rpu */ 1608c2ecf20Sopenharmony_ci if (rpu) { 1618c2ecf20Sopenharmony_ci dig3 &= 0xffc0; 1628c2ecf20Sopenharmony_ci dig3 |= WM9712_RPU(rpu); 1638c2ecf20Sopenharmony_ci dev_info(wm->dev, "setting pen detect pull-up to %d Ohms\n", 1648c2ecf20Sopenharmony_ci 64000 / rpu); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Five wire panel? */ 1688c2ecf20Sopenharmony_ci if (five_wire) { 1698c2ecf20Sopenharmony_ci dig3 |= WM9713_45W; 1708c2ecf20Sopenharmony_ci dev_info(wm->dev, "setting 5-wire touchscreen mode."); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (pil) { 1738c2ecf20Sopenharmony_ci dev_warn(wm->dev, 1748c2ecf20Sopenharmony_ci "Pressure measurement not supported in 5 " 1758c2ecf20Sopenharmony_ci "wire mode, disabling\n"); 1768c2ecf20Sopenharmony_ci pil = 0; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* touchpanel pressure */ 1818c2ecf20Sopenharmony_ci if (pil == 2) { 1828c2ecf20Sopenharmony_ci dig3 |= WM9712_PIL; 1838c2ecf20Sopenharmony_ci dev_info(wm->dev, 1848c2ecf20Sopenharmony_ci "setting pressure measurement current to 400uA."); 1858c2ecf20Sopenharmony_ci } else if (pil) 1868c2ecf20Sopenharmony_ci dev_info(wm->dev, 1878c2ecf20Sopenharmony_ci "setting pressure measurement current to 200uA."); 1888c2ecf20Sopenharmony_ci if (!pil) 1898c2ecf20Sopenharmony_ci pressure = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* sample settling delay */ 1928c2ecf20Sopenharmony_ci if (delay < 0 || delay > 15) { 1938c2ecf20Sopenharmony_ci dev_info(wm->dev, "supplied delay out of range."); 1948c2ecf20Sopenharmony_ci delay = 4; 1958c2ecf20Sopenharmony_ci dev_info(wm->dev, "setting adc sample delay to %d u Secs.", 1968c2ecf20Sopenharmony_ci delay_table[delay]); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci dig2 &= 0xff0f; 1998c2ecf20Sopenharmony_ci dig2 |= WM97XX_DELAY(delay); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* mask */ 2028c2ecf20Sopenharmony_ci dig3 |= ((mask & 0x3) << 4); 2038c2ecf20Sopenharmony_ci if (coord) 2048c2ecf20Sopenharmony_ci dig3 |= WM9713_WAIT; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci wm->misc = wm97xx_reg_read(wm, 0x5a); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1); 2098c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2); 2108c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3); 2118c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic void wm9713_dig_enable(struct wm97xx *wm, int enable) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u16 val; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (enable) { 2198c2ecf20Sopenharmony_ci val = wm97xx_reg_read(wm, AC97_EXTENDED_MID); 2208c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff); 2218c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] | 2228c2ecf20Sopenharmony_ci WM97XX_PRP_DET_DIG); 2238c2ecf20Sopenharmony_ci wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */ 2248c2ecf20Sopenharmony_ci } else { 2258c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] & 2268c2ecf20Sopenharmony_ci ~WM97XX_PRP_DET_DIG); 2278c2ecf20Sopenharmony_ci val = wm97xx_reg_read(wm, AC97_EXTENDED_MID); 2288c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void wm9713_dig_restore(struct wm97xx *wm) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]); 2358c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]); 2368c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void wm9713_aux_prepare(struct wm97xx *wm) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci memcpy(wm->dig_save, wm->dig, sizeof(wm->dig)); 2428c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0); 2438c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0); 2448c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic inline int is_pden(struct wm97xx *wm) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci return wm->dig[2] & WM9713_PDEN; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* 2538c2ecf20Sopenharmony_ci * Read a sample from the WM9713 adc in polling mode. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_cistatic int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci u16 dig1; 2588c2ecf20Sopenharmony_ci int timeout = 5 * delay; 2598c2ecf20Sopenharmony_ci bool wants_pen = adcsel & WM97XX_PEN_DOWN; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (wants_pen && !wm->pen_probably_down) { 2628c2ecf20Sopenharmony_ci u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 2638c2ecf20Sopenharmony_ci if (!(data & WM97XX_PEN_DOWN)) 2648c2ecf20Sopenharmony_ci return RC_PENUP; 2658c2ecf20Sopenharmony_ci wm->pen_probably_down = 1; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* set up digitiser */ 2698c2ecf20Sopenharmony_ci dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1); 2708c2ecf20Sopenharmony_ci dig1 &= ~WM9713_ADCSEL_MASK; 2718c2ecf20Sopenharmony_ci /* WM97XX_ADCSEL_* channels need to be converted to WM9713 format */ 2728c2ecf20Sopenharmony_ci dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (wm->mach_ops && wm->mach_ops->pre_sample) 2758c2ecf20Sopenharmony_ci wm->mach_ops->pre_sample(adcsel); 2768c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* wait 3 AC97 time slots + delay for conversion */ 2798c2ecf20Sopenharmony_ci poll_delay(delay); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* wait for POLL to go low */ 2828c2ecf20Sopenharmony_ci while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && 2838c2ecf20Sopenharmony_ci timeout) { 2848c2ecf20Sopenharmony_ci udelay(AC97_LINK_FRAME); 2858c2ecf20Sopenharmony_ci timeout--; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (timeout <= 0) { 2898c2ecf20Sopenharmony_ci /* If PDEN is set, we can get a timeout when pen goes up */ 2908c2ecf20Sopenharmony_ci if (is_pden(wm)) 2918c2ecf20Sopenharmony_ci wm->pen_probably_down = 0; 2928c2ecf20Sopenharmony_ci else 2938c2ecf20Sopenharmony_ci dev_dbg(wm->dev, "adc sample timeout"); 2948c2ecf20Sopenharmony_ci return RC_PENUP; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 2988c2ecf20Sopenharmony_ci if (wm->mach_ops && wm->mach_ops->post_sample) 2998c2ecf20Sopenharmony_ci wm->mach_ops->post_sample(adcsel); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* check we have correct sample */ 3028c2ecf20Sopenharmony_ci if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) { 3038c2ecf20Sopenharmony_ci dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x", 3048c2ecf20Sopenharmony_ci adcsel & WM97XX_ADCSEL_MASK, 3058c2ecf20Sopenharmony_ci *sample & WM97XX_ADCSEL_MASK); 3068c2ecf20Sopenharmony_ci return RC_PENUP; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) { 3108c2ecf20Sopenharmony_ci wm->pen_probably_down = 0; 3118c2ecf20Sopenharmony_ci return RC_PENUP; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return RC_VALID; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * Read a coordinate from the WM9713 adc in polling mode. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_cistatic int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u16 dig1; 3238c2ecf20Sopenharmony_ci int timeout = 5 * delay; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (!wm->pen_probably_down) { 3268c2ecf20Sopenharmony_ci u16 val = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 3278c2ecf20Sopenharmony_ci if (!(val & WM97XX_PEN_DOWN)) 3288c2ecf20Sopenharmony_ci return RC_PENUP; 3298c2ecf20Sopenharmony_ci wm->pen_probably_down = 1; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* set up digitiser */ 3338c2ecf20Sopenharmony_ci dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1); 3348c2ecf20Sopenharmony_ci dig1 &= ~WM9713_ADCSEL_MASK; 3358c2ecf20Sopenharmony_ci if (pil) 3368c2ecf20Sopenharmony_ci dig1 |= WM9713_ADCSEL_PRES; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (wm->mach_ops && wm->mach_ops->pre_sample) 3398c2ecf20Sopenharmony_ci wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y); 3408c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG1, 3418c2ecf20Sopenharmony_ci dig1 | WM9713_POLL | WM9713_COO); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* wait 3 AC97 time slots + delay for conversion */ 3448c2ecf20Sopenharmony_ci poll_delay(delay); 3458c2ecf20Sopenharmony_ci data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 3468c2ecf20Sopenharmony_ci /* wait for POLL to go low */ 3478c2ecf20Sopenharmony_ci while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) 3488c2ecf20Sopenharmony_ci && timeout) { 3498c2ecf20Sopenharmony_ci udelay(AC97_LINK_FRAME); 3508c2ecf20Sopenharmony_ci timeout--; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (timeout <= 0) { 3548c2ecf20Sopenharmony_ci /* If PDEN is set, we can get a timeout when pen goes up */ 3558c2ecf20Sopenharmony_ci if (is_pden(wm)) 3568c2ecf20Sopenharmony_ci wm->pen_probably_down = 0; 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci dev_dbg(wm->dev, "adc sample timeout"); 3598c2ecf20Sopenharmony_ci return RC_PENUP; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* read back data */ 3638c2ecf20Sopenharmony_ci data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 3648c2ecf20Sopenharmony_ci if (pil) 3658c2ecf20Sopenharmony_ci data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 3668c2ecf20Sopenharmony_ci else 3678c2ecf20Sopenharmony_ci data->p = DEFAULT_PRESSURE; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (wm->mach_ops && wm->mach_ops->post_sample) 3708c2ecf20Sopenharmony_ci wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* check we have correct sample */ 3738c2ecf20Sopenharmony_ci if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y)) 3748c2ecf20Sopenharmony_ci goto err; 3758c2ecf20Sopenharmony_ci if (pil && !(data->p & WM97XX_ADCSEL_PRES)) 3768c2ecf20Sopenharmony_ci goto err; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) { 3798c2ecf20Sopenharmony_ci wm->pen_probably_down = 0; 3808c2ecf20Sopenharmony_ci return RC_PENUP; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci return RC_VALID; 3838c2ecf20Sopenharmony_cierr: 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/* 3888c2ecf20Sopenharmony_ci * Sample the WM9713 touchscreen in polling mode 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_cistatic int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int rc; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (coord) { 3958c2ecf20Sopenharmony_ci rc = wm9713_poll_coord(wm, data); 3968c2ecf20Sopenharmony_ci if (rc != RC_VALID) 3978c2ecf20Sopenharmony_ci return rc; 3988c2ecf20Sopenharmony_ci } else { 3998c2ecf20Sopenharmony_ci rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x); 4008c2ecf20Sopenharmony_ci if (rc != RC_VALID) 4018c2ecf20Sopenharmony_ci return rc; 4028c2ecf20Sopenharmony_ci rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y); 4038c2ecf20Sopenharmony_ci if (rc != RC_VALID) 4048c2ecf20Sopenharmony_ci return rc; 4058c2ecf20Sopenharmony_ci if (pil) { 4068c2ecf20Sopenharmony_ci rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, 4078c2ecf20Sopenharmony_ci &data->p); 4088c2ecf20Sopenharmony_ci if (rc != RC_VALID) 4098c2ecf20Sopenharmony_ci return rc; 4108c2ecf20Sopenharmony_ci } else 4118c2ecf20Sopenharmony_ci data->p = DEFAULT_PRESSURE; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci return RC_VALID; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* 4178c2ecf20Sopenharmony_ci * Enable WM9713 continuous mode, i.e. touch data is streamed across 4188c2ecf20Sopenharmony_ci * an AC97 slot 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cistatic int wm9713_acc_enable(struct wm97xx *wm, int enable) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci u16 dig1, dig2, dig3; 4238c2ecf20Sopenharmony_ci int ret = 0; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci dig1 = wm->dig[0]; 4268c2ecf20Sopenharmony_ci dig2 = wm->dig[1]; 4278c2ecf20Sopenharmony_ci dig3 = wm->dig[2]; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (enable) { 4308c2ecf20Sopenharmony_ci /* continuous mode */ 4318c2ecf20Sopenharmony_ci if (wm->mach_ops->acc_startup && 4328c2ecf20Sopenharmony_ci (ret = wm->mach_ops->acc_startup(wm)) < 0) 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci dig1 &= ~WM9713_ADCSEL_MASK; 4368c2ecf20Sopenharmony_ci dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X | 4378c2ecf20Sopenharmony_ci WM9713_ADCSEL_Y; 4388c2ecf20Sopenharmony_ci if (pil) 4398c2ecf20Sopenharmony_ci dig1 |= WM9713_ADCSEL_PRES; 4408c2ecf20Sopenharmony_ci dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK | 4418c2ecf20Sopenharmony_ci WM97XX_CM_RATE_MASK); 4428c2ecf20Sopenharmony_ci dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) | 4438c2ecf20Sopenharmony_ci WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate); 4448c2ecf20Sopenharmony_ci dig3 |= WM9713_PDEN; 4458c2ecf20Sopenharmony_ci } else { 4468c2ecf20Sopenharmony_ci dig1 &= ~(WM9713_CTC | WM9713_COO); 4478c2ecf20Sopenharmony_ci dig2 &= ~WM97XX_SLEN; 4488c2ecf20Sopenharmony_ci dig3 &= ~WM9713_PDEN; 4498c2ecf20Sopenharmony_ci if (wm->mach_ops->acc_shutdown) 4508c2ecf20Sopenharmony_ci wm->mach_ops->acc_shutdown(wm); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1); 4548c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2); 4558c2ecf20Sopenharmony_ci wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return ret; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistruct wm97xx_codec_drv wm9713_codec = { 4618c2ecf20Sopenharmony_ci .id = WM9713_ID2, 4628c2ecf20Sopenharmony_ci .name = "wm9713", 4638c2ecf20Sopenharmony_ci .poll_sample = wm9713_poll_sample, 4648c2ecf20Sopenharmony_ci .poll_touch = wm9713_poll_touch, 4658c2ecf20Sopenharmony_ci .acc_enable = wm9713_acc_enable, 4668c2ecf20Sopenharmony_ci .phy_init = wm9713_phy_init, 4678c2ecf20Sopenharmony_ci .dig_enable = wm9713_dig_enable, 4688c2ecf20Sopenharmony_ci .dig_restore = wm9713_dig_restore, 4698c2ecf20Sopenharmony_ci .aux_prepare = wm9713_aux_prepare, 4708c2ecf20Sopenharmony_ci}; 4718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm9713_codec); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/* Module information */ 4748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>"); 4758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("WM9713 Touch Screen Driver"); 4768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 477