This is a slighty modified version of ar71xx gpio-latch driver written by Gabor Juhos <[email protected]>.
Changes: * DTS support, * New gpio API (gpiod_*). Signed-off-by: Denis Kalashnikov <[email protected]> --- Changelog: v1-->v2: - Don't use MFD driver API anymore. --- .../ath79/files/drivers/gpio/gpio-latch.c | 225 ++++++++++++++++++ .../patches-5.10/939-mikrotik-rb91x.patch | 25 ++ .../patches-5.4/939-mikrotik-rb91x.patch | 23 ++ 3 files changed, 273 insertions(+) create mode 100644 target/linux/ath79/files/drivers/gpio/gpio-latch.c create mode 100644 target/linux/ath79/patches-5.10/939-mikrotik-rb91x.patch create mode 100644 target/linux/ath79/patches-5.4/939-mikrotik-rb91x.patch diff --git a/target/linux/ath79/files/drivers/gpio/gpio-latch.c b/target/linux/ath79/files/drivers/gpio/gpio-latch.c new file mode 100644 index 0000000000..cb80b29052 --- /dev/null +++ b/target/linux/ath79/files/drivers/gpio/gpio-latch.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * GPIO latch driver + * + * Copyright (C) 2014 Gabor Juhos <[email protected]> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> + +#define GPIO_LATCH_DRIVER_NAME "gpio-latch" +#define GPIO_LATCH_LINES 9 + +struct gpio_latch_chip { + struct gpio_chip gc; + struct mutex mutex; + struct mutex latch_mutex; + bool latch_enabled; + int le_gpio; + bool le_active_low; + struct gpio_desc **gpios; +}; + +static inline struct gpio_latch_chip *to_gpio_latch_chip(struct gpio_chip *gc) +{ + return container_of(gc, struct gpio_latch_chip, gc); +} + +static void gpio_latch_lock(struct gpio_latch_chip *glc, bool enable) +{ + mutex_lock(&glc->mutex); + + if (enable) + glc->latch_enabled = true; + + if (glc->latch_enabled) + mutex_lock(&glc->latch_mutex); +} + +static void gpio_latch_unlock(struct gpio_latch_chip *glc, bool disable) +{ + if (glc->latch_enabled) + mutex_unlock(&glc->latch_mutex); + + if (disable) + glc->latch_enabled = true; + + mutex_unlock(&glc->mutex); +} + +static int +gpio_latch_get(struct gpio_chip *gc, unsigned offset) +{ + struct gpio_latch_chip *glc = to_gpio_latch_chip(gc); + int ret; + + gpio_latch_lock(glc, false); + ret = gpiod_get_value(glc->gpios[offset]); + gpio_latch_unlock(glc, false); + + return ret; +} + +static void +gpio_latch_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct gpio_latch_chip *glc = to_gpio_latch_chip(gc); + bool enable_latch = false; + bool disable_latch = false; + + if (offset == glc->le_gpio) { + enable_latch = value ^ glc->le_active_low; + disable_latch = !enable_latch; + } + + gpio_latch_lock(glc, enable_latch); + gpiod_set_value(glc->gpios[offset], value); + gpio_latch_unlock(glc, disable_latch); +} + +static int +gpio_latch_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct gpio_latch_chip *glc = to_gpio_latch_chip(gc); + int ret; + + gpio_latch_lock(glc, false); + ret = gpiod_direction_input(glc->gpios[offset]); + gpio_latch_unlock(glc, false); + + return ret; +} + +static int +gpio_latch_direction_output(struct gpio_chip *gc, unsigned offset, int value) +{ + struct gpio_latch_chip *glc = to_gpio_latch_chip(gc); + bool enable_latch = false; + bool disable_latch = false; + int ret; + + if (offset == glc->le_gpio) { + enable_latch = value ^ glc->le_active_low; + disable_latch = !enable_latch; + } + + gpio_latch_lock(glc, enable_latch); + ret = gpiod_direction_output(glc->gpios[offset], value); + gpio_latch_unlock(glc, disable_latch); + + return ret; +} + +static int gpio_latch_probe(struct platform_device *pdev) +{ + struct gpio_latch_chip *glc; + struct gpio_chip *gc; + struct device *dev = &pdev->dev; + struct device_node *of_node = dev->of_node; + struct gpio_descs *gpios; + int i; + enum of_gpio_flags flags; + + glc = devm_kzalloc(dev, sizeof(*glc), GFP_KERNEL); + if (!glc) + return -ENOMEM; + + mutex_init(&glc->mutex); + mutex_init(&glc->latch_mutex); + + gpios = devm_gpiod_get_array(dev, NULL, 0); + if (IS_ERR(gpios)) { + dev_err(dev, "failed to get gpios: %d\n", (int)gpios); + return -EINVAL; + } + glc->gpios = gpios->desc; + + if (gpios->ndescs != GPIO_LATCH_LINES) { + dev_err(dev, "gpios count must be %d\n", GPIO_LATCH_LINES); + return -EINVAL; + } + + glc->le_gpio = of_get_named_gpio_flags(of_node, "latch-enable-gpios", 0, + &flags); + if (glc->le_gpio < 0) { + dev_err(dev, + "could not read required 'latch-enable-gpios' property: %d\n", + glc->le_gpio); + return -EINVAL; + } + glc->le_active_low = (flags == OF_GPIO_ACTIVE_LOW) ? true : false; + + for (i = 0; i < gpios->ndescs; i++) { + if (glc->le_gpio == desc_to_gpio(glc->gpios[i])) { + glc->le_gpio = i; + break; + } + } + + if (i == gpios->ndescs) { + dev_err(dev, "latch-enable-gpio must be in gpios list\n"); + return -EINVAL; + } + + gc = &glc->gc; + gc->label = GPIO_LATCH_DRIVER_NAME; + gc->can_sleep = true; + gc->base = -1; + gc->ngpio = gpios->ndescs; + gc->get = gpio_latch_get; + gc->set = gpio_latch_set; + gc->direction_input = gpio_latch_direction_input, + gc->direction_output = gpio_latch_direction_output; + gc->of_node = of_node; + + platform_set_drvdata(pdev, glc); + + i = gpiochip_add(&glc->gc); + if (i) { + dev_err(dev, "gpiochip_add() failed: %d\n", i); + return i; + } + + return 0; +} + +static int gpio_latch_remove(struct platform_device *pdev) +{ + struct gpio_latch_chip *glc = platform_get_drvdata(pdev); + + gpiochip_remove(&glc->gc); + return 0; +} + +static const struct of_device_id gpio_latch_match[] = { + { .compatible = GPIO_LATCH_DRIVER_NAME }, + {}, +}; + +MODULE_DEVICE_TABLE(of, gpio_latch_match); + +static struct platform_driver gpio_latch_driver = { + .probe = gpio_latch_probe, + .remove = gpio_latch_remove, + .driver = { + .name = GPIO_LATCH_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = gpio_latch_match, + }, +}; + +module_platform_driver(gpio_latch_driver); + +MODULE_DESCRIPTION("GPIO latch driver"); +MODULE_AUTHOR("Gabor Juhos <[email protected]>"); +MODULE_AUTHOR("Denis Kalashnikov <[email protected]>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" GPIO_LATCH_DRIVER_NAME); diff --git a/target/linux/ath79/patches-5.10/939-mikrotik-rb91x.patch b/target/linux/ath79/patches-5.10/939-mikrotik-rb91x.patch new file mode 100644 index 0000000000..9f6441cc3c --- /dev/null +++ b/target/linux/ath79/patches-5.10/939-mikrotik-rb91x.patch @@ -0,0 +1,25 @@ +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -1524,6 +1524,12 @@ config GPIO_RB4XX + help + GPIO driver for Mikrotik Routerboard RB4xx series. + ++config GPIO_LATCH ++ tristate "Support for GPIO on latch on Mikrotik RouterBoards" ++ depends on ATH79 ++ help ++ GPIO driver for latch on Mikrotik Routerboards. ++ + endmenu + + menu "SPI GPIO expanders" +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -72,6 +72,7 @@ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o + obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o + obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o + obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o ++obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o + obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o + obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o + obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o diff --git a/target/linux/ath79/patches-5.4/939-mikrotik-rb91x.patch b/target/linux/ath79/patches-5.4/939-mikrotik-rb91x.patch new file mode 100644 index 0000000000..94b98445e9 --- /dev/null +++ b/target/linux/ath79/patches-5.4/939-mikrotik-rb91x.patch @@ -0,0 +1,23 @@ +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -130,6 +130,10 @@ config GPIO_ATH79 + Select this option to enable GPIO driver for + Atheros AR71XX/AR724X/AR913X SoC devices. + ++config GPIO_LATCH ++ tristate "Mikrotik GPIO latch driver" ++ depends on ATH79 ++ + config GPIO_RASPBERRYPI_EXP + tristate "Raspberry Pi 3 GPIO Expander" + default RASPBERRYPI_FIRMWARE +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o + obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o + obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o + obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o ++obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o + obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o + obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o + obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o -- 2.26.3 _______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/mailman/listinfo/openwrt-devel
