* [PATCH v2 0/2] Input/omap1: fix touchscreen functionality on Nokia 770
@ 2026-04-19 16:18 Aaro Koskinen
2026-04-19 16:18 ` [PATCH v2 1/2] Input: ads7846 - restore half-duplex support Aaro Koskinen
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Aaro Koskinen @ 2026-04-19 16:18 UTC (permalink / raw)
To: Dmitry Torokhov, Oleksij Rempel, Janusz Krzysztofik,
Tony Lindgren, Linus Walleij, linux-input
Cc: linux-kernel, linux-omap, Aaro Koskinen
Hi,
Another attempt to make 770 touchscreen work again.
v2: Unrelated fbdev patch dropped (already merged)
GPIO setup fixed by deleting the conflicting descriptor.
v1: https://lore.kernel.org/linux-input/20250102181953.1020878-1-aaro.koskinen@iki.fi/
Aaro Koskinen (2):
Input: ads7846 - restore half-duplex support
Input: ads7846 - fix up the pendown GPIO setup on Nokia 770
arch/arm/mach-omap1/board-nokia770.c | 11 --
drivers/input/touchscreen/ads7846.c | 180 +++++++++++++++++++++++++--
2 files changed, 173 insertions(+), 18 deletions(-)
--
2.39.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] Input: ads7846 - restore half-duplex support
2026-04-19 16:18 [PATCH v2 0/2] Input/omap1: fix touchscreen functionality on Nokia 770 Aaro Koskinen
@ 2026-04-19 16:18 ` Aaro Koskinen
2026-04-20 0:13 ` Dmitry Torokhov
2026-04-19 16:18 ` [PATCH v2 2/2] Input: ads7846 - fix up the pendown GPIO setup on Nokia 770 Aaro Koskinen
2026-04-19 20:10 ` [PATCH v2 0/2] Input/omap1: fix touchscreen functionality " Linus Walleij
2 siblings, 1 reply; 6+ messages in thread
From: Aaro Koskinen @ 2026-04-19 16:18 UTC (permalink / raw)
To: Dmitry Torokhov, Oleksij Rempel, Janusz Krzysztofik,
Tony Lindgren, Linus Walleij, linux-input
Cc: linux-kernel, linux-omap, Aaro Koskinen
On some boards, the SPI controller is limited to half-duplex and the driver
fails spamming "ads7846 spi2.1: spi_sync --> -22". Restore half-duplex
support with multiple SPI transfers.
Fixes: 9c9509717b53 ("Input: ads7846 - convert to full duplex")
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
---
drivers/input/touchscreen/ads7846.c | 168 +++++++++++++++++++++++++++-
1 file changed, 166 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 0963b1a78a0c..4f8cc450e779 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -134,6 +134,9 @@ struct ads7846 {
bool disabled; /* P: lock */
bool suspended; /* P: lock */
+ int (*setup_spi_msg)(struct ads7846 *ts,
+ const struct ads7846_platform_data *pdata);
+ void (*read_state)(struct ads7846 *ts);
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
int (*get_pendown_state)(void);
@@ -797,6 +800,22 @@ static int ads7846_filter(struct ads7846 *ts)
return 0;
}
+static int ads7846_filter_one(struct ads7846 *ts, unsigned int cmd_idx)
+{
+ struct ads7846_packet *packet = ts->packet;
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+ int action, val;
+
+ val = ads7846_get_value(&packet->rx[l->offset + l->count - 1]);
+ action = ts->filter(ts->filter_data, cmd_idx, &val);
+ if (action == ADS7846_FILTER_REPEAT)
+ return -EAGAIN;
+ else if (action != ADS7846_FILTER_OK)
+ return -EIO;
+ ads7846_set_cmd_val(ts, cmd_idx, val);
+ return 0;
+}
+
static void ads7846_wait_for_hsync(struct ads7846 *ts)
{
if (ts->wait_for_sync) {
@@ -819,6 +838,45 @@ static void ads7846_wait_for_hsync(struct ads7846 *ts)
cpu_relax();
}
+static void ads7846_halfd_read_state(struct ads7846 *ts)
+{
+ struct ads7846_packet *packet = ts->packet;
+ int msg_idx = 0;
+
+ packet->ignore = false;
+
+ while (msg_idx < ts->msg_count) {
+ int error;
+
+ ads7846_wait_for_hsync(ts);
+
+ error = spi_sync(ts->spi, &ts->msg[msg_idx]);
+ if (error) {
+ dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n",
+ error);
+ 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)
+ break;
+
+ error = ads7846_filter_one(ts, msg_idx);
+ if (error == -EAGAIN) {
+ continue;
+ } else if (error) {
+ packet->ignore = true;
+ msg_idx = ts->msg_count - 1;
+ } else {
+ msg_idx++;
+ }
+ }
+}
+
static void ads7846_read_state(struct ads7846 *ts)
{
struct ads7846_packet *packet = ts->packet;
@@ -947,7 +1005,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
while (!ts->stopped && get_pendown_state(ts)) {
/* pen is down, continue with the measurement */
- ads7846_read_state(ts);
+ ts->read_state(ts);
if (!ts->stopped)
ads7846_report_state(ts);
@@ -1034,6 +1092,102 @@ static int ads7846_setup_pendown(struct spi_device *spi,
return 0;
}
+/*
+ * Set up the transfers to read touchscreen state; this assumes we
+ * use formula #2 for pressure, not #3.
+ */
+static int ads7846_halfd_spi_msg(struct ads7846 *ts,
+ const struct ads7846_platform_data *pdata)
+{
+ struct spi_message *m = ts->msg;
+ struct spi_transfer *x = ts->xfer;
+ struct ads7846_packet *packet = ts->packet;
+ int vref = pdata->keep_vref_on;
+ unsigned int offset = 0;
+ unsigned int cmd_idx, b;
+ size_t size = 0;
+
+ if (pdata->settle_delay_usecs)
+ packet->count = 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;
+ max_count = 1;
+ } else {
+ max_count = packet->count;
+ }
+
+ l->offset = offset;
+ offset += max_count;
+ l->count = max_count;
+ l->skip = 0;
+ size += sizeof(*packet->rx) * max_count;
+ }
+
+ /* We use two transfers per command. */
+ if (ARRAY_SIZE(ts->xfer) < offset * 2)
+ return -ENOMEM;
+
+ packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+ if (!packet->rx)
+ return -ENOMEM;
+
+ if (ts->model == 7873) {
+ /*
+ * The AD7873 is almost identical to the ADS7846
+ * keep VREF off during differential/ratiometric
+ * conversion modes.
+ */
+ ts->model = 7846;
+ vref = 0;
+ }
+
+ ts->msg_count = 0;
+
+ for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+ u8 cmd;
+
+ ts->msg_count++;
+ spi_message_init(m);
+ m->context = ts;
+
+ 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->rx[l->offset + b].cmd = cmd;
+ x->tx_buf = &packet->rx[l->offset + b].cmd;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+ x++;
+ x->rx_buf = &packet->rx[l->offset + b].data;
+ x->len = 2;
+ if (b < l->count - 1 && l->count > 1) {
+ x->delay.value = pdata->settle_delay_usecs;
+ x->delay.unit = SPI_DELAY_UNIT_USECS;
+ }
+ spi_message_add_tail(x, m);
+ x++;
+ }
+ m++;
+ }
+ return 0;
+}
+
/*
* Set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
@@ -1248,6 +1402,14 @@ static int ads7846_probe(struct spi_device *spi)
if (!ts)
return -ENOMEM;
+ if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) {
+ ts->setup_spi_msg = ads7846_halfd_spi_msg;
+ ts->read_state = ads7846_halfd_read_state;
+ } else {
+ ts->setup_spi_msg = ads7846_setup_spi_msg;
+ ts->read_state = ads7846_read_state;
+ }
+
packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL);
if (!packet)
return -ENOMEM;
@@ -1342,7 +1504,9 @@ static int ads7846_probe(struct spi_device *spi)
ts->core_prop.swap_x_y = true;
}
- ads7846_setup_spi_msg(ts, pdata);
+ err = ts->setup_spi_msg(ts, pdata);
+ if (err)
+ return err;
ts->reg = devm_regulator_get(dev, "vcc");
if (IS_ERR(ts->reg)) {
--
2.39.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] Input: ads7846 - fix up the pendown GPIO setup on Nokia 770
2026-04-19 16:18 [PATCH v2 0/2] Input/omap1: fix touchscreen functionality on Nokia 770 Aaro Koskinen
2026-04-19 16:18 ` [PATCH v2 1/2] Input: ads7846 - restore half-duplex support Aaro Koskinen
@ 2026-04-19 16:18 ` Aaro Koskinen
2026-04-20 0:06 ` Dmitry Torokhov
2026-04-19 20:10 ` [PATCH v2 0/2] Input/omap1: fix touchscreen functionality " Linus Walleij
2 siblings, 1 reply; 6+ messages in thread
From: Aaro Koskinen @ 2026-04-19 16:18 UTC (permalink / raw)
To: Dmitry Torokhov, Oleksij Rempel, Janusz Krzysztofik,
Tony Lindgren, Linus Walleij, linux-input
Cc: linux-kernel, linux-omap, Aaro Koskinen
Commit 767d83361aaa6 ("Input: ads7846 - Convert to use software nodes")
added gpiod set up for the IRQ in the 770 board file, then another in
the touchscreen driver for reading the pen state. This will make the probe
fail:
[ 1.347381] ads7846 spi2.0: failed to request pendown GPIO
[ 1.361846] ads7846: probe of spi2.0 failed with error -16
I originally tried to fix it using non-exclusive flag, but that was not
found acceptable. Instead, just use a single gpiod.
Fixes: 767d83361aaa6 ("Input: ads7846 - Convert to use software nodes")
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
---
arch/arm/mach-omap1/board-nokia770.c | 11 -----------
drivers/input/touchscreen/ads7846.c | 12 +++++++-----
2 files changed, 7 insertions(+), 16 deletions(-)
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index a5bf5554800f..8b8013ab4590 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -285,9 +285,6 @@ static void __init nokia770_cbus_init(void)
static struct gpiod_lookup_table nokia770_irq_gpio_table = {
.dev_id = NULL,
.table = {
- /* GPIO used by SPI device 1 */
- GPIO_LOOKUP("gpio-0-15", 15, "ads7846_irq",
- GPIO_ACTIVE_HIGH),
/* GPIO used for retu IRQ */
GPIO_LOOKUP("gpio-48-63", 14, "retu_irq",
GPIO_ACTIVE_HIGH),
@@ -307,8 +304,6 @@ static struct gpiod_lookup_table nokia770_irq_gpio_table = {
static void __init omap_nokia770_init(void)
{
- struct gpio_desc *d;
-
/* On Nokia 770, the SleepX signal is masked with an
* MPUIO line by default. It has to be unmasked for it
* to become functional */
@@ -322,12 +317,6 @@ static void __init omap_nokia770_init(void)
platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
gpiod_add_lookup_table(&nokia770_irq_gpio_table);
- d = gpiod_get(NULL, "ads7846_irq", GPIOD_IN);
- if (IS_ERR(d))
- pr_err("Unable to get ADS7846 IRQ GPIO descriptor\n");
- else
- nokia770_spi_board_info[1].irq = gpiod_to_irq(d);
-
spi_register_board_info(nokia770_spi_board_info,
ARRAY_SIZE(nokia770_spi_board_info));
omap_serial_init();
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 4f8cc450e779..ca7dbd3afe29 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1084,6 +1084,8 @@ static int ads7846_setup_pendown(struct spi_device *spi,
dev_err(&spi->dev, "failed to request pendown GPIO\n");
return PTR_ERR(ts->gpio_pendown);
}
+ if (!spi->irq)
+ spi->irq = gpiod_to_irq(ts->gpio_pendown);
if (pdata->gpio_pendown_debounce)
gpiod_set_debounce(ts->gpio_pendown,
pdata->gpio_pendown_debounce);
@@ -1374,11 +1376,6 @@ static int ads7846_probe(struct spi_device *spi)
unsigned long irq_flags;
int err;
- if (!spi->irq) {
- dev_dbg(dev, "no IRQ?\n");
- return -EINVAL;
- }
-
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_err(dev, "f(sample) %d KHz?\n",
@@ -1455,6 +1452,11 @@ static int ads7846_probe(struct spi_device *spi)
if (err)
return err;
+ if (!spi->irq) {
+ dev_dbg(dev, "no IRQ?\n");
+ return -EINVAL;
+ }
+
if (pdata->penirq_recheck_delay_usecs)
ts->penirq_recheck_delay_usecs =
pdata->penirq_recheck_delay_usecs;
--
2.39.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] Input/omap1: fix touchscreen functionality on Nokia 770
2026-04-19 16:18 [PATCH v2 0/2] Input/omap1: fix touchscreen functionality on Nokia 770 Aaro Koskinen
2026-04-19 16:18 ` [PATCH v2 1/2] Input: ads7846 - restore half-duplex support Aaro Koskinen
2026-04-19 16:18 ` [PATCH v2 2/2] Input: ads7846 - fix up the pendown GPIO setup on Nokia 770 Aaro Koskinen
@ 2026-04-19 20:10 ` Linus Walleij
2 siblings, 0 replies; 6+ messages in thread
From: Linus Walleij @ 2026-04-19 20:10 UTC (permalink / raw)
To: Aaro Koskinen
Cc: Dmitry Torokhov, Oleksij Rempel, Janusz Krzysztofik,
Tony Lindgren, linux-input, linux-kernel, linux-omap
On Sun, Apr 19, 2026 at 6:21 PM Aaro Koskinen <aaro.koskinen@iki.fi> wrote:
> Another attempt to make 770 touchscreen work again.
>
> v2: Unrelated fbdev patch dropped (already merged)
> GPIO setup fixed by deleting the conflicting descriptor.
>
> v1: https://lore.kernel.org/linux-input/20250102181953.1020878-1-aaro.koskinen@iki.fi/
>
> Aaro Koskinen (2):
> Input: ads7846 - restore half-duplex support
> Input: ads7846 - fix up the pendown GPIO setup on Nokia 770
Patches look good to me!
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] Input: ads7846 - fix up the pendown GPIO setup on Nokia 770
2026-04-19 16:18 ` [PATCH v2 2/2] Input: ads7846 - fix up the pendown GPIO setup on Nokia 770 Aaro Koskinen
@ 2026-04-20 0:06 ` Dmitry Torokhov
0 siblings, 0 replies; 6+ messages in thread
From: Dmitry Torokhov @ 2026-04-20 0:06 UTC (permalink / raw)
To: Aaro Koskinen
Cc: Oleksij Rempel, Janusz Krzysztofik, Tony Lindgren, Linus Walleij,
linux-input, linux-kernel, linux-omap
Hi Aaro,
On Sun, Apr 19, 2026 at 07:18:48PM +0300, Aaro Koskinen wrote:
> Commit 767d83361aaa6 ("Input: ads7846 - Convert to use software nodes")
> added gpiod set up for the IRQ in the 770 board file, then another in
> the touchscreen driver for reading the pen state. This will make the probe
> fail:
>
> [ 1.347381] ads7846 spi2.0: failed to request pendown GPIO
> [ 1.361846] ads7846: probe of spi2.0 failed with error -16
>
> I originally tried to fix it using non-exclusive flag, but that was not
> found acceptable. Instead, just use a single gpiod.
>
> Fixes: 767d83361aaa6 ("Input: ads7846 - Convert to use software nodes")
> Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
> ---
> arch/arm/mach-omap1/board-nokia770.c | 11 -----------
> drivers/input/touchscreen/ads7846.c | 12 +++++++-----
> 2 files changed, 7 insertions(+), 16 deletions(-)
>
> diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
> index a5bf5554800f..8b8013ab4590 100644
> --- a/arch/arm/mach-omap1/board-nokia770.c
> +++ b/arch/arm/mach-omap1/board-nokia770.c
> @@ -285,9 +285,6 @@ static void __init nokia770_cbus_init(void)
> static struct gpiod_lookup_table nokia770_irq_gpio_table = {
> .dev_id = NULL,
> .table = {
> - /* GPIO used by SPI device 1 */
> - GPIO_LOOKUP("gpio-0-15", 15, "ads7846_irq",
> - GPIO_ACTIVE_HIGH),
> /* GPIO used for retu IRQ */
> GPIO_LOOKUP("gpio-48-63", 14, "retu_irq",
> GPIO_ACTIVE_HIGH),
> @@ -307,8 +304,6 @@ static struct gpiod_lookup_table nokia770_irq_gpio_table = {
>
> static void __init omap_nokia770_init(void)
> {
> - struct gpio_desc *d;
> -
> /* On Nokia 770, the SleepX signal is masked with an
> * MPUIO line by default. It has to be unmasked for it
> * to become functional */
> @@ -322,12 +317,6 @@ static void __init omap_nokia770_init(void)
> platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
>
> gpiod_add_lookup_table(&nokia770_irq_gpio_table);
> - d = gpiod_get(NULL, "ads7846_irq", GPIOD_IN);
> - if (IS_ERR(d))
> - pr_err("Unable to get ADS7846 IRQ GPIO descriptor\n");
> - else
> - nokia770_spi_board_info[1].irq = gpiod_to_irq(d);
No, I think what we need here is a simple gpiod_put(). The mapping is
not going to change unless someone tries to unload gpiochip, but then
the device is not going to work anyway.
Longer term we need to figure out how to describe interrupts with
software nodes (or wait long enough for everything to get converted to
device tree).
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] Input: ads7846 - restore half-duplex support
2026-04-19 16:18 ` [PATCH v2 1/2] Input: ads7846 - restore half-duplex support Aaro Koskinen
@ 2026-04-20 0:13 ` Dmitry Torokhov
0 siblings, 0 replies; 6+ messages in thread
From: Dmitry Torokhov @ 2026-04-20 0:13 UTC (permalink / raw)
To: Aaro Koskinen
Cc: Oleksij Rempel, Janusz Krzysztofik, Tony Lindgren, Linus Walleij,
linux-input, linux-kernel, linux-omap
Hi Aaro,
On Sun, Apr 19, 2026 at 07:18:47PM +0300, Aaro Koskinen wrote:
> +static void ads7846_halfd_read_state(struct ads7846 *ts)
> +{
> + struct ads7846_packet *packet = ts->packet;
> + int msg_idx = 0;
> +
> + packet->ignore = false;
> +
> + while (msg_idx < ts->msg_count) {
> + int error;
> +
> + ads7846_wait_for_hsync(ts);
> +
> + error = spi_sync(ts->spi, &ts->msg[msg_idx]);
> + if (error) {
> + dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n",
> + error);
> + packet->ignore = true;
> + return;
Sashiko recommends trying to power down ADC on errors, what do you
think?
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-20 0:14 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-19 16:18 [PATCH v2 0/2] Input/omap1: fix touchscreen functionality on Nokia 770 Aaro Koskinen
2026-04-19 16:18 ` [PATCH v2 1/2] Input: ads7846 - restore half-duplex support Aaro Koskinen
2026-04-20 0:13 ` Dmitry Torokhov
2026-04-19 16:18 ` [PATCH v2 2/2] Input: ads7846 - fix up the pendown GPIO setup on Nokia 770 Aaro Koskinen
2026-04-20 0:06 ` Dmitry Torokhov
2026-04-19 20:10 ` [PATCH v2 0/2] Input/omap1: fix touchscreen functionality " Linus Walleij
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox