@@ -77,6 +77,15 @@ config GPIO_GENERIC
depends on HAS_IOMEM # Only for IOMEM drivers
tristate
+config GPIO_INVERTER
+ tristate "Inverter GPIO controller for handling hardware inverters"
+ depends on OF_GPIO
+ help
+ Enabling this configuration provides an inverter gpio controller to
+ configure the polarity of the gpio pins.
+ This enables the consumers to directly use the gpio pin without
+ worrying about the hardware level polarity configuration.
+
# put drivers in the right section, in alphabetical order
# This symbol is selected by both I2C and SPI expanders
@@ -61,6 +61,7 @@ obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
+obj-$(CONFIG_GPIO_INVERTER) += gpio-inverter.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
new file mode 100644
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Inverter GPIO controller for configuring the gpio polarity
+ *
+ * Copyright (c) 2019 Mentor Graphics Inc.
+ * Developed using gpiolib and gpio documentation as reference
+ *
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+struct gpio_inverter {
+ struct gpio_chip gpiochip;
+ int count;
+ struct gpio_desc *gpios[];
+};
+
+static int gpio_inverter_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct gpio_inverter *inv = gpiochip_get_data(chip);
+
+ return gpiod_direction_input(inv->gpios[offset]);
+}
+
+static int gpio_inverter_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct gpio_inverter *inv = gpiochip_get_data(chip);
+
+ return gpiod_direction_output(inv->gpios[offset], value);
+}
+
+static int gpio_inverter_get(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct gpio_inverter *inv = gpiochip_get_data(chip);
+
+ return !gpiod_get_value(inv->gpios[offset]);
+}
+
+static void gpio_inverter_set(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct gpio_inverter *inv = gpiochip_get_data(chip);
+
+ return gpiod_set_value(inv->gpios[offset], !value);
+}
+
+static int gpio_inverter_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_inverter *inv;
+ struct gpio_chip *gpio_chip;
+ struct gpio_desc *gpio;
+ int index = 0;
+ int count;
+ int ret;
+
+ count = of_gpio_named_count(dev->of_node, "inverted-gpios");
+ if (count <= 0)
+ return count ? count : -ENOENT;
+
+ inv = devm_kzalloc(dev, struct_size(inv, gpios, count), GFP_KERNEL);
+ if (!inv)
+ return -ENOMEM;
+
+ inv->count = count;
+ gpio_chip = &inv->gpiochip;
+
+ platform_set_drvdata(pdev, inv);
+
+ while (index < count) {
+ gpio = devm_gpiod_get_index(dev, "inverted", index, GPIOD_ASIS);
+
+ if (gpio == ERR_PTR(-ENOENT)) {
+ devm_kfree(dev, inv);
+ return -EPROBE_DEFER;
+ }
+
+ if (IS_ERR(gpio))
+ return PTR_ERR(gpio);
+
+ inv->gpios[index++] = gpio;
+
+ if (!gpio_chip->can_sleep && gpiod_cansleep(gpio))
+ gpio_chip->can_sleep = true;
+ }
+
+ gpio_chip->direction_input = gpio_inverter_direction_input;
+ gpio_chip->direction_output = gpio_inverter_direction_output;
+ gpio_chip->get = gpio_inverter_get;
+ gpio_chip->set = gpio_inverter_set;
+ gpio_chip->label = dev_name(dev);
+ gpio_chip->parent = dev;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->base = -1;
+ gpio_chip->ngpio = count;
+
+ ret = devm_gpiochip_add_data(dev, gpio_chip, inv);
+ if (ret) {
+ dev_err(dev, "failed to add gpio controller\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id gpio_inverter_match[] = {
+ { .compatible = "gpio-inverter", }, { },
+};
+
+static struct platform_driver gpio_inverter_driver = {
+ .probe = gpio_inverter_probe,
+ .driver = {
+ .name = "gpio-inverter",
+ .of_match_table = of_match_ptr(gpio_inverter_match),
+ }
+};
+
+module_platform_driver(gpio_inverter_driver);
+
+MODULE_AUTHOR("Harish Jenny K N <harish_kandiga@mentor.com>");
+MODULE_AUTHOR("Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>");
+MODULE_DESCRIPTION("Inverter GPIO controller for configuring the gpio polarity");
+MODULE_LICENSE("GPL v2");