cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mainstone-wm97xx.c (7276B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * mainstone-wm97xx.c  --  Mainstone Continuous Touch screen driver for
      4 *                         Wolfson WM97xx AC97 Codecs.
      5 *
      6 * Copyright 2004, 2007 Wolfson Microelectronics PLC.
      7 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
      8 * Parts Copyright : Ian Molton <spyro@f2s.com>
      9 *                   Andrew Zabolotny <zap@homelink.ru>
     10 *
     11 * Notes:
     12 *     This is a wm97xx extended touch driver to capture touch
     13 *     data in a continuous manner on the Intel XScale architecture
     14 *
     15 *  Features:
     16 *       - codecs supported:- WM9705, WM9712, WM9713
     17 *       - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
     18 */
     19
     20#include <linux/module.h>
     21#include <linux/moduleparam.h>
     22#include <linux/kernel.h>
     23#include <linux/delay.h>
     24#include <linux/gpio/consumer.h>
     25#include <linux/irq.h>
     26#include <linux/interrupt.h>
     27#include <linux/io.h>
     28#include <linux/soc/pxa/cpu.h>
     29#include <linux/wm97xx.h>
     30
     31#include <sound/pxa2xx-lib.h>
     32
     33#include <asm/mach-types.h>
     34
     35struct continuous {
     36	u16 id;    /* codec id */
     37	u8 code;   /* continuous code */
     38	u8 reads;  /* number of coord reads per read cycle */
     39	u32 speed; /* number of coords per second */
     40};
     41
     42#define WM_READS(sp) ((sp / HZ) + 1)
     43
     44static const struct continuous cinfo[] = {
     45	{ WM9705_ID2, 0, WM_READS(94),  94  },
     46	{ WM9705_ID2, 1, WM_READS(188), 188 },
     47	{ WM9705_ID2, 2, WM_READS(375), 375 },
     48	{ WM9705_ID2, 3, WM_READS(750), 750 },
     49	{ WM9712_ID2, 0, WM_READS(94),  94  },
     50	{ WM9712_ID2, 1, WM_READS(188), 188 },
     51	{ WM9712_ID2, 2, WM_READS(375), 375 },
     52	{ WM9712_ID2, 3, WM_READS(750), 750 },
     53	{ WM9713_ID2, 0, WM_READS(94),  94  },
     54	{ WM9713_ID2, 1, WM_READS(120), 120 },
     55	{ WM9713_ID2, 2, WM_READS(154), 154 },
     56	{ WM9713_ID2, 3, WM_READS(188), 188 },
     57};
     58
     59/* continuous speed index */
     60static int sp_idx;
     61static struct gpio_desc *gpiod_irq;
     62
     63/*
     64 * Pen sampling frequency (Hz) in continuous mode.
     65 */
     66static int cont_rate = 200;
     67module_param(cont_rate, int, 0);
     68MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
     69
     70/*
     71 * Pen down detection.
     72 *
     73 * This driver can either poll or use an interrupt to indicate a pen down
     74 * event. If the irq request fails then it will fall back to polling mode.
     75 */
     76static int pen_int;
     77module_param(pen_int, int, 0);
     78MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
     79
     80/*
     81 * Pressure readback.
     82 *
     83 * Set to 1 to read back pen down pressure
     84 */
     85static int pressure;
     86module_param(pressure, int, 0);
     87MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
     88
     89/*
     90 * AC97 touch data slot.
     91 *
     92 * Touch screen readback data ac97 slot
     93 */
     94static int ac97_touch_slot = 5;
     95module_param(ac97_touch_slot, int, 0);
     96MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
     97
     98
     99/* flush AC97 slot 5 FIFO on pxa machines */
    100static void wm97xx_acc_pen_up(struct wm97xx *wm)
    101{
    102	unsigned int count;
    103
    104	msleep(1);
    105
    106	if (cpu_is_pxa27x()) {
    107		while (pxa2xx_ac97_read_misr() & (1 << 2))
    108			pxa2xx_ac97_read_modr();
    109	} else if (cpu_is_pxa3xx()) {
    110		for (count = 0; count < 16; count++)
    111			pxa2xx_ac97_read_modr();
    112	}
    113}
    114
    115static int wm97xx_acc_pen_down(struct wm97xx *wm)
    116{
    117	u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
    118	int reads = 0;
    119	static u16 last, tries;
    120
    121	/* When the AC97 queue has been drained we need to allow time
    122	 * to buffer up samples otherwise we end up spinning polling
    123	 * for samples.  The controller can't have a suitably low
    124	 * threshold set to use the notifications it gives.
    125	 */
    126	msleep(1);
    127
    128	if (tries > 5) {
    129		tries = 0;
    130		return RC_PENUP;
    131	}
    132
    133	x = pxa2xx_ac97_read_modr();
    134	if (x == last) {
    135		tries++;
    136		return RC_AGAIN;
    137	}
    138	last = x;
    139	do {
    140		if (reads)
    141			x = pxa2xx_ac97_read_modr();
    142		y = pxa2xx_ac97_read_modr();
    143		if (pressure)
    144			p = pxa2xx_ac97_read_modr();
    145
    146		dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
    147			x, y, p);
    148
    149		/* are samples valid */
    150		if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
    151		    (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
    152		    (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
    153			goto up;
    154
    155		/* coordinate is good */
    156		tries = 0;
    157		input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
    158		input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
    159		input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
    160		input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
    161		input_sync(wm->input_dev);
    162		reads++;
    163	} while (reads < cinfo[sp_idx].reads);
    164up:
    165	return RC_PENDOWN | RC_AGAIN;
    166}
    167
    168static int wm97xx_acc_startup(struct wm97xx *wm)
    169{
    170	int idx = 0, ret = 0;
    171
    172	/* check we have a codec */
    173	if (wm->ac97 == NULL)
    174		return -ENODEV;
    175
    176	/* Go you big red fire engine */
    177	for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
    178		if (wm->id != cinfo[idx].id)
    179			continue;
    180		sp_idx = idx;
    181		if (cont_rate <= cinfo[idx].speed)
    182			break;
    183	}
    184	wm->acc_rate = cinfo[sp_idx].code;
    185	wm->acc_slot = ac97_touch_slot;
    186	dev_info(wm->dev,
    187		 "mainstone accelerated touchscreen driver, %d samples/sec\n",
    188		 cinfo[sp_idx].speed);
    189
    190	/* IRQ driven touchscreen is used on Palm hardware */
    191	if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
    192		pen_int = 1;
    193		/* There is some obscure mutant of WM9712 interbred with WM9713
    194		 * used on Palm HW */
    195		wm->variant = WM97xx_WM1613;
    196	} else if (machine_is_zylonite()) {
    197		pen_int = 1;
    198	}
    199
    200	if (pen_int) {
    201		gpiod_irq = gpiod_get(wm->dev, "touch", GPIOD_IN);
    202		if (IS_ERR(gpiod_irq))
    203			pen_int = 0;
    204	}
    205
    206	if (pen_int) {
    207		wm->pen_irq = gpiod_to_irq(gpiod_irq);
    208		irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
    209	}
    210
    211	/* codec specific irq config */
    212	if (pen_int) {
    213		switch (wm->id) {
    214		case WM9705_ID2:
    215			break;
    216		case WM9712_ID2:
    217		case WM9713_ID2:
    218			/* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
    219			wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
    220					   WM97XX_GPIO_POL_HIGH,
    221					   WM97XX_GPIO_STICKY,
    222					   WM97XX_GPIO_WAKE);
    223			wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
    224					   WM97XX_GPIO_POL_HIGH,
    225					   WM97XX_GPIO_NOTSTICKY,
    226					   WM97XX_GPIO_NOWAKE);
    227			break;
    228		default:
    229			dev_err(wm->dev,
    230				"pen down irq not supported on this device\n");
    231			pen_int = 0;
    232			break;
    233		}
    234	}
    235
    236	return ret;
    237}
    238
    239static void wm97xx_acc_shutdown(struct wm97xx *wm)
    240{
    241	/* codec specific deconfig */
    242	if (pen_int) {
    243		if (gpiod_irq)
    244			gpiod_put(gpiod_irq);
    245		wm->pen_irq = 0;
    246	}
    247}
    248
    249static struct wm97xx_mach_ops mainstone_mach_ops = {
    250	.acc_enabled	= 1,
    251	.acc_pen_up	= wm97xx_acc_pen_up,
    252	.acc_pen_down	= wm97xx_acc_pen_down,
    253	.acc_startup	= wm97xx_acc_startup,
    254	.acc_shutdown	= wm97xx_acc_shutdown,
    255	.irq_gpio	= WM97XX_GPIO_2,
    256};
    257
    258static int mainstone_wm97xx_probe(struct platform_device *pdev)
    259{
    260	struct wm97xx *wm = platform_get_drvdata(pdev);
    261
    262	return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
    263}
    264
    265static int mainstone_wm97xx_remove(struct platform_device *pdev)
    266{
    267	struct wm97xx *wm = platform_get_drvdata(pdev);
    268
    269	wm97xx_unregister_mach_ops(wm);
    270
    271	return 0;
    272}
    273
    274static struct platform_driver mainstone_wm97xx_driver = {
    275	.probe	= mainstone_wm97xx_probe,
    276	.remove	= mainstone_wm97xx_remove,
    277	.driver	= {
    278		.name	= "wm97xx-touch",
    279	},
    280};
    281module_platform_driver(mainstone_wm97xx_driver);
    282
    283/* Module information */
    284MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
    285MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
    286MODULE_LICENSE("GPL");