155714Skris// SPDX-License-Identifier: GPL-2.0-or-later 255714Skris/* 355714Skris * Touchscreen driver for WM831x PMICs 455714Skris * 555714Skris * Copyright 2011 Wolfson Microelectronics plc. 655714Skris * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 755714Skris */ 855714Skris 955714Skris#include <linux/module.h> 1055714Skris#include <linux/moduleparam.h> 1155714Skris#include <linux/kernel.h> 1255714Skris#include <linux/string.h> 1355714Skris#include <linux/pm.h> 1455714Skris#include <linux/input.h> 1555714Skris#include <linux/interrupt.h> 1655714Skris#include <linux/io.h> 1755714Skris#include <linux/mfd/wm831x/core.h> 1855714Skris#include <linux/mfd/wm831x/irq.h> 1955714Skris#include <linux/mfd/wm831x/pdata.h> 2055714Skris#include <linux/platform_device.h> 2155714Skris#include <linux/slab.h> 2255714Skris#include <linux/types.h> 2355714Skris 2455714Skris/* 2555714Skris * R16424 (0x4028) - Touch Control 1 2655714Skris */ 2755714Skris#define WM831X_TCH_ENA 0x8000 /* TCH_ENA */ 2855714Skris#define WM831X_TCH_CVT_ENA 0x4000 /* TCH_CVT_ENA */ 2955714Skris#define WM831X_TCH_SLPENA 0x1000 /* TCH_SLPENA */ 3055714Skris#define WM831X_TCH_Z_ENA 0x0400 /* TCH_Z_ENA */ 3155714Skris#define WM831X_TCH_Y_ENA 0x0200 /* TCH_Y_ENA */ 3255714Skris#define WM831X_TCH_X_ENA 0x0100 /* TCH_X_ENA */ 3355714Skris#define WM831X_TCH_DELAY_MASK 0x00E0 /* TCH_DELAY - [7:5] */ 3455714Skris#define WM831X_TCH_DELAY_SHIFT 5 /* TCH_DELAY - [7:5] */ 3555714Skris#define WM831X_TCH_DELAY_WIDTH 3 /* TCH_DELAY - [7:5] */ 3655714Skris#define WM831X_TCH_RATE_MASK 0x001F /* TCH_RATE - [4:0] */ 3755714Skris#define WM831X_TCH_RATE_SHIFT 0 /* TCH_RATE - [4:0] */ 3855714Skris#define WM831X_TCH_RATE_WIDTH 5 /* TCH_RATE - [4:0] */ 3955714Skris 4055714Skris/* 4155714Skris * R16425 (0x4029) - Touch Control 2 4255714Skris */ 4355714Skris#define WM831X_TCH_PD_WK 0x2000 /* TCH_PD_WK */ 4455714Skris#define WM831X_TCH_5WIRE 0x1000 /* TCH_5WIRE */ 4555714Skris#define WM831X_TCH_PDONLY 0x0800 /* TCH_PDONLY */ 4655714Skris#define WM831X_TCH_ISEL 0x0100 /* TCH_ISEL */ 4755714Skris#define WM831X_TCH_RPU_MASK 0x000F /* TCH_RPU - [3:0] */ 4855714Skris#define WM831X_TCH_RPU_SHIFT 0 /* TCH_RPU - [3:0] */ 4955714Skris#define WM831X_TCH_RPU_WIDTH 4 /* TCH_RPU - [3:0] */ 5055714Skris 5155714Skris/* 5255714Skris * R16426-8 (0x402A-C) - Touch Data X/Y/X 5355714Skris */ 5455714Skris#define WM831X_TCH_PD 0x8000 /* TCH_PD1 */ 5555714Skris#define WM831X_TCH_DATA_MASK 0x0FFF /* TCH_DATA - [11:0] */ 5655714Skris#define WM831X_TCH_DATA_SHIFT 0 /* TCH_DATA - [11:0] */ 5755714Skris#define WM831X_TCH_DATA_WIDTH 12 /* TCH_DATA - [11:0] */ 5855714Skris 5955714Skrisstruct wm831x_ts { 6068651Skris struct input_dev *input_dev; 6155714Skris struct wm831x *wm831x; 6268651Skris unsigned int data_irq; 6368651Skris unsigned int pd_irq; 6468651Skris bool pressure; 6555714Skris bool pen_down; 6668651Skris struct work_struct pd_data_work; 6755714Skris}; 6855714Skris 6968651Skrisstatic void wm831x_pd_data_work(struct work_struct *work) 7055714Skris{ 7168651Skris struct wm831x_ts *wm831x_ts = 7255714Skris container_of(work, struct wm831x_ts, pd_data_work); 7368651Skris 7468651Skris if (wm831x_ts->pen_down) { 7568651Skris enable_irq(wm831x_ts->data_irq); 7668651Skris dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n"); 7768651Skris } else { 7868651Skris enable_irq(wm831x_ts->pd_irq); 7968651Skris dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n"); 8068651Skris } 8168651Skris} 8268651Skris 8368651Skrisstatic irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) 8468651Skris{ 8568651Skris struct wm831x_ts *wm831x_ts = irq_data; 8668651Skris struct wm831x *wm831x = wm831x_ts->wm831x; 8768651Skris static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE }; 8868651Skris u16 data[3]; 8968651Skris int count; 9068651Skris int i, ret; 9168651Skris 9268651Skris if (wm831x_ts->pressure) 9368651Skris count = 3; 9468651Skris else 9568651Skris count = 2; 9668651Skris 9768651Skris wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, 9868651Skris WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); 9968651Skris 10068651Skris ret = wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, 10168651Skris data); 10268651Skris if (ret != 0) { 10368651Skris dev_err(wm831x->dev, "Failed to read touch data: %d\n", 10468651Skris ret); 10568651Skris return IRQ_NONE; 10668651Skris } 10768651Skris 10868651Skris /* 10968651Skris * We get a pen down reading on every reading, report pen up if any 11068651Skris * individual reading does so. 11168651Skris */ 11268651Skris wm831x_ts->pen_down = true; 11368651Skris for (i = 0; i < count; i++) { 11468651Skris if (!(data[i] & WM831X_TCH_PD)) { 11568651Skris wm831x_ts->pen_down = false; 11668651Skris continue; 11768651Skris } 11868651Skris input_report_abs(wm831x_ts->input_dev, data_types[i], 11968651Skris data[i] & WM831X_TCH_DATA_MASK); 12068651Skris } 12168651Skris 12268651Skris if (!wm831x_ts->pen_down) { 12368651Skris /* Switch from data to pen down */ 12468651Skris dev_dbg(wm831x->dev, "IRQ DATA->PD\n"); 12568651Skris 12668651Skris disable_irq_nosync(wm831x_ts->data_irq); 12768651Skris 12868651Skris /* Don't need data any more */ 12968651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 13068651Skris WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | 13168651Skris WM831X_TCH_Z_ENA, 0); 13268651Skris 13368651Skris /* Flush any final samples that arrived while reading */ 13468651Skris wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, 13568651Skris WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); 13668651Skris 13768651Skris wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, data); 13868651Skris 13968651Skris if (wm831x_ts->pressure) 14068651Skris input_report_abs(wm831x_ts->input_dev, 14168651Skris ABS_PRESSURE, 0); 14268651Skris 14368651Skris input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); 14468651Skris 14568651Skris schedule_work(&wm831x_ts->pd_data_work); 14668651Skris } else { 14768651Skris input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); 14868651Skris } 14968651Skris 15068651Skris input_sync(wm831x_ts->input_dev); 15168651Skris 15268651Skris return IRQ_HANDLED; 15368651Skris} 15468651Skris 15568651Skrisstatic irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) 15668651Skris{ 15768651Skris struct wm831x_ts *wm831x_ts = irq_data; 15868651Skris struct wm831x *wm831x = wm831x_ts->wm831x; 15968651Skris int ena = 0; 16068651Skris 16168651Skris if (wm831x_ts->pen_down) 16268651Skris return IRQ_HANDLED; 16368651Skris 16468651Skris disable_irq_nosync(wm831x_ts->pd_irq); 16568651Skris 16668651Skris /* Start collecting data */ 16768651Skris if (wm831x_ts->pressure) 16868651Skris ena |= WM831X_TCH_Z_ENA; 16968651Skris 17068651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 17168651Skris WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 17268651Skris WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); 17368651Skris 17468651Skris wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, 17568651Skris WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); 17668651Skris 17768651Skris wm831x_ts->pen_down = true; 17868651Skris 17968651Skris /* Switch from pen down to data */ 18068651Skris dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); 18168651Skris schedule_work(&wm831x_ts->pd_data_work); 18268651Skris 18368651Skris return IRQ_HANDLED; 18468651Skris} 18568651Skris 18668651Skrisstatic int wm831x_ts_input_open(struct input_dev *idev) 18768651Skris{ 18868651Skris struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); 18968651Skris struct wm831x *wm831x = wm831x_ts->wm831x; 19068651Skris 19168651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 19268651Skris WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | 19368651Skris WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | 19468651Skris WM831X_TCH_Z_ENA, WM831X_TCH_ENA); 19568651Skris 19668651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 19768651Skris WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA); 19868651Skris 19968651Skris return 0; 20068651Skris} 20168651Skris 20268651Skrisstatic void wm831x_ts_input_close(struct input_dev *idev) 20368651Skris{ 20468651Skris struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); 20568651Skris struct wm831x *wm831x = wm831x_ts->wm831x; 20668651Skris 20768651Skris /* Shut the controller down, disabling all other functionality too */ 20868651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 20968651Skris WM831X_TCH_ENA | WM831X_TCH_X_ENA | 21068651Skris WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); 21168651Skris 21268651Skris /* Make sure any pending IRQs are done, the above will prevent 21368651Skris * new ones firing. 21468651Skris */ 21568651Skris synchronize_irq(wm831x_ts->data_irq); 21668651Skris synchronize_irq(wm831x_ts->pd_irq); 21768651Skris 21868651Skris /* Make sure the IRQ completion work is quiesced */ 21968651Skris flush_work(&wm831x_ts->pd_data_work); 22068651Skris 22168651Skris /* If we ended up with the pen down then make sure we revert back 22268651Skris * to pen detection state for the next time we start up. 22368651Skris */ 22468651Skris if (wm831x_ts->pen_down) { 22568651Skris disable_irq(wm831x_ts->data_irq); 22668651Skris enable_irq(wm831x_ts->pd_irq); 22768651Skris wm831x_ts->pen_down = false; 22868651Skris } 22968651Skris} 23068651Skris 23168651Skrisstatic int wm831x_ts_probe(struct platform_device *pdev) 23268651Skris{ 23368651Skris struct wm831x_ts *wm831x_ts; 23468651Skris struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 23568651Skris struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); 23668651Skris struct wm831x_touch_pdata *pdata = NULL; 23768651Skris struct input_dev *input_dev; 23868651Skris int error, irqf; 23968651Skris 24068651Skris if (core_pdata) 24168651Skris pdata = core_pdata->touch; 24268651Skris 24368651Skris wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts), 24468651Skris GFP_KERNEL); 24568651Skris input_dev = devm_input_allocate_device(&pdev->dev); 24668651Skris if (!wm831x_ts || !input_dev) { 24768651Skris error = -ENOMEM; 24868651Skris goto err_alloc; 24968651Skris } 25068651Skris 25168651Skris wm831x_ts->wm831x = wm831x; 25268651Skris wm831x_ts->input_dev = input_dev; 25368651Skris INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); 25468651Skris 25568651Skris /* 25668651Skris * If we have a direct IRQ use it, otherwise use the interrupt 25768651Skris * from the WM831x IRQ controller. 25868651Skris */ 25968651Skris wm831x_ts->data_irq = wm831x_irq(wm831x, 26068651Skris platform_get_irq_byname(pdev, 26168651Skris "TCHDATA")); 26268651Skris if (pdata && pdata->data_irq) 26368651Skris wm831x_ts->data_irq = pdata->data_irq; 26468651Skris 26568651Skris wm831x_ts->pd_irq = wm831x_irq(wm831x, 26668651Skris platform_get_irq_byname(pdev, "TCHPD")); 26768651Skris if (pdata && pdata->pd_irq) 26868651Skris wm831x_ts->pd_irq = pdata->pd_irq; 26968651Skris 27068651Skris if (pdata) 27168651Skris wm831x_ts->pressure = pdata->pressure; 27268651Skris else 27368651Skris wm831x_ts->pressure = true; 27468651Skris 27568651Skris /* Five wire touchscreens can't report pressure */ 27668651Skris if (pdata && pdata->fivewire) { 27768651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, 27868651Skris WM831X_TCH_5WIRE, WM831X_TCH_5WIRE); 27968651Skris 28068651Skris /* Pressure measurements are not possible for five wire mode */ 28168651Skris WARN_ON(pdata->pressure && pdata->fivewire); 28268651Skris wm831x_ts->pressure = false; 28368651Skris } else { 28468651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, 28568651Skris WM831X_TCH_5WIRE, 0); 28668651Skris } 28768651Skris 28868651Skris if (pdata) { 28968651Skris switch (pdata->isel) { 29068651Skris default: 29168651Skris dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n", 29268651Skris pdata->isel); 29368651Skris fallthrough; 29468651Skris case 200: 29568651Skris case 0: 29668651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, 29768651Skris WM831X_TCH_ISEL, 0); 29868651Skris break; 29968651Skris case 400: 30068651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, 30168651Skris WM831X_TCH_ISEL, WM831X_TCH_ISEL); 30268651Skris break; 30368651Skris } 30468651Skris } 30568651Skris 30668651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, 30768651Skris WM831X_TCH_PDONLY, 0); 30868651Skris 30968651Skris /* Default to 96 samples/sec */ 31068651Skris wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 31168651Skris WM831X_TCH_RATE_MASK, 6); 31268651Skris 31368651Skris if (pdata && pdata->data_irqf) 31468651Skris irqf = pdata->data_irqf; 31568651Skris else 31668651Skris irqf = IRQF_TRIGGER_HIGH; 31768651Skris 31868651Skris error = request_threaded_irq(wm831x_ts->data_irq, 31968651Skris NULL, wm831x_ts_data_irq, 32068651Skris irqf | IRQF_ONESHOT | IRQF_NO_AUTOEN, 32168651Skris "Touchscreen data", wm831x_ts); 32268651Skris if (error) { 32368651Skris dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", 32468651Skris wm831x_ts->data_irq, error); 32568651Skris goto err_alloc; 32668651Skris } 32768651Skris 32868651Skris if (pdata && pdata->pd_irqf) 32968651Skris irqf = pdata->pd_irqf; 33068651Skris else 33168651Skris irqf = IRQF_TRIGGER_HIGH; 33268651Skris 33368651Skris error = request_threaded_irq(wm831x_ts->pd_irq, 33468651Skris NULL, wm831x_ts_pen_down_irq, 33568651Skris irqf | IRQF_ONESHOT, 33668651Skris "Touchscreen pen down", wm831x_ts); 33768651Skris if (error) { 33868651Skris dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", 33968651Skris wm831x_ts->pd_irq, error); 34068651Skris goto err_data_irq; 34168651Skris } 34268651Skris 34368651Skris /* set up touch configuration */ 34468651Skris input_dev->name = "WM831x touchscreen"; 34568651Skris input_dev->phys = "wm831x"; 34668651Skris input_dev->open = wm831x_ts_input_open; 34768651Skris input_dev->close = wm831x_ts_input_close; 34868651Skris 34968651Skris __set_bit(EV_ABS, input_dev->evbit); 35068651Skris __set_bit(EV_KEY, input_dev->evbit); 35168651Skris __set_bit(BTN_TOUCH, input_dev->keybit); 35268651Skris 35368651Skris input_set_abs_params(input_dev, ABS_X, 0, 4095, 5, 0); 35468651Skris input_set_abs_params(input_dev, ABS_Y, 0, 4095, 5, 0); 35568651Skris if (wm831x_ts->pressure) 35668651Skris input_set_abs_params(input_dev, ABS_PRESSURE, 0, 4095, 5, 0); 35768651Skris 35868651Skris input_set_drvdata(input_dev, wm831x_ts); 35968651Skris input_dev->dev.parent = &pdev->dev; 36068651Skris 36168651Skris error = input_register_device(input_dev); 36268651Skris if (error) 36368651Skris goto err_pd_irq; 36468651Skris 36568651Skris platform_set_drvdata(pdev, wm831x_ts); 36668651Skris return 0; 36768651Skris 36868651Skriserr_pd_irq: 36968651Skris free_irq(wm831x_ts->pd_irq, wm831x_ts); 37068651Skriserr_data_irq: 37168651Skris free_irq(wm831x_ts->data_irq, wm831x_ts); 37268651Skriserr_alloc: 37368651Skris 37468651Skris return error; 37568651Skris} 37668651Skris 37768651Skrisstatic void wm831x_ts_remove(struct platform_device *pdev) 37868651Skris{ 37968651Skris struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev); 38068651Skris 38168651Skris free_irq(wm831x_ts->pd_irq, wm831x_ts); 38268651Skris free_irq(wm831x_ts->data_irq, wm831x_ts); 38368651Skris} 38468651Skris 38568651Skrisstatic struct platform_driver wm831x_ts_driver = { 38668651Skris .driver = { 38768651Skris .name = "wm831x-touch", 38868651Skris }, 38968651Skris .probe = wm831x_ts_probe, 39068651Skris .remove_new = wm831x_ts_remove, 39168651Skris}; 39268651Skrismodule_platform_driver(wm831x_ts_driver); 39368651Skris 39468651Skris/* Module information */ 39568651SkrisMODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 39668651SkrisMODULE_DESCRIPTION("WM831x PMIC touchscreen driver"); 39768651SkrisMODULE_LICENSE("GPL"); 39868651SkrisMODULE_ALIAS("platform:wm831x-touch"); 39968651Skris