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