diff mbox series

[2/2] gpio: Add support for SLG7XL45106 I2C GPO expander

Message ID 1656426829-1008-3-git-send-email-shubhrajyoti.datta@xilinx.com
State New
Headers show
Series gpio: Add support for SLG7XL45106 I2C GPO expander | expand

Commit Message

Shubhrajyoti Datta June 28, 2022, 2:33 p.m. UTC
From: Raviteja Narayanam <raviteja.narayanam@xilinx.com>

Dialog semiconductors SLG7XL45106 is an 8-bit I2C GPO expander.
The output port is controlled by a data byte with register
address.

Signed-off-by: Raviteja Narayanam <raviteja.narayanam@xilinx.com>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
---
 MAINTAINERS                     |   7 ++
 drivers/gpio/Kconfig            |   9 +++
 drivers/gpio/Makefile           |   1 +
 drivers/gpio/gpio-slg7xl45106.c | 133 ++++++++++++++++++++++++++++++++
 4 files changed, 150 insertions(+)
 create mode 100644 drivers/gpio/gpio-slg7xl45106.c

Comments

Datta, Shubhrajyoti June 29, 2022, 1:19 p.m. UTC | #1
[AMD Official Use Only - General]



> -----Original Message-----
> From: Simek, Michal <michal.simek@amd.com>
> Sent: Wednesday, June 29, 2022 4:08 PM
> To: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: Sungbo Eo <mans0n@gorani.run>; Shubhrajyoti Datta
> <shubhrajyoti.datta@xilinx.com>; open list:GPIO SUBSYSTEM <linux-
> gpio@vger.kernel.org>; Michal Simek <michal.simek@xilinx.com>; git (AMD-
> Xilinx) <git@amd.com>; git <git@xilinx.com>
> Subject: Re: [PATCH 2/2] gpio: Add support for SLG7XL45106 I2C GPO
> expander
> 
> 
> 
> On 6/29/22 12:15, Andy Shevchenko wrote:
> > On Wed, Jun 29, 2022 at 9:14 AM Michal Simek <michal.simek@amd.com>
> wrote:
> >> On 6/29/22 03:00, Sungbo Eo wrote:
> >>> On 2022-06-29 04:21, Andy Shevchenko wrote:
> >>>> On Tue, Jun 28, 2022 at 9:13 PM Andy Shevchenko
> >>>> <andy.shevchenko@gmail.com> wrote:
> >
> > ...
> >
> >>>> Actually, why can't pca9570 be amended to support this?
> >
> >>> It seems the slg7xl45106 driver reads/writes a reg at 0xDB so it is
> >>> not compatible with pca9570 driver (in the current state), and (I
> >>> suppose) it could be converted to use gpio-regmap.
> >>>
> >>> [1]
> >>> https://lore.kernel.org/linux-
> gpio/69f5d1a1970838b8c4bd8d6e8dba6cac@
> >>> walle.cc/
> >>
> >> As was mentioned driver is based on pca9570 and the only important
> >> difference is with i2c_smbus_read_byte/i2c_smbus_read_byte_data and
> >> especially i2c_smbus_write_byte/i2c_smbus_write_byte_data.
> >>
> >> Read can be aligned without any issue but write will have if/else
> >> because of i2c_smbus_write_byte_data. Example below.
> >>
> >> Something like this. If this change is fine I think there won't be
> >> any issue to just merge it with pca9570.
> >
> > Thanks, I also would like to see something as below in the result.
> 
> ok. Good.
> 
> >
> >> diff --git a/drivers/gpio/gpio-slg7xl45106.c
> >> b/drivers/gpio/gpio-slg7xl45106.c index bf25e6fb6782..b90950ae38c1
> >> 100644
> >> --- a/drivers/gpio/gpio-slg7xl45106.c
> >> +++ b/drivers/gpio/gpio-slg7xl45106.c
> >> @@ -22,20 +22,24 @@
> >>    struct slg7xl45106 {
> >>           struct gpio_chip chip;
> >>           struct mutex lock;      /* To protect writes */
> >> +       u32 command;
> >>    };
> >>
> >>    static int slg7xl45106_read(struct slg7xl45106 *gpio)
> >>    {
> >>           struct i2c_client *client =
> >> to_i2c_client(gpio->chip.parent);
> >>
> >> -       return i2c_smbus_read_byte_data(client, SLG7XL45106_GPO_REG);
> >> +       return i2c_smbus_read_byte_data(client, gpio->command);
> >>    }
> >>
> >>    static int slg7xl45106_write(struct slg7xl45106 *gpio, u8 value)
> >>    {
> >>           struct i2c_client *client =
> >> to_i2c_client(gpio->chip.parent);
> >>
> >> -       return i2c_smbus_write_byte_data(client, SLG7XL45106_GPO_REG,
> value);
> >> +       if (gpio->command)
> >> +               return i2c_smbus_write_byte_data(client,
> >> + SLG7XL45106_GPO_REG,
> >> value);
> >
> > Missed change to gpio->command :-)
> 
> I found it too. :-)
> 
> Shubhrajyoti: Can you please merge that slg driver to 9570? That dt-binding
> will require small massage too.

Will fix in the next version.
Thanks 
> 
> Thanks,
> Michal
>
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 1fc9ead83d2a..3b3f322b5012 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5875,6 +5875,13 @@  F:	include/linux/regulator/da9211.h
 F:	include/sound/da[79]*.h
 F:	sound/soc/codecs/da[79]*.[ch]
 
+DIALOG SLG7XL45106 GPO DRIVER
+M:	Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/gpio/gpio-slg7xl45106.yaml
+F:	drivers/gpio/gpio-slg7xl45106.c
+
 DIAMOND SYSTEMS GPIO-MM GPIO DRIVER
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-gpio@vger.kernel.org
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b01961999ced..1e10f96c9c09 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1101,6 +1101,15 @@  config GPIO_PCF857X
 	  This driver provides an in-kernel interface to those GPIOs using
 	  platform-neutral GPIO calls.
 
+config GPIO_SLG7XL45106
+	tristate "SLG7XL45106 8-Bit I2C GPO expander"
+	help
+	  Say yes here to enable the GPO driver for the Dialog SLG7XL45106 chip.
+	  This expander has 8 output pins.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called gpio-slg7xl45106.
+
 config GPIO_TPIC2810
 	tristate "TPIC2810 8-Bit I2C GPO expander"
 	help
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 14352f6dfe8e..8248e4fcc22f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -136,6 +136,7 @@  obj-$(CONFIG_GPIO_SIFIVE)		+= gpio-sifive.o
 obj-$(CONFIG_GPIO_SIM)			+= gpio-sim.o
 obj-$(CONFIG_GPIO_SIOX)			+= gpio-siox.o
 obj-$(CONFIG_GPIO_SL28CPLD)		+= gpio-sl28cpld.o
+obj-$(CONFIG_GPIO_SLG7XL45106)		+= gpio-slg7xl45106.o
 obj-$(CONFIG_GPIO_SODAVILLE)		+= gpio-sodaville.o
 obj-$(CONFIG_GPIO_SPEAR_SPICS)		+= gpio-spear-spics.o
 obj-$(CONFIG_GPIO_SPRD)			+= gpio-sprd.o
diff --git a/drivers/gpio/gpio-slg7xl45106.c b/drivers/gpio/gpio-slg7xl45106.c
new file mode 100644
index 000000000000..61935b8538d1
--- /dev/null
+++ b/drivers/gpio/gpio-slg7xl45106.c
@@ -0,0 +1,133 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for slg7xl45106 I2C GPO expander
+ *
+ * Copyright (C) 2021 Xilinx, Inc.
+ * Copyright (C) 2022 AMD, Inc.
+ *
+ * Based on gpio-pca9570.c
+ * Copyright (C) 2020 Sungbo Eo <mans0n@gorani.run>
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#define SLG7XL45106_GPO_REG	0xDB
+
+/**
+ * struct slg7xl45106 - GPIO driver data
+ * @chip: GPIO controller chip
+ * @lock: Protects write sequences
+ */
+struct slg7xl45106 {
+	struct gpio_chip chip;
+	struct mutex lock;	/* To protect writes */
+};
+
+static int slg7xl45106_read(struct slg7xl45106 *gpio)
+{
+	struct i2c_client *client = to_i2c_client(gpio->chip.parent);
+
+	return i2c_smbus_read_byte_data(client, SLG7XL45106_GPO_REG);
+}
+
+static int slg7xl45106_write(struct slg7xl45106 *gpio, u8 value)
+{
+	struct i2c_client *client = to_i2c_client(gpio->chip.parent);
+
+	return i2c_smbus_write_byte_data(client, SLG7XL45106_GPO_REG, value);
+}
+
+static int slg7xl45106_get_direction(struct gpio_chip *chip,
+				     unsigned int offset)
+{
+	/* This device always output */
+	return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int slg7xl45106_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct slg7xl45106 *gpio = gpiochip_get_data(chip);
+	int ret;
+
+	ret = slg7xl45106_read(gpio);
+	if (ret < 0)
+		return ret;
+
+	return !!(ret & BIT(offset));
+}
+
+static void slg7xl45106_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+	struct slg7xl45106 *gpio = gpiochip_get_data(chip);
+	u8 buffer;
+
+	mutex_lock(&gpio->lock);
+
+	buffer = slg7xl45106_read(gpio);
+	if (buffer < 0)
+		goto out;
+
+	if (value)
+		buffer |= BIT(offset);
+	else
+		buffer &= ~BIT(offset);
+
+	slg7xl45106_write(gpio, buffer);
+
+out:
+	mutex_unlock(&gpio->lock);
+}
+
+static int slg7xl45106_probe(struct i2c_client *client)
+{
+	struct slg7xl45106 *gpio;
+
+	gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	gpio->chip.label = client->name;
+	gpio->chip.parent = &client->dev;
+	gpio->chip.owner = THIS_MODULE;
+	gpio->chip.get_direction = slg7xl45106_get_direction;
+	gpio->chip.get = slg7xl45106_get;
+	gpio->chip.set = slg7xl45106_set;
+	gpio->chip.base = -1;
+	gpio->chip.ngpio = (uintptr_t)device_get_match_data(&client->dev);
+	gpio->chip.can_sleep = true;
+
+	mutex_init(&gpio->lock);
+
+	i2c_set_clientdata(client, gpio);
+
+	return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
+}
+
+static const struct i2c_device_id slg7xl45106_id_table[] = {
+	{ "slg7xl45106", 8 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, slg7xl45106_id_table);
+
+static const struct of_device_id slg7xl45106_of_match_table[] = {
+	{ .compatible = "dlg,slg7xl45106", .data = (void *)8 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, slg7xl45106_of_match_table);
+
+static struct i2c_driver slg7xl45106_driver = {
+	.driver = {
+		.name = "slg7xl45106",
+		.of_match_table = slg7xl45106_of_match_table,
+	},
+	.probe_new = slg7xl45106_probe,
+	.id_table = slg7xl45106_id_table,
+};
+module_i2c_driver(slg7xl45106_driver);
+
+MODULE_AUTHOR("Raviteja Narayanam <raviteja.narayanam@xilinx.com>");
+MODULE_DESCRIPTION("GPIO expander driver for slg7xl45106");
+MODULE_LICENSE("GPL");