* [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791
@ 2026-10-11 12:44 Lukas Timmermann
2026-10-11 12:44 ` [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO Lukas Timmermann
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Lukas Timmermann @ 2026-10-11 12:44 UTC (permalink / raw)
To: Lukas Timmermann, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin,
André Draszik, Tudor Ambarus, Alim Akhtar
Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel,
linux-samsung-soc
This series adds SPI support to S6SY761 touch controllers, specifically
S6SY791 devices. Also included are the necessary adjustments in the DTS
for the Google Pixel 6 Pro (raven) which uses the aforementioned SPI
version. As the mentioned board has a reset line wired, I also added that
functionality to the bindings and driver. To implement SPI versions
cleanly, the driver was split into core and bus transfer modules like
seen in other drivers.
This series was successfully tested with a Google Pixel 6 Pro. The I2C
transfer part was untested because I don't have a device with an
S6SY761 controller.
Known issue: on gs101 the touchscreen probe at boot fails with -EIO
because the very first SPI transfer is not understood by the controller
(the reply is all zeros); rebinding the driver works. This looks like
spi-s3c64xx applying CPOL/CPHA only in transfer_one(), after chip
select has been asserted, but I have not verified this further. It is
not addressed by this series.
Patches 1-4 and 7 are meant for the input tree, patches 5-6 for the
Samsung SoC tree. The DTS patches depend on the binding in patch 1.
---
Lukas Timmermann (7):
dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO
Input: s6sy761 - split into core and I2C modules
Input: s6sy761 - add reset GPIO support
Input: s6sy761 - add SPI support for S6SY791
arm64: dts: exynos: gs101-pixel-common: add labels for touchscreen supplies
arm64: dts: exynos: gs101-raven: add S6SY791 touchscreen
MAINTAINERS: add entry for Samsung S6SY761 touchscreen driver
.../input/touchscreen/samsung,s6sy761.yaml | 37 +++-
MAINTAINERS | 7 +
.../boot/dts/exynos/google/gs101-pixel-common.dtsi | 4 +-
arch/arm64/boot/dts/exynos/google/gs101-raven.dts | 50 +++++
drivers/input/touchscreen/Kconfig | 20 +-
drivers/input/touchscreen/Makefile | 4 +-
.../touchscreen/{s6sy761.c => s6sy761_core.c} | 226 ++++++++++-----------
drivers/input/touchscreen/s6sy761_core.h | 34 ++++
drivers/input/touchscreen/s6sy761_i2c.c | 112 ++++++++++
drivers/input/touchscreen/s6sy761_spi.c | 172 ++++++++++++++++
10 files changed, 534 insertions(+), 132 deletions(-)
---
base-commit: 3857c2fe5449541e24afc5efdb0f81a8a8f9a3a0
change-id: 20261011-lat3st-google-raven-touch-upstream-f19acd121f2c
Best regards,
--
Lukas Timmermann <foss@timmermann.space>
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann @ 2026-10-11 12:44 ` Lukas Timmermann 2026-10-12 11:30 ` Krzysztof Kozlowski 2026-10-11 12:44 ` [PATCH 2/7] Input: s6sy761 - split into core and I2C modules Lukas Timmermann ` (5 subsequent siblings) 6 siblings, 1 reply; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:44 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc S6SY791 is the SPI-based counterpart of S6SY761. The register map and commands are identical for the subset the kernel currently implements. Therefore add S6SY791 as a related touch controller. Optionally, the reset line can be controlled on some boards, such as the Google Pixel 6 Pro (raven). Also reference spi-peripheral-props for the SPI bus properties. Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- .../input/touchscreen/samsung,s6sy761.yaml | 37 +++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml index 1ffd17af3c53..d24f35038934 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml @@ -8,13 +8,17 @@ title: Samsung S6SY761 touchscreen controller maintainers: - Andi Shyti <andi.shyti@kernel.org> + - Lukas Timmermann <foss@timmermann.space> allOf: - $ref: touchscreen.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: compatible: - const: samsung,s6sy761 + enum: + - samsung,s6sy761 + - samsung,s6sy791 reg: maxItems: 1 @@ -22,9 +26,19 @@ properties: interrupts: maxItems: 1 + reset-gpios: + maxItems: 1 + description: GPIO connected to the reset pin of the controller + avdd-supply: true vdd-supply: true + spi-max-frequency: true + + spi-cpha: true + + spi-cpol: true + unevaluatedProperties: false required: @@ -52,3 +66,24 @@ examples: touchscreen-size-y = <4096>; }; }; + + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@0 { + compatible = "samsung,s6sy791"; + reg = <0>; + spi-max-frequency = <10000000>; + spi-cpol; + spi-cpha; + interrupt-parent = <&gpa9>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpp26 0 GPIO_ACTIVE_LOW>; + avdd-supply = <&ldo26_reg>; + vdd-supply = <&ldo25_reg>; + }; + }; -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO 2026-10-11 12:44 ` [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO Lukas Timmermann @ 2026-10-12 11:30 ` Krzysztof Kozlowski 0 siblings, 0 replies; 10+ messages in thread From: Krzysztof Kozlowski @ 2026-10-12 11:30 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc On 11/10/2026 14:44, Lukas Timmermann wrote: > S6SY791 is the SPI-based counterpart of S6SY761. The register map and > commands are identical for the subset the kernel currently implements. > Therefore add S6SY791 as a related touch controller. > > Optionally, the reset line can be controlled on some boards, > such as the Google Pixel 6 Pro (raven). > > Also reference spi-peripheral-props for the SPI bus properties. > > Signed-off-by: Lukas Timmermann <foss@timmermann.space> > --- > .../input/touchscreen/samsung,s6sy761.yaml | 37 +++++++++++++++++++++- > 1 file changed, 36 insertions(+), 1 deletion(-) > > diff --git a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml > index 1ffd17af3c53..d24f35038934 100644 > --- a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml > +++ b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml > @@ -8,13 +8,17 @@ title: Samsung S6SY761 touchscreen controller > > maintainers: > - Andi Shyti <andi.shyti@kernel.org> > + - Lukas Timmermann <foss@timmermann.space> > > allOf: > - $ref: touchscreen.yaml# > + - $ref: /schemas/spi/spi-peripheral-props.yaml# > > properties: > compatible: > - const: samsung,s6sy761 > + enum: > + - samsung,s6sy761 > + - samsung,s6sy791 > > reg: > maxItems: 1 > @@ -22,9 +26,19 @@ properties: > interrupts: > maxItems: 1 > > + reset-gpios: > + maxItems: 1 > + description: GPIO connected to the reset pin of the controller > + > avdd-supply: true > vdd-supply: true > > + spi-max-frequency: true Drop > + > + spi-cpha: true > + > + spi-cpol: true These two should be probably required for the new device. > + > unevaluatedProperties: false > > required: Best regards, Krzysztof ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/7] Input: s6sy761 - split into core and I2C modules 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann 2026-10-11 12:44 ` [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO Lukas Timmermann @ 2026-10-11 12:44 ` Lukas Timmermann 2026-10-12 11:04 ` Uwe Kleine-König 2026-10-11 12:44 ` [PATCH 3/7] Input: s6sy761 - add reset GPIO support Lukas Timmermann ` (4 subsequent siblings) 6 siblings, 1 reply; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:44 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc Split this driver into a bus-agnostic core and I2C transport part in preparation for adding SPI support. Also add a mutex because the driver now has a transfer buffer shared between IRQ, sysfs and PM threads. The Kconfig is backwards-compatible and should work on boards with an S6SY761 touchscreen as before. The I2C transfers of the driver should be byte by byte identical. The modules are now called s6sy761_core and s6sy761_i2c. Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- drivers/input/touchscreen/Kconfig | 8 +- drivers/input/touchscreen/Makefile | 3 +- .../touchscreen/{s6sy761.c => s6sy761_core.c} | 214 +++++++++------------ drivers/input/touchscreen/s6sy761_core.h | 34 ++++ drivers/input/touchscreen/s6sy761_i2c.c | 112 +++++++++++ 5 files changed, 245 insertions(+), 126 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 9b9ae8ac3f7f..76651a61324f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -535,8 +535,12 @@ config TOUCHSCREEN_S6SY761 If unsure, say N - To compile this driver as module, choose M here: the - module will be called s6sy761. + To compile this driver as a module, choose M here: the + modules will be called s6sy761_core and s6sy761_i2c. + select TOUCHSCREEN_S6SY761_I2C if I2C + +config TOUCHSCREEN_S6SY761_I2C + tristate config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index bfd9de83389d..24b8fb1e38d3 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -77,7 +77,8 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o -obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o +obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761_core.o +obj-$(CONFIG_TOUCHSCREEN_S6SY761_I2C) += s6sy761_i2c.o obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761_core.c similarity index 71% rename from drivers/input/touchscreen/s6sy761.c rename to drivers/input/touchscreen/s6sy761_core.c index 899c179fb2d3..0e455060dbc0 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761_core.c @@ -3,18 +3,21 @@ // // Copyright (c) 2017 Samsung Electronics Co., Ltd. // Copyright (c) 2017 Andi Shyti <andi@etezian.org> +// Copyright (c) 2026 Lukas Timmermann <foss@timmermann.space> #include <linux/unaligned.h> #include <linux/delay.h> -#include <linux/i2c.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include "s6sy761_core.h" + /* commands */ #define S6SY761_SENSE_ON 0x10 #define S6SY761_SENSE_OFF 0x11 @@ -84,22 +87,18 @@ #define S6SY761_APP_FLASH 0x3 #define S6SY761_APP_SLEEP 0x4 -#define S6SY761_EVENT_SIZE 8 -#define S6SY761_EVENT_COUNT 32 #define S6SY761_DEVID_SIZE 3 #define S6SY761_PANEL_ID_SIZE 11 #define S6SY761_TS_STATUS_SIZE 5 #define S6SY761_MAX_FINGERS 10 -#define S6SY761_DEV_NAME "s6sy761" - -enum s6sy761_regulators { - S6SY761_REGULATOR_VDD, - S6SY761_REGULATOR_AVDD, -}; - struct s6sy761_data { - struct i2c_client *client; + struct device *dev; + const struct s6sy761_bus_ops *bus_ops; + u8 *xfer_buf; + /* serializes bus access and protects xfer_buf */ + struct mutex xfer_lock; + int irq; struct regulator_bulk_data regulators[2]; struct input_dev *input; struct touchscreen_properties prop; @@ -110,33 +109,21 @@ struct s6sy761_data { u8 tx_channel; }; -/* - * We can't simply use i2c_smbus_read_i2c_block_data because we - * need to read more than 255 bytes - */ -static int s6sy761_read_events(struct s6sy761_data *sdata, u16 n_events) -{ - u8 cmd = S6SY761_READ_ALL_EVENT; - struct i2c_msg msgs[2] = { - { - .addr = sdata->client->addr, - .len = 1, - .buf = &cmd, - }, - { - .addr = sdata->client->addr, - .flags = I2C_M_RD, - .len = (n_events * S6SY761_EVENT_SIZE), - .buf = sdata->data + S6SY761_EVENT_SIZE, - }, - }; - int ret; +enum s6sy761_regulators { + S6SY761_REGULATOR_VDD, + S6SY761_REGULATOR_AVDD, +}; - ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - return ret; +static int s6sy761_read(struct s6sy761_data *sdata, u8 cmd, size_t len, void *buf) +{ + guard(mutex)(&sdata->xfer_lock); + return sdata->bus_ops->read(sdata->dev, sdata->xfer_buf, cmd, len, buf); +} - return ret == ARRAY_SIZE(msgs) ? 0 : -EIO; +static int s6sy761_write(struct s6sy761_data *sdata, u8 cmd, size_t len, const void *buf) +{ + guard(mutex)(&sdata->xfer_lock); + return sdata->bus_ops->write(sdata->dev, sdata->xfer_buf, cmd, len, buf); } static void s6sy761_report_coordinates(struct s6sy761_data *sdata, @@ -226,12 +213,10 @@ static irqreturn_t s6sy761_irq_handler(int irq, void *dev) int ret; u8 n_events; - ret = i2c_smbus_read_i2c_block_data(sdata->client, - S6SY761_READ_ONE_EVENT, - S6SY761_EVENT_SIZE, - sdata->data); + ret = s6sy761_read(sdata, S6SY761_READ_ONE_EVENT, + S6SY761_EVENT_SIZE, sdata->data); if (ret < 0) { - dev_err(&sdata->client->dev, "failed to read events\n"); + dev_err(sdata->dev, "failed to read events\n"); return IRQ_HANDLED; } @@ -243,9 +228,11 @@ static irqreturn_t s6sy761_irq_handler(int irq, void *dev) return IRQ_HANDLED; if (n_events) { - ret = s6sy761_read_events(sdata, n_events); + ret = s6sy761_read(sdata, S6SY761_READ_ALL_EVENT, + n_events * S6SY761_EVENT_SIZE, + sdata->data + S6SY761_EVENT_SIZE); if (ret < 0) { - dev_err(&sdata->client->dev, "failed to read events\n"); + dev_err(sdata->dev, "failed to read events\n"); return IRQ_HANDLED; } } @@ -259,7 +246,7 @@ static int s6sy761_input_open(struct input_dev *dev) { struct s6sy761_data *sdata = input_get_drvdata(dev); - return i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON); + return s6sy761_write(sdata, S6SY761_SENSE_ON, 0, NULL); } static void s6sy761_input_close(struct input_dev *dev) @@ -267,9 +254,9 @@ static void s6sy761_input_close(struct input_dev *dev) struct s6sy761_data *sdata = input_get_drvdata(dev); int ret; - ret = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_OFF); + ret = s6sy761_write(sdata, S6SY761_SENSE_OFF, 0, NULL); if (ret) - dev_err(&sdata->client->dev, "failed to turn off sensing\n"); + dev_err(sdata->dev, "failed to turn off sensing\n"); } static ssize_t s6sy761_sysfs_devid(struct device *dev, @@ -286,12 +273,23 @@ static struct attribute *s6sy761_sysfs_attrs[] = { &dev_attr_devid.attr, NULL }; -ATTRIBUTE_GROUPS(s6sy761_sysfs); + +static const struct attribute_group s6sy761_sysfs_group = { + .attrs = s6sy761_sysfs_attrs, +}; + +const struct attribute_group *s6sy761_sysfs_groups[] = { + &s6sy761_sysfs_group, + NULL, +}; +EXPORT_SYMBOL_NS_GPL(s6sy761_sysfs_groups, "S6SY761"); static int s6sy761_power_on(struct s6sy761_data *sdata) { + __le16 touch_func; u8 buffer[S6SY761_EVENT_SIZE]; u8 event; + u8 status; int ret; ret = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators), @@ -302,10 +300,7 @@ static int s6sy761_power_on(struct s6sy761_data *sdata) msleep(140); /* double check whether the touch is functional */ - ret = i2c_smbus_read_i2c_block_data(sdata->client, - S6SY761_READ_ONE_EVENT, - S6SY761_EVENT_SIZE, - buffer); + ret = s6sy761_read(sdata, S6SY761_READ_ONE_EVENT, S6SY761_EVENT_SIZE, buffer); if (ret < 0) return ret; @@ -317,18 +312,17 @@ static int s6sy761_power_on(struct s6sy761_data *sdata) return -ENODEV; } - ret = i2c_smbus_read_byte_data(sdata->client, S6SY761_BOOT_STATUS); + ret = s6sy761_read(sdata, S6SY761_BOOT_STATUS, 1, &status); if (ret < 0) return ret; /* for some reasons the device might be stuck in the bootloader */ - if (ret != S6SY761_BS_APPLICATION) + if (status != S6SY761_BS_APPLICATION) return -ENODEV; /* enable touch functionality */ - ret = i2c_smbus_write_word_data(sdata->client, - S6SY761_TOUCH_FUNCTION, - S6SY761_MASK_TOUCH); + touch_func = cpu_to_le16(S6SY761_MASK_TOUCH); + ret = s6sy761_write(sdata, S6SY761_TOUCH_FUNCTION, sizeof(touch_func), &touch_func); if (ret) return ret; @@ -339,25 +333,20 @@ static int s6sy761_hw_init(struct s6sy761_data *sdata, unsigned int *max_x, unsigned int *max_y) { u8 buffer[S6SY761_PANEL_ID_SIZE]; /* larger read size */ + u8 integrity; int ret; ret = s6sy761_power_on(sdata); if (ret) return ret; - ret = i2c_smbus_read_i2c_block_data(sdata->client, - S6SY761_DEVICE_ID, - S6SY761_DEVID_SIZE, - buffer); + ret = s6sy761_read(sdata, S6SY761_DEVICE_ID, S6SY761_DEVID_SIZE, buffer); if (ret < 0) return ret; sdata->devid = get_unaligned_be16(buffer + 1); - ret = i2c_smbus_read_i2c_block_data(sdata->client, - S6SY761_PANEL_INFO, - S6SY761_PANEL_ID_SIZE, - buffer); + ret = s6sy761_read(sdata, S6SY761_PANEL_INFO, S6SY761_PANEL_ID_SIZE, buffer); if (ret < 0) return ret; @@ -367,11 +356,10 @@ static int s6sy761_hw_init(struct s6sy761_data *sdata, /* if no tx channels defined, at least keep one */ sdata->tx_channel = max_t(u8, buffer[8], 1); - ret = i2c_smbus_read_byte_data(sdata->client, - S6SY761_FIRMWARE_INTEGRITY); + ret = s6sy761_read(sdata, S6SY761_FIRMWARE_INTEGRITY, 1, &integrity); if (ret < 0) return ret; - else if (ret != S6SY761_FW_OK) + else if (integrity != S6SY761_FW_OK) return -ENODEV; return 0; @@ -381,38 +369,44 @@ static void s6sy761_power_off(void *data) { struct s6sy761_data *sdata = data; - disable_irq(sdata->client->irq); + disable_irq(sdata->irq); regulator_bulk_disable(ARRAY_SIZE(sdata->regulators), sdata->regulators); } -static int s6sy761_probe(struct i2c_client *client) +int s6sy761_probe(struct device *dev, const struct s6sy761_bus_ops *bus_ops, int irq) { struct s6sy761_data *sdata; unsigned int max_x, max_y; int err; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) - return -ENODEV; - - sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL); + sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); if (!sdata) return -ENOMEM; - i2c_set_clientdata(client, sdata); - sdata->client = client; + sdata->xfer_buf = devm_kzalloc(dev, S6SY761_XFER_BUFFER_SIZE, GFP_KERNEL); + if (!sdata->xfer_buf) + return -ENOMEM; + + dev_set_drvdata(dev, sdata); + + sdata->bus_ops = bus_ops; + sdata->dev = dev; + sdata->irq = irq; + + err = devm_mutex_init(dev, &sdata->xfer_lock); + if (err) + return err; sdata->regulators[S6SY761_REGULATOR_VDD].supply = "vdd"; sdata->regulators[S6SY761_REGULATOR_AVDD].supply = "avdd"; - err = devm_regulator_bulk_get(&client->dev, + err = devm_regulator_bulk_get(dev, ARRAY_SIZE(sdata->regulators), sdata->regulators); if (err) return err; - err = devm_add_action_or_reset(&client->dev, s6sy761_power_off, sdata); + err = devm_add_action_or_reset(dev, s6sy761_power_off, sdata); if (err) return err; @@ -420,12 +414,12 @@ static int s6sy761_probe(struct i2c_client *client) if (err) return err; - sdata->input = devm_input_allocate_device(&client->dev); + sdata->input = devm_input_allocate_device(dev); if (!sdata->input) return -ENOMEM; sdata->input->name = S6SY761_DEV_NAME; - sdata->input->id.bustype = BUS_I2C; + sdata->input->id.bustype = bus_ops->bustype; sdata->input->open = s6sy761_input_open; sdata->input->close = s6sy761_input_close; @@ -441,7 +435,7 @@ static int s6sy761_probe(struct i2c_client *client) if (!input_abs_get_max(sdata->input, ABS_X) || !input_abs_get_max(sdata->input, ABS_Y)) { - dev_warn(&client->dev, "the axis have not been set\n"); + dev_warn(dev, "the axis have not been set\n"); } err = input_mt_init_slots(sdata->input, sdata->tx_channel, @@ -455,37 +449,39 @@ static int s6sy761_probe(struct i2c_client *client) if (err) return err; - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + err = devm_request_threaded_irq(dev, sdata->irq, NULL, s6sy761_irq_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "s6sy761_irq", sdata); if (err) return err; - pm_runtime_enable(&client->dev); + pm_runtime_enable(dev); return 0; } +EXPORT_SYMBOL_NS_GPL(s6sy761_probe, "S6SY761"); -static void s6sy761_remove(struct i2c_client *client) +void s6sy761_remove(struct device *dev) { - pm_runtime_disable(&client->dev); + pm_runtime_disable(dev); } +EXPORT_SYMBOL_NS_GPL(s6sy761_remove, "S6SY761"); static int s6sy761_runtime_suspend(struct device *dev) { struct s6sy761_data *sdata = dev_get_drvdata(dev); + u8 mode = S6SY761_APP_SLEEP; - return i2c_smbus_write_byte_data(sdata->client, - S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP); + return s6sy761_write(sdata, S6SY761_APPLICATION_MODE, 1, &mode); } static int s6sy761_runtime_resume(struct device *dev) { struct s6sy761_data *sdata = dev_get_drvdata(dev); + u8 mode = S6SY761_APP_NORMAL; - return i2c_smbus_write_byte_data(sdata->client, - S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL); + return s6sy761_write(sdata, S6SY761_APPLICATION_MODE, 1, &mode); } static int s6sy761_suspend(struct device *dev) @@ -506,51 +502,23 @@ static int s6sy761_resume(struct device *dev) if (err) return err; - enable_irq(sdata->client->irq); + enable_irq(sdata->irq); guard(mutex)(&sdata->input->mutex); if (!input_device_enabled(sdata->input)) return 0; - err = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON); + err = s6sy761_write(sdata, S6SY761_SENSE_ON, 0, NULL); return err; } -static const struct dev_pm_ops s6sy761_pm_ops = { +EXPORT_NS_GPL_DEV_PM_OPS(s6sy761_pm_ops, S6SY761) = { SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume) RUNTIME_PM_OPS(s6sy761_runtime_suspend, s6sy761_runtime_resume, NULL) }; -#ifdef CONFIG_OF -static const struct of_device_id s6sy761_of_match[] = { - { .compatible = "samsung,s6sy761", }, - { }, -}; -MODULE_DEVICE_TABLE(of, s6sy761_of_match); -#endif - -static const struct i2c_device_id s6sy761_id[] = { - { .name = "s6sy761" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, s6sy761_id); - -static struct i2c_driver s6sy761_driver = { - .driver = { - .name = S6SY761_DEV_NAME, - .dev_groups = s6sy761_sysfs_groups, - .of_match_table = of_match_ptr(s6sy761_of_match), - .pm = pm_ptr(&s6sy761_pm_ops), - }, - .probe = s6sy761_probe, - .remove = s6sy761_remove, - .id_table = s6sy761_id, -}; - -module_i2c_driver(s6sy761_driver); - MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); -MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/s6sy761_core.h b/drivers/input/touchscreen/s6sy761_core.h new file mode 100644 index 000000000000..059cd5a36a34 --- /dev/null +++ b/drivers/input/touchscreen/s6sy761_core.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _S6SY761_H +#define _S6SY761_H + +#include <linux/align.h> +#include <linux/types.h> + +#define S6SY761_EVENT_SIZE 8 +#define S6SY761_EVENT_COUNT 32 +/* largest SPI read: reply header + all events + checksum */ +#define S6SY761_XFER_BUFFER_SIZE ALIGN(7 + S6SY761_EVENT_SIZE * S6SY761_EVENT_COUNT + 1, 4) + +#define S6SY761_DEV_NAME "s6sy761" + +struct device; +struct dev_pm_ops; +struct attribute_group; + +struct s6sy761_bus_ops { + u16 bustype; + int (*write)(struct device *dev, u8 *xfer_buf, + u8 cmd, size_t length, const void *values); + int (*read)(struct device *dev, u8 *xfer_buf, + u8 cmd, size_t length, void *values); +}; + +extern const struct dev_pm_ops s6sy761_pm_ops; + +extern const struct attribute_group *s6sy761_sysfs_groups[]; + +int s6sy761_probe(struct device *dev, const struct s6sy761_bus_ops *bus_ops, int irq); +void s6sy761_remove(struct device *dev); + +#endif diff --git a/drivers/input/touchscreen/s6sy761_i2c.c b/drivers/input/touchscreen/s6sy761_i2c.c new file mode 100644 index 000000000000..b5cbebfd722a --- /dev/null +++ b/drivers/input/touchscreen/s6sy761_i2c.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +// Samsung S6SY761 I2C Touchscreen device driver +// +// Copyright (c) 2017 Samsung Electronics Co., Ltd. +// Copyright (c) 2017 Andi Shyti <andi@etezian.org> +// Copyright (c) 2026 Lukas Timmermann <foss@timmermann.space> + +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> + +#include "s6sy761_core.h" + +static int s6sy761_i2c_write(struct device *dev, u8 *xfer_buf, + u8 cmd, size_t length, const void *values) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret; + + if (length + 1 > S6SY761_XFER_BUFFER_SIZE) + return -EINVAL; + + xfer_buf[0] = cmd; + + if (length) + memcpy(xfer_buf + 1, values, length); + + ret = i2c_master_send(client, xfer_buf, length + 1); + if (ret < 0) + return ret; + if (ret != length + 1) + return -EIO; + + return 0; +} + +static int s6sy761_i2c_read(struct device *dev, u8 *xfer_buf, + u8 cmd, size_t length, void *values) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .len = 1, + .buf = &cmd, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = values, + }, + }; + int ret; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + + return ret == ARRAY_SIZE(msgs) ? 0 : -EIO; +} + +static const struct s6sy761_bus_ops s6sy761_i2c_bus_ops = { + .bustype = BUS_I2C, + .read = s6sy761_i2c_read, + .write = s6sy761_i2c_write, +}; + +static int s6sy761_i2c_probe(struct i2c_client *client) +{ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + return s6sy761_probe(&client->dev, &s6sy761_i2c_bus_ops, client->irq); +} + +static void s6sy761_i2c_remove(struct i2c_client *client) +{ + s6sy761_remove(&client->dev); +} + +static const struct of_device_id s6sy761_of_match[] = { + { .compatible = "samsung,s6sy761", }, + { }, +}; +MODULE_DEVICE_TABLE(of, s6sy761_of_match); + +static const struct i2c_device_id s6sy761_id[] = { + { "s6sy761" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, s6sy761_id); + +static struct i2c_driver s6sy761_driver = { + .driver = { + .name = S6SY761_DEV_NAME, + .dev_groups = s6sy761_sysfs_groups, + .of_match_table = s6sy761_of_match, + .pm = pm_ptr(&s6sy761_pm_ops), + }, + .probe = s6sy761_i2c_probe, + .remove = s6sy761_i2c_remove, + .id_table = s6sy761_id, +}; + +module_i2c_driver(s6sy761_driver); + +MODULE_IMPORT_NS("S6SY761"); +MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); +MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen"); +MODULE_LICENSE("GPL"); -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/7] Input: s6sy761 - split into core and I2C modules 2026-10-11 12:44 ` [PATCH 2/7] Input: s6sy761 - split into core and I2C modules Lukas Timmermann @ 2026-10-12 11:04 ` Uwe Kleine-König 0 siblings, 0 replies; 10+ messages in thread From: Uwe Kleine-König @ 2026-10-12 11:04 UTC (permalink / raw) To: Lukas Timmermann Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar, linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc [-- Attachment #1: Type: text/plain, Size: 19674 bytes --] On Sun, Oct 11, 2026 at 02:44:57PM +0200, Lukas Timmermann wrote: > Split this driver into a bus-agnostic core and I2C transport part in > preparation for adding SPI support. Also add a mutex because the > driver now has a transfer buffer shared between IRQ, sysfs > and PM threads. > > The Kconfig is backwards-compatible and should work on boards with an > S6SY761 touchscreen as before. The I2C transfers of the driver should be > byte by byte identical. > > The modules are now called s6sy761_core and s6sy761_i2c. > > Signed-off-by: Lukas Timmermann <foss@timmermann.space> > --- > drivers/input/touchscreen/Kconfig | 8 +- > drivers/input/touchscreen/Makefile | 3 +- > .../touchscreen/{s6sy761.c => s6sy761_core.c} | 214 +++++++++------------ > drivers/input/touchscreen/s6sy761_core.h | 34 ++++ > drivers/input/touchscreen/s6sy761_i2c.c | 112 +++++++++++ > 5 files changed, 245 insertions(+), 126 deletions(-) > > diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig > index 9b9ae8ac3f7f..76651a61324f 100644 > --- a/drivers/input/touchscreen/Kconfig > +++ b/drivers/input/touchscreen/Kconfig > @@ -535,8 +535,12 @@ config TOUCHSCREEN_S6SY761 > > If unsure, say N > > - To compile this driver as module, choose M here: the > - module will be called s6sy761. > + To compile this driver as a module, choose M here: the > + modules will be called s6sy761_core and s6sy761_i2c. > + select TOUCHSCREEN_S6SY761_I2C if I2C > + > +config TOUCHSCREEN_S6SY761_I2C > + tristate > > config TOUCHSCREEN_GUNZE > tristate "Gunze AHL-51S touchscreen" > diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile > index bfd9de83389d..24b8fb1e38d3 100644 > --- a/drivers/input/touchscreen/Makefile > +++ b/drivers/input/touchscreen/Makefile > @@ -77,7 +77,8 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o > obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o > obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o > obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o > -obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o > +obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761_core.o > +obj-$(CONFIG_TOUCHSCREEN_S6SY761_I2C) += s6sy761_i2c.o > obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o > obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o > obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o > diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761_core.c > similarity index 71% > rename from drivers/input/touchscreen/s6sy761.c > rename to drivers/input/touchscreen/s6sy761_core.c > index 899c179fb2d3..0e455060dbc0 100644 > --- a/drivers/input/touchscreen/s6sy761.c > +++ b/drivers/input/touchscreen/s6sy761_core.c > @@ -3,18 +3,21 @@ > // > // Copyright (c) 2017 Samsung Electronics Co., Ltd. > // Copyright (c) 2017 Andi Shyti <andi@etezian.org> > +// Copyright (c) 2026 Lukas Timmermann <foss@timmermann.space> > > #include <linux/unaligned.h> > #include <linux/delay.h> > -#include <linux/i2c.h> > #include <linux/input/mt.h> > #include <linux/input/touchscreen.h> > #include <linux/interrupt.h> > #include <linux/irq.h> > #include <linux/module.h> > +#include <linux/mutex.h> > #include <linux/pm_runtime.h> > #include <linux/regulator/consumer.h> > > +#include "s6sy761_core.h" > + > /* commands */ > #define S6SY761_SENSE_ON 0x10 > #define S6SY761_SENSE_OFF 0x11 > @@ -84,22 +87,18 @@ > #define S6SY761_APP_FLASH 0x3 > #define S6SY761_APP_SLEEP 0x4 > > -#define S6SY761_EVENT_SIZE 8 > -#define S6SY761_EVENT_COUNT 32 > #define S6SY761_DEVID_SIZE 3 > #define S6SY761_PANEL_ID_SIZE 11 > #define S6SY761_TS_STATUS_SIZE 5 > #define S6SY761_MAX_FINGERS 10 > > -#define S6SY761_DEV_NAME "s6sy761" > - > -enum s6sy761_regulators { > - S6SY761_REGULATOR_VDD, > - S6SY761_REGULATOR_AVDD, > -}; > - > struct s6sy761_data { > - struct i2c_client *client; > + struct device *dev; > + const struct s6sy761_bus_ops *bus_ops; > + u8 *xfer_buf; > + /* serializes bus access and protects xfer_buf */ > + struct mutex xfer_lock; > + int irq; > struct regulator_bulk_data regulators[2]; > struct input_dev *input; > struct touchscreen_properties prop; > @@ -110,33 +109,21 @@ struct s6sy761_data { > u8 tx_channel; > }; > > -/* > - * We can't simply use i2c_smbus_read_i2c_block_data because we > - * need to read more than 255 bytes > - */ > -static int s6sy761_read_events(struct s6sy761_data *sdata, u16 n_events) > -{ > - u8 cmd = S6SY761_READ_ALL_EVENT; > - struct i2c_msg msgs[2] = { > - { > - .addr = sdata->client->addr, > - .len = 1, > - .buf = &cmd, > - }, > - { > - .addr = sdata->client->addr, > - .flags = I2C_M_RD, > - .len = (n_events * S6SY761_EVENT_SIZE), > - .buf = sdata->data + S6SY761_EVENT_SIZE, > - }, > - }; > - int ret; > +enum s6sy761_regulators { > + S6SY761_REGULATOR_VDD, > + S6SY761_REGULATOR_AVDD, > +}; > > - ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs)); > - if (ret < 0) > - return ret; > +static int s6sy761_read(struct s6sy761_data *sdata, u8 cmd, size_t len, void *buf) > +{ > + guard(mutex)(&sdata->xfer_lock); > + return sdata->bus_ops->read(sdata->dev, sdata->xfer_buf, cmd, len, buf); > +} > > - return ret == ARRAY_SIZE(msgs) ? 0 : -EIO; > +static int s6sy761_write(struct s6sy761_data *sdata, u8 cmd, size_t len, const void *buf) > +{ > + guard(mutex)(&sdata->xfer_lock); > + return sdata->bus_ops->write(sdata->dev, sdata->xfer_buf, cmd, len, buf); > } > > static void s6sy761_report_coordinates(struct s6sy761_data *sdata, > @@ -226,12 +213,10 @@ static irqreturn_t s6sy761_irq_handler(int irq, void *dev) > int ret; > u8 n_events; > > - ret = i2c_smbus_read_i2c_block_data(sdata->client, > - S6SY761_READ_ONE_EVENT, > - S6SY761_EVENT_SIZE, > - sdata->data); > + ret = s6sy761_read(sdata, S6SY761_READ_ONE_EVENT, > + S6SY761_EVENT_SIZE, sdata->data); > if (ret < 0) { > - dev_err(&sdata->client->dev, "failed to read events\n"); > + dev_err(sdata->dev, "failed to read events\n"); > return IRQ_HANDLED; > } > > @@ -243,9 +228,11 @@ static irqreturn_t s6sy761_irq_handler(int irq, void *dev) > return IRQ_HANDLED; > > if (n_events) { > - ret = s6sy761_read_events(sdata, n_events); > + ret = s6sy761_read(sdata, S6SY761_READ_ALL_EVENT, > + n_events * S6SY761_EVENT_SIZE, > + sdata->data + S6SY761_EVENT_SIZE); > if (ret < 0) { > - dev_err(&sdata->client->dev, "failed to read events\n"); > + dev_err(sdata->dev, "failed to read events\n"); > return IRQ_HANDLED; > } > } > @@ -259,7 +246,7 @@ static int s6sy761_input_open(struct input_dev *dev) > { > struct s6sy761_data *sdata = input_get_drvdata(dev); > > - return i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON); > + return s6sy761_write(sdata, S6SY761_SENSE_ON, 0, NULL); > } > > static void s6sy761_input_close(struct input_dev *dev) > @@ -267,9 +254,9 @@ static void s6sy761_input_close(struct input_dev *dev) > struct s6sy761_data *sdata = input_get_drvdata(dev); > int ret; > > - ret = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_OFF); > + ret = s6sy761_write(sdata, S6SY761_SENSE_OFF, 0, NULL); > if (ret) > - dev_err(&sdata->client->dev, "failed to turn off sensing\n"); > + dev_err(sdata->dev, "failed to turn off sensing\n"); > } > > static ssize_t s6sy761_sysfs_devid(struct device *dev, > @@ -286,12 +273,23 @@ static struct attribute *s6sy761_sysfs_attrs[] = { > &dev_attr_devid.attr, > NULL > }; > -ATTRIBUTE_GROUPS(s6sy761_sysfs); > + > +static const struct attribute_group s6sy761_sysfs_group = { > + .attrs = s6sy761_sysfs_attrs, > +}; > + > +const struct attribute_group *s6sy761_sysfs_groups[] = { > + &s6sy761_sysfs_group, > + NULL, > +}; > +EXPORT_SYMBOL_NS_GPL(s6sy761_sysfs_groups, "S6SY761"); > > static int s6sy761_power_on(struct s6sy761_data *sdata) > { > + __le16 touch_func; > u8 buffer[S6SY761_EVENT_SIZE]; > u8 event; > + u8 status; > int ret; > > ret = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators), > @@ -302,10 +300,7 @@ static int s6sy761_power_on(struct s6sy761_data *sdata) > msleep(140); > > /* double check whether the touch is functional */ > - ret = i2c_smbus_read_i2c_block_data(sdata->client, > - S6SY761_READ_ONE_EVENT, > - S6SY761_EVENT_SIZE, > - buffer); > + ret = s6sy761_read(sdata, S6SY761_READ_ONE_EVENT, S6SY761_EVENT_SIZE, buffer); > if (ret < 0) > return ret; > > @@ -317,18 +312,17 @@ static int s6sy761_power_on(struct s6sy761_data *sdata) > return -ENODEV; > } > > - ret = i2c_smbus_read_byte_data(sdata->client, S6SY761_BOOT_STATUS); > + ret = s6sy761_read(sdata, S6SY761_BOOT_STATUS, 1, &status); > if (ret < 0) > return ret; > > /* for some reasons the device might be stuck in the bootloader */ > - if (ret != S6SY761_BS_APPLICATION) > + if (status != S6SY761_BS_APPLICATION) > return -ENODEV; > > /* enable touch functionality */ > - ret = i2c_smbus_write_word_data(sdata->client, > - S6SY761_TOUCH_FUNCTION, > - S6SY761_MASK_TOUCH); > + touch_func = cpu_to_le16(S6SY761_MASK_TOUCH); > + ret = s6sy761_write(sdata, S6SY761_TOUCH_FUNCTION, sizeof(touch_func), &touch_func); > if (ret) > return ret; > > @@ -339,25 +333,20 @@ static int s6sy761_hw_init(struct s6sy761_data *sdata, > unsigned int *max_x, unsigned int *max_y) > { > u8 buffer[S6SY761_PANEL_ID_SIZE]; /* larger read size */ > + u8 integrity; > int ret; > > ret = s6sy761_power_on(sdata); > if (ret) > return ret; > > - ret = i2c_smbus_read_i2c_block_data(sdata->client, > - S6SY761_DEVICE_ID, > - S6SY761_DEVID_SIZE, > - buffer); > + ret = s6sy761_read(sdata, S6SY761_DEVICE_ID, S6SY761_DEVID_SIZE, buffer); > if (ret < 0) > return ret; > > sdata->devid = get_unaligned_be16(buffer + 1); > > - ret = i2c_smbus_read_i2c_block_data(sdata->client, > - S6SY761_PANEL_INFO, > - S6SY761_PANEL_ID_SIZE, > - buffer); > + ret = s6sy761_read(sdata, S6SY761_PANEL_INFO, S6SY761_PANEL_ID_SIZE, buffer); > if (ret < 0) > return ret; > > @@ -367,11 +356,10 @@ static int s6sy761_hw_init(struct s6sy761_data *sdata, > /* if no tx channels defined, at least keep one */ > sdata->tx_channel = max_t(u8, buffer[8], 1); > > - ret = i2c_smbus_read_byte_data(sdata->client, > - S6SY761_FIRMWARE_INTEGRITY); > + ret = s6sy761_read(sdata, S6SY761_FIRMWARE_INTEGRITY, 1, &integrity); > if (ret < 0) > return ret; > - else if (ret != S6SY761_FW_OK) > + else if (integrity != S6SY761_FW_OK) > return -ENODEV; > > return 0; > @@ -381,38 +369,44 @@ static void s6sy761_power_off(void *data) > { > struct s6sy761_data *sdata = data; > > - disable_irq(sdata->client->irq); > + disable_irq(sdata->irq); > regulator_bulk_disable(ARRAY_SIZE(sdata->regulators), > sdata->regulators); > } > > -static int s6sy761_probe(struct i2c_client *client) > +int s6sy761_probe(struct device *dev, const struct s6sy761_bus_ops *bus_ops, int irq) > { > struct s6sy761_data *sdata; > unsigned int max_x, max_y; > int err; > > - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | > - I2C_FUNC_SMBUS_BYTE_DATA | > - I2C_FUNC_SMBUS_I2C_BLOCK)) > - return -ENODEV; > - > - sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL); > + sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); > if (!sdata) > return -ENOMEM; > > - i2c_set_clientdata(client, sdata); > - sdata->client = client; > + sdata->xfer_buf = devm_kzalloc(dev, S6SY761_XFER_BUFFER_SIZE, GFP_KERNEL); > + if (!sdata->xfer_buf) > + return -ENOMEM; > + > + dev_set_drvdata(dev, sdata); > + > + sdata->bus_ops = bus_ops; > + sdata->dev = dev; > + sdata->irq = irq; > + > + err = devm_mutex_init(dev, &sdata->xfer_lock); > + if (err) > + return err; > > sdata->regulators[S6SY761_REGULATOR_VDD].supply = "vdd"; > sdata->regulators[S6SY761_REGULATOR_AVDD].supply = "avdd"; > - err = devm_regulator_bulk_get(&client->dev, > + err = devm_regulator_bulk_get(dev, > ARRAY_SIZE(sdata->regulators), > sdata->regulators); > if (err) > return err; > > - err = devm_add_action_or_reset(&client->dev, s6sy761_power_off, sdata); > + err = devm_add_action_or_reset(dev, s6sy761_power_off, sdata); > if (err) > return err; > > @@ -420,12 +414,12 @@ static int s6sy761_probe(struct i2c_client *client) > if (err) > return err; > > - sdata->input = devm_input_allocate_device(&client->dev); > + sdata->input = devm_input_allocate_device(dev); > if (!sdata->input) > return -ENOMEM; > > sdata->input->name = S6SY761_DEV_NAME; > - sdata->input->id.bustype = BUS_I2C; > + sdata->input->id.bustype = bus_ops->bustype; > sdata->input->open = s6sy761_input_open; > sdata->input->close = s6sy761_input_close; > > @@ -441,7 +435,7 @@ static int s6sy761_probe(struct i2c_client *client) > > if (!input_abs_get_max(sdata->input, ABS_X) || > !input_abs_get_max(sdata->input, ABS_Y)) { > - dev_warn(&client->dev, "the axis have not been set\n"); > + dev_warn(dev, "the axis have not been set\n"); > } > > err = input_mt_init_slots(sdata->input, sdata->tx_channel, > @@ -455,37 +449,39 @@ static int s6sy761_probe(struct i2c_client *client) > if (err) > return err; > > - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, > + err = devm_request_threaded_irq(dev, sdata->irq, NULL, > s6sy761_irq_handler, > IRQF_TRIGGER_LOW | IRQF_ONESHOT, > "s6sy761_irq", sdata); > if (err) > return err; > > - pm_runtime_enable(&client->dev); > + pm_runtime_enable(dev); > > return 0; > } > +EXPORT_SYMBOL_NS_GPL(s6sy761_probe, "S6SY761"); > > -static void s6sy761_remove(struct i2c_client *client) > +void s6sy761_remove(struct device *dev) > { > - pm_runtime_disable(&client->dev); > + pm_runtime_disable(dev); > } > +EXPORT_SYMBOL_NS_GPL(s6sy761_remove, "S6SY761"); > > static int s6sy761_runtime_suspend(struct device *dev) > { > struct s6sy761_data *sdata = dev_get_drvdata(dev); > + u8 mode = S6SY761_APP_SLEEP; > > - return i2c_smbus_write_byte_data(sdata->client, > - S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP); > + return s6sy761_write(sdata, S6SY761_APPLICATION_MODE, 1, &mode); > } > > static int s6sy761_runtime_resume(struct device *dev) > { > struct s6sy761_data *sdata = dev_get_drvdata(dev); > + u8 mode = S6SY761_APP_NORMAL; > > - return i2c_smbus_write_byte_data(sdata->client, > - S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL); > + return s6sy761_write(sdata, S6SY761_APPLICATION_MODE, 1, &mode); > } > > static int s6sy761_suspend(struct device *dev) > @@ -506,51 +502,23 @@ static int s6sy761_resume(struct device *dev) > if (err) > return err; > > - enable_irq(sdata->client->irq); > + enable_irq(sdata->irq); > > guard(mutex)(&sdata->input->mutex); > > if (!input_device_enabled(sdata->input)) > return 0; > > - err = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON); > + err = s6sy761_write(sdata, S6SY761_SENSE_ON, 0, NULL); > > return err; > } > > -static const struct dev_pm_ops s6sy761_pm_ops = { > +EXPORT_NS_GPL_DEV_PM_OPS(s6sy761_pm_ops, S6SY761) = { > SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume) > RUNTIME_PM_OPS(s6sy761_runtime_suspend, s6sy761_runtime_resume, NULL) > }; > > -#ifdef CONFIG_OF > -static const struct of_device_id s6sy761_of_match[] = { > - { .compatible = "samsung,s6sy761", }, > - { }, > -}; > -MODULE_DEVICE_TABLE(of, s6sy761_of_match); > -#endif > - > -static const struct i2c_device_id s6sy761_id[] = { > - { .name = "s6sy761" }, > - { } > -}; > -MODULE_DEVICE_TABLE(i2c, s6sy761_id); > - > -static struct i2c_driver s6sy761_driver = { > - .driver = { > - .name = S6SY761_DEV_NAME, > - .dev_groups = s6sy761_sysfs_groups, > - .of_match_table = of_match_ptr(s6sy761_of_match), > - .pm = pm_ptr(&s6sy761_pm_ops), > - }, > - .probe = s6sy761_probe, > - .remove = s6sy761_remove, > - .id_table = s6sy761_id, > -}; > - > -module_i2c_driver(s6sy761_driver); > - > MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); > -MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen"); > -MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen core"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/input/touchscreen/s6sy761_core.h b/drivers/input/touchscreen/s6sy761_core.h > new file mode 100644 > index 000000000000..059cd5a36a34 > --- /dev/null > +++ b/drivers/input/touchscreen/s6sy761_core.h > @@ -0,0 +1,34 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef _S6SY761_H > +#define _S6SY761_H > + > +#include <linux/align.h> > +#include <linux/types.h> > + > +#define S6SY761_EVENT_SIZE 8 > +#define S6SY761_EVENT_COUNT 32 > +/* largest SPI read: reply header + all events + checksum */ > +#define S6SY761_XFER_BUFFER_SIZE ALIGN(7 + S6SY761_EVENT_SIZE * S6SY761_EVENT_COUNT + 1, 4) > + > +#define S6SY761_DEV_NAME "s6sy761" > + > +struct device; > +struct dev_pm_ops; > +struct attribute_group; > + > +struct s6sy761_bus_ops { > + u16 bustype; > + int (*write)(struct device *dev, u8 *xfer_buf, > + u8 cmd, size_t length, const void *values); > + int (*read)(struct device *dev, u8 *xfer_buf, > + u8 cmd, size_t length, void *values); > +}; > + > +extern const struct dev_pm_ops s6sy761_pm_ops; > + > +extern const struct attribute_group *s6sy761_sysfs_groups[]; > + > +int s6sy761_probe(struct device *dev, const struct s6sy761_bus_ops *bus_ops, int irq); > +void s6sy761_remove(struct device *dev); > + > +#endif > diff --git a/drivers/input/touchscreen/s6sy761_i2c.c b/drivers/input/touchscreen/s6sy761_i2c.c > new file mode 100644 > index 000000000000..b5cbebfd722a > --- /dev/null > +++ b/drivers/input/touchscreen/s6sy761_i2c.c > @@ -0,0 +1,112 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// Samsung S6SY761 I2C Touchscreen device driver > +// > +// Copyright (c) 2017 Samsung Electronics Co., Ltd. > +// Copyright (c) 2017 Andi Shyti <andi@etezian.org> > +// Copyright (c) 2026 Lukas Timmermann <foss@timmermann.space> > + > +#include <linux/input.h> > +#include <linux/i2c.h> > +#include <linux/mod_devicetable.h> Please don't add new usages of <linux/mod_devicetable.h>. <linux/i2c.h> is enough to get the definition of of_device_id and i2c_device_id. I didn't look into the other patches of this series in detail, but I suspect that the same holds true in your spi patch. <linux/spi/spi.h> provides of_device_id and spi_device_id, so don't add <linux/mod_devicetable.h> there either. (If you want to go full iwyu, use the subsystem specific headers below linux/device-id/. > +static const struct of_device_id s6sy761_of_match[] = { > + { .compatible = "samsung,s6sy761", }, > + { }, No trailing comma after the list terminator please. > +}; > +MODULE_DEVICE_TABLE(of, s6sy761_of_match); > + > +static const struct i2c_device_id s6sy761_id[] = { > + { "s6sy761" }, please make this: { .name = "s6sy761" } Best regards Uwe [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 3/7] Input: s6sy761 - add reset GPIO support 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann 2026-10-11 12:44 ` [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO Lukas Timmermann 2026-10-11 12:44 ` [PATCH 2/7] Input: s6sy761 - split into core and I2C modules Lukas Timmermann @ 2026-10-11 12:44 ` Lukas Timmermann 2026-10-11 12:44 ` [PATCH 4/7] Input: s6sy761 - add SPI support for S6SY791 Lukas Timmermann ` (3 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:44 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc Some boards wire up the controller's reset line. Hold the controller in reset while its supplies come up and release it 10 ms later, as the vendor driver does, and assert it again on power down. The GPIO is optional, so boards without it are unaffected. Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- drivers/input/touchscreen/s6sy761_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/input/touchscreen/s6sy761_core.c b/drivers/input/touchscreen/s6sy761_core.c index 0e455060dbc0..8541cd9aa930 100644 --- a/drivers/input/touchscreen/s6sy761_core.c +++ b/drivers/input/touchscreen/s6sy761_core.c @@ -7,6 +7,7 @@ #include <linux/unaligned.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> #include <linux/interrupt.h> @@ -100,6 +101,7 @@ struct s6sy761_data { struct mutex xfer_lock; int irq; struct regulator_bulk_data regulators[2]; + struct gpio_desc *reset_gpio; struct input_dev *input; struct touchscreen_properties prop; @@ -297,6 +299,9 @@ static int s6sy761_power_on(struct s6sy761_data *sdata) if (ret) return ret; + usleep_range(10000, 11000); + gpiod_set_value_cansleep(sdata->reset_gpio, 0); + msleep(140); /* double check whether the touch is functional */ @@ -370,6 +375,7 @@ static void s6sy761_power_off(void *data) struct s6sy761_data *sdata = data; disable_irq(sdata->irq); + gpiod_set_value_cansleep(sdata->reset_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(sdata->regulators), sdata->regulators); } @@ -406,6 +412,12 @@ int s6sy761_probe(struct device *dev, const struct s6sy761_bus_ops *bus_ops, int if (err) return err; + sdata->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sdata->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(sdata->reset_gpio), + "failed to get reset GPIO\n"); + err = devm_add_action_or_reset(dev, s6sy761_power_off, sdata); if (err) return err; -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 4/7] Input: s6sy761 - add SPI support for S6SY791 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann ` (2 preceding siblings ...) 2026-10-11 12:44 ` [PATCH 3/7] Input: s6sy761 - add reset GPIO support Lukas Timmermann @ 2026-10-11 12:44 ` Lukas Timmermann 2026-10-11 12:45 ` [PATCH 5/7] arm64: dts: exynos: gs101-pixel-common: add labels for touchscreen supplies Lukas Timmermann ` (2 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:44 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc The S6SY791 uses the same commands as the S6SY761, wrapped in an SPI frame: a sync byte, length fields, the opcode, the payload and an 8-bit checksum, padded to a multiple of 4 bytes. Reads are a request frame followed by a reply frame after an opcode-specific delay, taken from Google's downstream driver. The reply is clocked out full duplex with zeroed tx data. On gs101 (spi-s3c64xx) a receive-only transfer leaves MOSI undefined, and the controller then ignores the next command. Tested on a Google Pixel 6 Pro (raven). Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- drivers/input/touchscreen/Kconfig | 14 ++- drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/s6sy761_spi.c | 172 ++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 76651a61324f..49788ca10d80 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -528,20 +528,26 @@ config TOUCHSCREEN_IPROC module will be called bcm_iproc_tsc. config TOUCHSCREEN_S6SY761 - tristate "Samsung S6SY761 Touchscreen driver" - depends on I2C + tristate "Samsung S6SY761/S6SY791 Touchscreen driver" + depends on I2C || SPI help - Say Y if you have the Samsung S6SY761 driver + Say Y here if you have a Samsung S6SY761 or S6SY791 + touchscreen controller connected to your system via I2C or SPI. If unsure, say N To compile this driver as a module, choose M here: the - modules will be called s6sy761_core and s6sy761_i2c. + modules will be called s6sy761_core, s6sy761_i2c and + s6sy761_spi. select TOUCHSCREEN_S6SY761_I2C if I2C + select TOUCHSCREEN_S6SY761_SPI if SPI config TOUCHSCREEN_S6SY761_I2C tristate +config TOUCHSCREEN_S6SY761_SPI + tristate + config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 24b8fb1e38d3..b76009f89bec 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761_core.o obj-$(CONFIG_TOUCHSCREEN_S6SY761_I2C) += s6sy761_i2c.o +obj-$(CONFIG_TOUCHSCREEN_S6SY761_SPI) += s6sy761_spi.o obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o diff --git a/drivers/input/touchscreen/s6sy761_spi.c b/drivers/input/touchscreen/s6sy761_spi.c new file mode 100644 index 000000000000..c6627e61c285 --- /dev/null +++ b/drivers/input/touchscreen/s6sy761_spi.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +// Samsung S6SY761 SPI Touchscreen device driver +// +// Copyright (c) 2026 Lukas Timmermann <foss@timmermann.space> + +#include <linux/delay.h> +#include <linux/input.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/unaligned.h> + +#include "s6sy761_core.h" + +#define S6SY761_SPI_SYNC_CODE 0xaa +#define S6SY761_SPI_HEADER_SIZE 5 /* sync, 2 len, 2 reserved */ +#define S6SY761_SPI_CHECKSUM_SIZE 1 +#define S6SY761_SPI_READ_HEADER_SIZE 7 /* sync, 4 len, opcode, status */ + +/* opcodes that need a longer wait before the reply is ready */ +#define S6SY761_SPI_CMD_FW_INTEGRITY 0x21 +#define S6SY761_SPI_CMD_READ_ALL_EVENT 0x61 + +static u8 s6sy761_spi_checksum(const u8 *buf, size_t len) +{ + u8 sum = 0; + size_t i; + + for (i = 0; i < len; i++) + sum += buf[i]; + + return sum; +} + +static int s6sy761_spi_write(struct device *dev, u8 *xfer_buf, + u8 cmd, size_t length, const void *values) +{ + struct spi_device *spi = to_spi_device(dev); + + /* header + opcode + payload + checksum */ + size_t frame_len = S6SY761_SPI_HEADER_SIZE + 1 + length + + S6SY761_SPI_CHECKSUM_SIZE; + size_t xfer_len = ALIGN(frame_len, 4); + + if (xfer_len > S6SY761_XFER_BUFFER_SIZE) + return -EINVAL; + + xfer_buf[0] = S6SY761_SPI_SYNC_CODE; + put_unaligned_be16(length + 1, xfer_buf + 1); + xfer_buf[3] = 0; + xfer_buf[4] = 0; + xfer_buf[5] = cmd; + + if (length) + memcpy(xfer_buf + 6, values, length); + + xfer_buf[frame_len - 1] = s6sy761_spi_checksum(xfer_buf, frame_len - 1); + + /* the chip expects transfers in multiples of 4 bytes */ + memset(xfer_buf + frame_len, 0, xfer_len - frame_len); + + return spi_write(spi, xfer_buf, xfer_len); +} + +static unsigned int s6sy761_spi_read_delay_us(u8 cmd) +{ + switch (cmd) { + case S6SY761_SPI_CMD_FW_INTEGRITY: + return 20000; + case S6SY761_SPI_CMD_READ_ALL_EVENT: + return 550; + default: + return 100; + } +} + +static int s6sy761_spi_read(struct device *dev, u8 *xfer_buf, + u8 cmd, size_t length, void *values) +{ + struct spi_device *spi = to_spi_device(dev); + struct spi_transfer reply = { }; + /* request: header + opcode + checksum, no payload */ + size_t req_len = S6SY761_SPI_HEADER_SIZE + 1 + + S6SY761_SPI_CHECKSUM_SIZE; + /* reply: header + data + checksum */ + size_t resp_len = S6SY761_SPI_READ_HEADER_SIZE + length + + S6SY761_SPI_CHECKSUM_SIZE; + int ret; + + if (ALIGN(resp_len, 4) > S6SY761_XFER_BUFFER_SIZE) + return -EINVAL; + + /* tell the chip what to read and how much */ + xfer_buf[0] = S6SY761_SPI_SYNC_CODE; + put_unaligned_be16(1, xfer_buf + 1); /* write length: opcode */ + put_unaligned_be16(length, xfer_buf + 3); /* read length */ + xfer_buf[5] = cmd; + xfer_buf[req_len - 1] = s6sy761_spi_checksum(xfer_buf, req_len - 1); + memset(xfer_buf + req_len, 0, ALIGN(req_len, 4) - req_len); + + ret = spi_write(spi, xfer_buf, ALIGN(req_len, 4)); + if (ret) + return ret; + + /* give the chip time to prepare the reply */ + fsleep(s6sy761_spi_read_delay_us(cmd)); + + memset(xfer_buf, 0, ALIGN(resp_len, 4)); + reply.tx_buf = xfer_buf; + reply.rx_buf = xfer_buf; + reply.len = ALIGN(resp_len, 4); + ret = spi_sync_transfer(spi, &reply, 1); + if (ret) + return ret; + + if (xfer_buf[0] != S6SY761_SPI_SYNC_CODE || + xfer_buf[5] != cmd || + xfer_buf[resp_len - 1] != + s6sy761_spi_checksum(xfer_buf, resp_len - 1)) + return -EIO; + + memcpy(values, xfer_buf + S6SY761_SPI_READ_HEADER_SIZE, length); + + return 0; +} + +static const struct s6sy761_bus_ops s6sy761_spi_bus_ops = { + .bustype = BUS_SPI, + .read = s6sy761_spi_read, + .write = s6sy761_spi_write, +}; + +static int s6sy761_spi_probe(struct spi_device *spi) +{ + return s6sy761_probe(&spi->dev, &s6sy761_spi_bus_ops, spi->irq); +} + +static void s6sy761_spi_remove(struct spi_device *spi) +{ + s6sy761_remove(&spi->dev); +} + +static const struct of_device_id s6sy761_of_match[] = { + { .compatible = "samsung,s6sy791", }, + { }, +}; +MODULE_DEVICE_TABLE(of, s6sy761_of_match); + +static const struct spi_device_id s6sy761_id[] = { + { "s6sy791" }, + { } +}; +MODULE_DEVICE_TABLE(spi, s6sy761_id); + +static struct spi_driver s6sy761_driver = { + .driver = { + .name = S6SY761_DEV_NAME, + .dev_groups = s6sy761_sysfs_groups, + .of_match_table = s6sy761_of_match, + .pm = pm_ptr(&s6sy761_pm_ops), + }, + .probe = s6sy761_spi_probe, + .remove = s6sy761_spi_remove, + .id_table = s6sy761_id, +}; + +module_spi_driver(s6sy761_driver); + +MODULE_IMPORT_NS("S6SY761"); +MODULE_AUTHOR("Lukas Timmermann <foss@timmermann.space>"); +MODULE_DESCRIPTION("Samsung S6SY791 Touch Screen"); +MODULE_LICENSE("GPL"); -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 5/7] arm64: dts: exynos: gs101-pixel-common: add labels for touchscreen supplies 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann ` (3 preceding siblings ...) 2026-10-11 12:44 ` [PATCH 4/7] Input: s6sy761 - add SPI support for S6SY791 Lukas Timmermann @ 2026-10-11 12:45 ` Lukas Timmermann 2026-10-11 12:45 ` [PATCH 6/7] arm64: dts: exynos: gs101-raven: add S6SY791 touchscreen Lukas Timmermann 2026-10-11 12:45 ` [PATCH 7/7] MAINTAINERS: add entry for Samsung S6SY761 touchscreen driver Lukas Timmermann 6 siblings, 0 replies; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:45 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc The Pixel 6 boards use different touchscreen controllers. Label the touchscreen supplies so board files can reference them. Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi b/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi index a12f2b88d72d..92b1640c0612 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi +++ b/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi @@ -399,14 +399,14 @@ s2mpg10_ldo22m: ldo22m { /* ldo23m & ldo24m are unused */ - ldo25m { + s2mpg10_ldo25m: ldo25m { /* touch */ regulator-name = "dvdd_tsp"; regulator-min-microvolt = <1600000>; regulator-max-microvolt = <1950000>; }; - ldo26m { + s2mpg10_ldo26m: ldo26m { /* touch */ regulator-name = "avdd_ts"; regulator-min-microvolt = <2500000>; -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 6/7] arm64: dts: exynos: gs101-raven: add S6SY791 touchscreen 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann ` (4 preceding siblings ...) 2026-10-11 12:45 ` [PATCH 5/7] arm64: dts: exynos: gs101-pixel-common: add labels for touchscreen supplies Lukas Timmermann @ 2026-10-11 12:45 ` Lukas Timmermann 2026-10-11 12:45 ` [PATCH 7/7] MAINTAINERS: add entry for Samsung S6SY761 touchscreen driver Lukas Timmermann 6 siblings, 0 replies; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:45 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc Configure USI11 as SPI controller and add the S6SY791 touchscreen with its supplies, reset and interrupt lines. The touch SPI bus can be muxed between the AP and the AOC coprocessor via TS_SPI_SEL (gpp26-1). Hog it low so the AP owns the bus. Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- arch/arm64/boot/dts/exynos/google/gs101-raven.dts | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/google/gs101-raven.dts b/arch/arm64/boot/dts/exynos/google/gs101-raven.dts index 7c4273796a22..02b19e39055a 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101-raven.dts +++ b/arch/arm64/boot/dts/exynos/google/gs101-raven.dts @@ -47,3 +47,53 @@ &framebuffer0 { status = "okay"; }; + +&gpp26 { + /* TS_SPI_SEL: low = AP owns the touch SPI bus, high = AOC */ + ts-spi-sel-hog { + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "ts-spi-sel"; + }; +}; + +&pinctrl_gpio_alive { + ts_irq: ts-irq-pins { + samsung,pins = "gpa9-0"; + samsung,pin-function = <GS101_PIN_FUNC_EINT>; + samsung,pin-pud = <GS101_PIN_PULL_NONE>; + samsung,pin-drv = <GS101_PIN_DRV_2_5_MA>; + }; +}; + +&spi_11 { + cs-gpios = <&gpp23 3 GPIO_ACTIVE_LOW>; + num-cs = <1>; + pinctrl-0 = <&spi11_bus &spi11_cs>; + pinctrl-names = "default"; + status = "okay"; + + touchscreen@0 { + compatible = "samsung,s6sy791"; + reg = <0>; + spi-max-frequency = <10000000>; + spi-cpol; + spi-cpha; + + interrupt-parent = <&gpa9>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&ts_irq>; + pinctrl-names = "default"; + + reset-gpios = <&gpp26 0 GPIO_ACTIVE_LOW>; + + vdd-supply = <&s2mpg10_ldo25m>; + avdd-supply = <&s2mpg10_ldo26m>; + }; +}; + +&usi11 { + samsung,mode = <USI_MODE_SPI>; + status = "okay"; +}; -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 7/7] MAINTAINERS: add entry for Samsung S6SY761 touchscreen driver 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann ` (5 preceding siblings ...) 2026-10-11 12:45 ` [PATCH 6/7] arm64: dts: exynos: gs101-raven: add S6SY791 touchscreen Lukas Timmermann @ 2026-10-11 12:45 ` Lukas Timmermann 6 siblings, 0 replies; 10+ messages in thread From: Lukas Timmermann @ 2026-10-11 12:45 UTC (permalink / raw) To: Lukas Timmermann, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andi Shyti, Peter Griffin, André Draszik, Tudor Ambarus, Alim Akhtar Cc: linux-input, devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc Add a MAINTAINERS entry for the S6SY761 driver and its binding, which currently have no entry. Signed-off-by: Lukas Timmermann <foss@timmermann.space> --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f53047aa8d3c..9de472b68ea9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24430,6 +24430,13 @@ F: Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-lite.yaml F: Documentation/devicetree/bindings/media/samsung,fimc.yaml F: drivers/media/platform/samsung/exynos4-is/ +SAMSUNG S6SY761 TOUCHSCREEN DRIVER +M: Lukas Timmermann <foss@timmermann.space> +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml +F: drivers/input/touchscreen/s6sy761* + SAMSUNG SOC CLOCK DRIVERS M: Krzysztof Kozlowski <krzk@kernel.org> M: Sylwester Nawrocki <s.nawrocki@samsung.com> -- 2.56.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-10-12 11:30 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-10-11 12:44 [PATCH 0/7] Input: s6sy761 - add SPI support for the S6SY791 Lukas Timmermann 2026-10-11 12:44 ` [PATCH 1/7] dt-bindings: input: touchscreen: samsung,s6sy761: Add S6SY791 and reset GPIO Lukas Timmermann 2026-10-12 11:30 ` Krzysztof Kozlowski 2026-10-11 12:44 ` [PATCH 2/7] Input: s6sy761 - split into core and I2C modules Lukas Timmermann 2026-10-12 11:04 ` Uwe Kleine-König 2026-10-11 12:44 ` [PATCH 3/7] Input: s6sy761 - add reset GPIO support Lukas Timmermann 2026-10-11 12:44 ` [PATCH 4/7] Input: s6sy761 - add SPI support for S6SY791 Lukas Timmermann 2026-10-11 12:45 ` [PATCH 5/7] arm64: dts: exynos: gs101-pixel-common: add labels for touchscreen supplies Lukas Timmermann 2026-10-11 12:45 ` [PATCH 6/7] arm64: dts: exynos: gs101-raven: add S6SY791 touchscreen Lukas Timmermann 2026-10-11 12:45 ` [PATCH 7/7] MAINTAINERS: add entry for Samsung S6SY761 touchscreen driver Lukas Timmermann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®