From 10ebd8556b7990499c896a550e3d416b444211e6 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 02:23:07 +0000
Subject: [PATCH] add led
---
kernel/drivers/input/touchscreen/ads7846.c | 519 +++++++++++++++++++++++++++------------------------------
1 files changed, 244 insertions(+), 275 deletions(-)
diff --git a/kernel/drivers/input/touchscreen/ads7846.c b/kernel/drivers/input/touchscreen/ads7846.c
index b536768..1753288 100644
--- a/kernel/drivers/input/touchscreen/ads7846.c
+++ b/kernel/drivers/input/touchscreen/ads7846.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ADS7846 based touchscreen and sensor driver
*
@@ -12,10 +13,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/hwmon.h>
@@ -23,6 +20,7 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/input.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/pm.h>
@@ -65,19 +63,15 @@
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
-struct ts_event {
- /*
- * For portability, we can't read 12 bit values using SPI (which
- * would make the controller deliver them as native byte order u16
- * with msbs zeroed). Instead, we read them as two 8-bit values,
- * *** WHICH NEED BYTESWAPPING *** and range adjustment.
- */
- u16 x;
- u16 y;
- u16 z1, z2;
- bool ignore;
- u8 x_buf[3];
- u8 y_buf[3];
+struct ads7846_buf {
+ u8 cmd;
+ __be16 data;
+} __packed;
+
+struct ads7846_buf_layout {
+ unsigned int offset;
+ unsigned int count;
+ unsigned int skip;
};
/*
@@ -86,11 +80,18 @@
* systems where main memory is not DMA-coherent (most non-x86 boards).
*/
struct ads7846_packet {
- u8 read_x, read_y, read_z1, read_z2, pwrdown;
- u16 dummy; /* for the pwrdown read */
- struct ts_event tc;
- /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
- u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
+ unsigned int count;
+ unsigned int count_skip;
+ unsigned int cmds;
+ unsigned int last_cmd_idx;
+ struct ads7846_buf_layout l[5];
+ struct ads7846_buf *rx;
+ struct ads7846_buf *tx;
+
+ struct ads7846_buf pwrdown_cmd;
+
+ bool ignore;
+ u16 x, y, z1, z2;
};
struct ads7846 {
@@ -132,6 +133,8 @@
u16 debounce_rep;
u16 penirq_recheck_delay_usecs;
+
+ struct touchscreen_properties core_prop;
struct mutex lock;
bool stopped; /* P: lock */
@@ -187,7 +190,6 @@
#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
-
#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
@@ -199,6 +201,21 @@
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+
+/* Order commands in the most optimal way to reduce Vref switching and
+ * settling time:
+ * Measure: X; Vref: X+, X-; IN: Y+
+ * Measure: Y; Vref: Y+, Y-; IN: X+
+ * Measure: Z1; Vref: Y+, X-; IN: X+
+ * Measure: Z2; Vref: Y+, X-; IN: Y-
+ */
+enum ads7846_cmds {
+ ADS7846_X,
+ ADS7846_Y,
+ ADS7846_Z1,
+ ADS7846_Z2,
+ ADS7846_PWDOWN,
+};
static int get_pendown_state(struct ads7846 *ts)
{
@@ -358,7 +375,8 @@
req->xfer[1].len = 2;
/* for 1uF, settle for 800 usec; no cap, 100 usec. */
- req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[1].delay.value = ts->vref_delay_usecs;
+ req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS;
spi_message_add_tail(&req->xfer[1], &req->msg);
/* Enable reference voltage */
@@ -681,32 +699,109 @@
return ADS7846_FILTER_OK;
}
-static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+static int ads7846_get_value(struct ads7846_buf *buf)
{
int value;
- struct spi_transfer *t =
- list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- if (ts->model == 7845) {
- value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1]));
- } else {
- /*
- * adjust: on-wire is a must-ignore bit, a BE12 value, then
- * padding; built from two 8 bit values written msb-first.
- */
- value = be16_to_cpup((__be16 *)t->rx_buf);
- }
+ value = be16_to_cpup(&buf->data);
/* enforce ADC output is 12 bits width */
return (value >> 3) & 0xfff;
}
-static void ads7846_update_value(struct spi_message *m, int val)
+static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx,
+ u16 val)
{
- struct spi_transfer *t =
- list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ struct ads7846_packet *packet = ts->packet;
- *(u16 *)t->rx_buf = val;
+ switch (cmd_idx) {
+ case ADS7846_Y:
+ packet->y = val;
+ break;
+ case ADS7846_X:
+ packet->x = val;
+ break;
+ case ADS7846_Z1:
+ packet->z1 = val;
+ break;
+ case ADS7846_Z2:
+ packet->z2 = val;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+
+static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref)
+{
+ switch (cmd_idx) {
+ case ADS7846_Y:
+ return READ_Y(vref);
+ case ADS7846_X:
+ return READ_X(vref);
+
+ /* 7846 specific commands */
+ case ADS7846_Z1:
+ return READ_Z1(vref);
+ case ADS7846_Z2:
+ return READ_Z2(vref);
+ case ADS7846_PWDOWN:
+ return PWRDOWN;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ return 0;
+}
+
+static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)
+{
+ switch (cmd_idx) {
+ case ADS7846_X:
+ case ADS7846_Y:
+ case ADS7846_Z1:
+ case ADS7846_Z2:
+ return true;
+ case ADS7846_PWDOWN:
+ return false;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ return false;
+}
+
+static int ads7846_filter(struct ads7846 *ts)
+{
+ struct ads7846_packet *packet = ts->packet;
+ int action;
+ int val;
+ unsigned int cmd_idx, b;
+
+ packet->ignore = false;
+ for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+
+ packet->last_cmd_idx = cmd_idx;
+
+ for (b = l->skip; b < l->count; b++) {
+ val = ads7846_get_value(&packet->rx[l->offset + b]);
+
+ action = ts->filter(ts->filter_data, cmd_idx, &val);
+ if (action == ADS7846_FILTER_REPEAT) {
+ if (b == l->count - 1)
+ return -EAGAIN;
+ } else if (action == ADS7846_FILTER_OK) {
+ ads7846_set_cmd_val(ts, cmd_idx, val);
+ break;
+ } else {
+ packet->ignore = true;
+ return 0;
+ }
+ }
+ }
+
+ return 0;
}
static void ads7846_read_state(struct ads7846 *ts)
@@ -714,52 +809,26 @@
struct ads7846_packet *packet = ts->packet;
struct spi_message *m;
int msg_idx = 0;
- int val;
- int action;
int error;
- while (msg_idx < ts->msg_count) {
+ packet->last_cmd_idx = 0;
+ while (true) {
ts->wait_for_sync();
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
- packet->tc.ignore = true;
+ packet->ignore = true;
return;
}
- /*
- * Last message is power down request, no need to convert
- * or filter the value.
- */
- if (msg_idx < ts->msg_count - 1) {
+ error = ads7846_filter(ts);
+ if (error)
+ continue;
- val = ads7846_get_value(ts, m);
-
- action = ts->filter(ts->filter_data, msg_idx, &val);
- switch (action) {
- case ADS7846_FILTER_REPEAT:
- continue;
-
- case ADS7846_FILTER_IGNORE:
- packet->tc.ignore = true;
- msg_idx = ts->msg_count - 1;
- continue;
-
- case ADS7846_FILTER_OK:
- ads7846_update_value(m, val);
- packet->tc.ignore = false;
- msg_idx++;
- break;
-
- default:
- BUG();
- }
- } else {
- msg_idx++;
- }
+ return;
}
}
@@ -769,35 +838,22 @@
unsigned int Rt;
u16 x, y, z1, z2;
- /*
- * ads7846_get_value() does in-place conversion (including byte swap)
- * from on-the-wire format as part of debouncing to get stable
- * readings.
- */
+ x = packet->x;
+ y = packet->y;
if (ts->model == 7845) {
- x = *(u16 *)packet->tc.x_buf;
- y = *(u16 *)packet->tc.y_buf;
z1 = 0;
z2 = 0;
} else {
- x = packet->tc.x;
- y = packet->tc.y;
- z1 = packet->tc.z1;
- z2 = packet->tc.z2;
+ z1 = packet->z1;
+ z2 = packet->z2;
}
/* range filtering */
if (x == MAX_12BIT)
x = 0;
- if (ts->model == 7843) {
+ if (ts->model == 7843 || ts->model == 7845) {
Rt = ts->pressure_max / 2;
- } else if (ts->model == 7845) {
- if (get_pendown_state(ts))
- Rt = ts->pressure_max / 2;
- else
- Rt = 0;
- dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
} else if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
@@ -816,9 +872,9 @@
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
*/
- if (packet->tc.ignore || Rt > ts->pressure_max) {
+ if (packet->ignore || Rt > ts->pressure_max) {
dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
- packet->tc.ignore, Rt);
+ packet->ignore, Rt);
return;
}
@@ -844,17 +900,13 @@
if (Rt) {
struct input_dev *input = ts->input;
- if (ts->swap_xy)
- swap(x, y);
-
if (!ts->pendown) {
input_report_key(input, BTN_TOUCH, 1);
ts->pendown = true;
dev_vdbg(&ts->spi->dev, "DOWN\n");
}
- input_report_abs(input, ABS_X, x);
- input_report_abs(input, ABS_Y, y);
+ touchscreen_report_pos(input, &ts->core_prop, x, y, false);
input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
input_sync(input);
@@ -983,13 +1035,62 @@
* Set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
-static void ads7846_setup_spi_msg(struct ads7846 *ts,
+static int ads7846_setup_spi_msg(struct ads7846 *ts,
const struct ads7846_platform_data *pdata)
{
struct spi_message *m = &ts->msg[0];
struct spi_transfer *x = ts->xfer;
struct ads7846_packet *packet = ts->packet;
int vref = pdata->keep_vref_on;
+ unsigned int count, offset = 0;
+ unsigned int cmd_idx, b;
+ unsigned long time;
+ size_t size = 0;
+
+ /* time per bit */
+ time = NSEC_PER_SEC / ts->spi->max_speed_hz;
+
+ count = pdata->settle_delay_usecs * NSEC_PER_USEC / time;
+ packet->count_skip = DIV_ROUND_UP(count, 24);
+
+ if (ts->debounce_max && ts->debounce_rep)
+ /* ads7846_debounce_filter() is making ts->debounce_rep + 2
+ * reads. So we need to get all samples for normal case. */
+ packet->count = ts->debounce_rep + 2;
+ else
+ packet->count = 1;
+
+ if (ts->model == 7846)
+ packet->cmds = 5; /* x, y, z1, z2, pwdown */
+ else
+ packet->cmds = 3; /* x, y, pwdown */
+
+ for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+ unsigned int max_count;
+
+ if (cmd_idx == packet->cmds - 1)
+ cmd_idx = ADS7846_PWDOWN;
+
+ if (ads7846_cmd_need_settle(cmd_idx))
+ max_count = packet->count + packet->count_skip;
+ else
+ max_count = packet->count;
+
+ l->offset = offset;
+ offset += max_count;
+ l->count = max_count;
+ l->skip = packet->count_skip;
+ size += sizeof(*packet->tx) * max_count;
+ }
+
+ packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+ if (!packet->tx)
+ return -ENOMEM;
+
+ packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+ if (!packet->rx)
+ return -ENOMEM;
if (ts->model == 7873) {
/*
@@ -1005,181 +1106,25 @@
spi_message_init(m);
m->context = ts;
- if (ts->model == 7845) {
- packet->read_y_cmd[0] = READ_Y(vref);
- packet->read_y_cmd[1] = 0;
- packet->read_y_cmd[2] = 0;
- x->tx_buf = &packet->read_y_cmd[0];
- x->rx_buf = &packet->tc.y_buf[0];
- x->len = 3;
- spi_message_add_tail(x, m);
- } else {
- /* y- still on; turn on only y+ (and ADC) */
- packet->read_y = READ_Y(vref);
- x->tx_buf = &packet->read_y;
- x->len = 1;
- spi_message_add_tail(x, m);
+ for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+ u8 cmd;
- x++;
- x->rx_buf = &packet->tc.y;
- x->len = 2;
- spi_message_add_tail(x, m);
+ if (cmd_idx == packet->cmds - 1)
+ cmd_idx = ADS7846_PWDOWN;
+
+ cmd = ads7846_get_cmd(cmd_idx, vref);
+
+ for (b = 0; b < l->count; b++)
+ packet->tx[l->offset + b].cmd = cmd;
}
- /*
- * The first sample after switching drivers can be low quality;
- * optionally discard it, using a second one after the signals
- * have had enough time to stabilize.
- */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
-
- x++;
- x->tx_buf = &packet->read_y;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.y;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
-
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- if (ts->model == 7845) {
- x++;
- packet->read_x_cmd[0] = READ_X(vref);
- packet->read_x_cmd[1] = 0;
- packet->read_x_cmd[2] = 0;
- x->tx_buf = &packet->read_x_cmd[0];
- x->rx_buf = &packet->tc.x_buf[0];
- x->len = 3;
- spi_message_add_tail(x, m);
- } else {
- /* turn y- off, x+ on, then leave in lowpower */
- x++;
- packet->read_x = READ_X(vref);
- x->tx_buf = &packet->read_x;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.x;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
-
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
-
- x++;
- x->tx_buf = &packet->read_x;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.x;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
-
- /* turn y+ off, x- on; we'll use formula #2 */
- if (ts->model == 7846) {
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- x++;
- packet->read_z1 = READ_Z1(vref);
- x->tx_buf = &packet->read_z1;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.z1;
- x->len = 2;
- spi_message_add_tail(x, m);
-
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
-
- x++;
- x->tx_buf = &packet->read_z1;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.z1;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
-
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- x++;
- packet->read_z2 = READ_Z2(vref);
- x->tx_buf = &packet->read_z2;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.z2;
- x->len = 2;
- spi_message_add_tail(x, m);
-
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
-
- x++;
- x->tx_buf = &packet->read_z2;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.z2;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
- }
-
- /* power down */
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- if (ts->model == 7845) {
- x++;
- packet->pwrdown_cmd[0] = PWRDOWN;
- packet->pwrdown_cmd[1] = 0;
- packet->pwrdown_cmd[2] = 0;
- x->tx_buf = &packet->pwrdown_cmd[0];
- x->len = 3;
- } else {
- x++;
- packet->pwrdown = PWRDOWN;
- x->tx_buf = &packet->pwrdown;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->dummy;
- x->len = 2;
- }
-
- CS_CHANGE(*x);
+ x->tx_buf = packet->tx;
+ x->rx_buf = packet->rx;
+ x->len = size;
spi_message_add_tail(x, m);
+
+ return 0;
}
#ifdef CONFIG_OF
@@ -1198,6 +1143,7 @@
struct ads7846_platform_data *pdata;
struct device_node *node = dev->of_node;
const struct of_device_id *match;
+ u32 value;
if (!node) {
dev_err(dev, "Device does not have associated DT data\n");
@@ -1236,10 +1182,18 @@
of_property_read_u16(node, "ti,x-max", &pdata->x_max);
of_property_read_u16(node, "ti,y-max", &pdata->y_max);
+ /*
+ * touchscreen-max-pressure gets parsed during
+ * touchscreen_parse_properties()
+ */
of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min);
+ if (!of_property_read_u32(node, "touchscreen-min-pressure", &value))
+ pdata->pressure_min = (u16) value;
of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max);
of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max);
+ if (!of_property_read_u32(node, "touchscreen-average-samples", &value))
+ pdata->debounce_max = (u16) value;
of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
@@ -1322,10 +1276,7 @@
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
- ts->pressure_max = pdata->pressure_max ? : ~0;
-
ts->vref_mv = pdata->vref_mv;
- ts->swap_xy = pdata->swap_xy;
if (pdata->filter != NULL) {
if (pdata->filter_init != NULL) {
@@ -1374,8 +1325,26 @@
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min, pdata->pressure_max, 0, 0);
+ if (ts->model != 7845)
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+ /*
+ * Parse common framework properties. Must be done here to ensure the
+ * correct behaviour in case of using the legacy vendor bindings. The
+ * general binding value overrides the vendor specific one.
+ */
+ touchscreen_parse_properties(ts->input, false, &ts->core_prop);
+ ts->pressure_max = input_abs_get_max(input_dev, ABS_PRESSURE) ? : ~0;
+
+ /*
+ * Check if legacy ti,swap-xy binding is used instead of
+ * touchscreen-swapped-x-y
+ */
+ if (!ts->core_prop.swap_x_y && pdata->swap_xy) {
+ swap(input_dev->absinfo[ABS_X], input_dev->absinfo[ABS_Y]);
+ ts->core_prop.swap_x_y = true;
+ }
ads7846_setup_spi_msg(ts, pdata);
--
Gitblit v1.6.2