@@ -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
@@ -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
@@ -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
new file mode 100644
@@ -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");