Hi, > -----Original Message----- > From: openwrt-devel [mailto:[email protected]] > On Behalf Of Denis Kalashnikov > Sent: Donnerstag, 6. Mai 2021 18:25 > To: [email protected] > Cc: Gabor Juhos <[email protected]> > Subject: [PATCH 1/4] ath79: add MFD driver (NAND and GPIO) for Mikrotik > RB91xG > > rb91x-ngl (nand-gpio-latch) requests and controls SoC GPIO lines that are > used for NAND control and data lines multiplexed with a latch. Lines of the > latch that are not used for NAND control lines, are used for power LED and > user LED and a Shift Register nCS. > > Like rb4xx-cpld driver rb91x-ngl provides API for separate NAND driver and > latch-GPIO driver. > > This driver is used in place of the ar71xx gpio-latch driver. > > Signed-off-by: Denis Kalashnikov <[email protected]> > --- > .../linux/ath79/files/drivers/mfd/rb91x-ngl.c | 331 ++++++++++++++++++ > .../linux/ath79/files/include/mfd/rb91x-ngl.h | 59 ++++ > target/linux/ath79/mikrotik/config-default | 1 + > .../patches-5.4/939-mikrotik-rb91x.patch | 21 ++ > 4 files changed, 412 insertions(+) > create mode 100644 target/linux/ath79/files/drivers/mfd/rb91x-ngl.c > create mode 100644 target/linux/ath79/files/include/mfd/rb91x-ngl.h > create mode 100644 target/linux/ath79/patches-5.4/939-mikrotik- > rb91x.patch
Please also take care of 5.10. Best Adrian > > diff --git a/target/linux/ath79/files/drivers/mfd/rb91x-ngl.c > b/target/linux/ath79/files/drivers/mfd/rb91x-ngl.c > new file mode 100644 > index 0000000000..c6ab4631f5 > --- /dev/null > +++ b/target/linux/ath79/files/drivers/mfd/rb91x-ngl.c > @@ -0,0 +1,331 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * MFD driver for the MikroTik RouterBoard NAND controlled through GPIO > + * multiplexed with latch. Why MFD, not pure NAND driver? Since the > +latch > + * lines, that are not used for NAND control lines, are used for GPIO > + * output function -- for leds and other. > + * > + * Copyright (C) 2021 Denis Kalashnikov <[email protected]> > + * > + */ > +#include <linux/mutex.h> > +#include <linux/mfd/core.h> > +#include <linux/module.h> > +#include <linux/of_platform.h> > +#include <linux/of_gpio.h> > + > +#include <mfd/rb91x-ngl.h> > + > +#define DRIVER_NAME "rb91x-nand-gpio-latch" > + > +#define NAND_DATAS 8 > +#define LATCH_GPIOS 3 > + > +static int nand_datas_count(struct rb91x_ngl *ngl) { > + return NAND_DATAS; > +} > + > +static int latch_gpios_count(struct rb91x_ngl *ngl) { > + return LATCH_GPIOS; > +} > + > +static void latch_lock(struct rb91x_ngl *ngl) { > + mutex_lock(&ngl->mutex); > + > + gpio_set_value_cansleep(ngl->gpio[RB91X_NGL_NLE], 0); } > + > +static void latch_unlock(struct rb91x_ngl *ngl) { > + gpio_set_value_cansleep(ngl->gpio[RB91X_NGL_NLE], 1); > + > + mutex_unlock(&ngl->mutex); > +} > + > +#define OFFSET_INVAL(offset) ((offset) < 0 || (offset) >= > +RB91X_NGL_GPIOS) > + > +static void rb91x_ngl_gpio_set_value(struct rb91x_ngl *ngl, int offset, > +int val) { > + if (OFFSET_INVAL(offset)) > + return; > + > + gpio_set_value_cansleep(ngl->gpio[offset], val); } > + > +static void latch_gpio_set_value(struct rb91x_ngl *ngl, int offset, int > +val) { > + if (offset >= LATCH_GPIOS) > + return; > + > + mutex_lock(&ngl->mutex); > + > + gpio_set_value_cansleep(ngl->gpio[RB91X_NGL_LATCH_GPIO0 + > offset], > +val); > + > + mutex_unlock(&ngl->mutex); > +} > + > +static int rb91x_ngl_gpio_get_value(struct rb91x_ngl *ngl, int offset) > +{ > + if (OFFSET_INVAL(offset)) > + return -EINVAL; > + > + return gpio_get_value(ngl->gpio[offset]); > +} > + > +static void rb91x_ngl_gpio_direction_output(struct rb91x_ngl *ngl, int > offset, > + int val) > +{ > + if (OFFSET_INVAL(offset)) > + return; > + > + gpio_direction_output(ngl->gpio[offset], val); } > + > +static void rb91x_ngl_gpio_direction_input(struct rb91x_ngl *ngl, int > +offset) { > + if (OFFSET_INVAL(offset)) > + return; > + > + gpio_direction_input(ngl->gpio[offset]); > +} > + > +static const struct mfd_cell mfd_cells[] = { > + { > + .name = "mikrotik,rb91x-nand", > + .of_compatible = "mikrotik,rb91x-nand", > + }, { > + .name = "mikrotik,rb91x-gpio-latch", > + .of_compatible = "mikrotik,rb91x-gpio-latch", > + }, > +}; > + > +static int get_gpios(struct device *dev, const char *prop_name) { > + int n; > + > + n = of_get_named_gpio(dev->of_node, prop_name, 0); > + if (n < 0) > + dev_err(dev, "Could not read required '%s' property: %d\n", > prop_name, n); > + //pr_info(DRIVER_NAME ": %s = %d\n", prop_name, n); > + > + return n; > +} > + > +/* > + * NOTE: all gpios are labeled with driver name, not with @name. > + * @name is used only in error message. Since we failed to choose > + * a good names for multiplexed gpios. > + */ > +static int req_gpio(struct device *dev, int gpio, const char *name) { > + int ret; > + > + ret = devm_gpio_request(dev, gpio, DRIVER_NAME); > + if (ret) { > + pr_err(DRIVER_NAME ": failed to request gpio %d ('%s'): > %d\n", > + gpio, name, ret); > + return ret; > + } > + > + //pr_info(DRIVER_NAME ": request gpio %d ('%s')\n", gpio, name); > + > + return ret; > +} > + > +static int probe(struct platform_device *pdev) { > + struct device_node *of_node = pdev->dev.of_node; > + struct device *dev = &pdev->dev; > + struct rb91x_ngl *ngl; > + int i, n, ret; > + > + pr_info("rb91x-nand-gpio-latch driver probe\n"); > + > + ngl = devm_kzalloc(dev, sizeof(*ngl), GFP_KERNEL); > + if (!ngl) > + return -ENOMEM; > + > + /* TODO: read gpios flags (active high/low) */ > + > + for (i = 0; i < RB91X_NGL_GPIOS; i++) { > + ngl->gpio[i] = -ENOENT; > + } > + > + /* Read NAND control gpios */ > + ngl->gpio[RB91X_NGL_NAND_NCE] = get_gpios(dev, "nand-nce- > gpios"); > + ngl->gpio[RB91X_NGL_NAND_CLE] = get_gpios(dev, "nand-cle- > gpios"); > + ngl->gpio[RB91X_NGL_NAND_ALE] = get_gpios(dev, "nand-ale- > gpios"); > + ngl->gpio[RB91X_NGL_NAND_NRW] = get_gpios(dev, "nand-nrw- > gpios"); > + ngl->gpio[RB91X_NGL_NAND_RDY] = get_gpios(dev, "nand-rdy- > gpios"); > + ngl->gpio[RB91X_NGL_NAND_READ] = get_gpios(dev, "nand-read- > gpios"); > + > + ngl->gpio[RB91X_NGL_NLE] = get_gpios(dev, "nle-gpios"); > + > + /* Read NAND data gpios */ > + > + n = of_gpio_named_count(of_node, "nand-data-gpios"); > + if (n != NAND_DATAS) { > + dev_err(dev, DRIVER_NAME > + ": required 'nand-data-gpios' property must have %d > gpios\n", > + NAND_DATAS); > + return -EINVAL; > + } > + > + //dev_info(dev, DRIVER_NAME ": nand-data-gpios count = %d\n", > n); > + > + for (i = 0; i < n; i++) { > + ret = of_get_named_gpio(of_node, "nand-data-gpios", i); > + if (ret < 0) { > + dev_err(dev, DRIVER_NAME > + ": Couldn't read required 'nand-data-gpios': %d\n", > + ret); > + return -EINVAL; > + } > + > + //dev_info(dev, DRIVER_NAME ": nand-data-gpios = %d\n", > ret); > + > + ngl->gpio[RB91X_NGL_NAND_DATA0 + i] = ret; > + } > + > + /* Read latch gpios */ > + > + n = of_gpio_named_count(of_node, "latch-gpios"); > + if (n != LATCH_GPIOS) { > + dev_err(dev, DRIVER_NAME > + ": required 'latch-gpios' property must have %d gpios\n", > + LATCH_GPIOS); > + return -EINVAL; > + } > + > + //dev_info(dev, DRIVER_NAME ": latch-gpios count = %d\n", n); > + > + for (i = 0; i < n; i++) { > + ret = of_get_named_gpio(of_node, "latch-gpios", i); > + if (ret < 0) { > + dev_err(dev, DRIVER_NAME > + ": Couldn't read required 'latch-gpios': %d\n", > + ret); > + return -EINVAL; > + } > + > + //dev_info(dev, DRIVER_NAME ": latch-gpios = %d\n", ret); > + > + ngl->gpio[RB91X_NGL_LATCH_GPIO0 + i] = ret; > + } > + > + if (ngl->gpio[RB91X_NGL_NAND_NCE] < 0 > + || ngl->gpio[RB91X_NGL_NAND_CLE] < 0 > + || ngl->gpio[RB91X_NGL_NAND_ALE] < 0 > + || ngl->gpio[RB91X_NGL_NAND_NRW] < 0 > + || ngl->gpio[RB91X_NGL_NAND_RDY] < 0 > + || ngl->gpio[RB91X_NGL_NAND_READ] < 0 > + || ngl->gpio[RB91X_NGL_NLE] < 0) > + return -EINVAL; > + > + /* Request gpios */ > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NLE], "nLE")) > + return -EINVAL; > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NAND_NCE], "NAND-nCE")) > + return -EINVAL; > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NAND_CLE], "NAND-CLE")) > + return -EINVAL; > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NAND_ALE], "NAND-ALE")) > + return -EINVAL; > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NAND_NRW], "NAND- > nRW")) > + return -EINVAL; > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NAND_RDY], "NAND-RDY")) > + return -EINVAL; > + > + if (req_gpio(dev, ngl->gpio[RB91X_NGL_NAND_READ], "NAND- > READ")) > + return -EINVAL; > + > + for (i = 0; i < NAND_DATAS; i++) { > + /* > + * Some data gpios are equal to control gpios. > + * Check this. > + */ > + n = ngl->gpio[RB91X_NGL_NAND_DATA0 + i]; > + if (n == ngl->gpio[RB91X_NGL_NAND_NCE] > + || n == ngl->gpio[RB91X_NGL_NAND_CLE] > + || n == ngl->gpio[RB91X_NGL_NAND_ALE] > + || n == ngl->gpio[RB91X_NGL_NAND_NRW] > + || n == ngl->gpio[RB91X_NGL_NAND_RDY] > + || n == ngl->gpio[RB91X_NGL_NAND_READ]) > + continue; > + if (req_gpio(dev, n, "NAND-DATAx")) > + return -EINVAL; > + } > + > + /* > + * NOTE: We suppose that latch gpios are equal to some > + * control gpios, so they have been already requested. > + */ > + > + ngl->nand_datas_count = nand_datas_count; > + ngl->latch_lock = latch_lock; > + ngl->latch_unlock = latch_unlock; > + ngl->gpio_set_value = rb91x_ngl_gpio_set_value; > + ngl->gpio_get_value = rb91x_ngl_gpio_get_value; > + ngl->gpio_direction_input = rb91x_ngl_gpio_direction_input; > + ngl->gpio_direction_output = rb91x_ngl_gpio_direction_output; > + ngl->latch_gpio_set_value = latch_gpio_set_value; > + ngl->latch_gpios_count = latch_gpios_count; > + > + mutex_init(&ngl->mutex); > + > + dev_set_drvdata(dev, ngl); > + > + /* > + * All gpios and the latch are controlled by NAND driver, > + * but we need to init gpio lines for the latch gpio in case > + * of NAND driver is missing. > + */ > + > + /* Unlock the latch */ > + gpio_direction_output(ngl->gpio[RB91X_NGL_NLE], 1); > + > + /* TODO: are latch gpio lines active high or low? */ > + for (i = 0; i < LATCH_GPIOS; i++) { > + gpio_direction_output(ngl->gpio[RB91X_NGL_LATCH_GPIO0 > + i], 0); > + } > + > + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, > + mfd_cells, ARRAY_SIZE(mfd_cells), > + NULL, 0, NULL); > +} > + > +static int remove(struct platform_device *pdev) { > + return 0; > +} > + > +static const struct of_device_id match[] = { > + { .compatible = "mikrotik,nand-gpio-latch", }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, match); > + > +static struct platform_driver rb91x_ngl_driver = { > + .probe = probe, > + .remove = remove, > + .driver = { > + .name = DRIVER_NAME, > + .owner = THIS_MODULE, > + .of_match_table = of_match_ptr(match), > + }, > +}; > + > +module_platform_driver(rb91x_ngl_driver); > + > +MODULE_DESCRIPTION("Driver for Mikrotik RouterBoard 91x NAND > controlled > +through GPIOs multiplexed with latch"); MODULE_AUTHOR("Denis > +Kalashnikov <[email protected]>"); MODULE_LICENSE("GPL v2"); > diff --git a/target/linux/ath79/files/include/mfd/rb91x-ngl.h > b/target/linux/ath79/files/include/mfd/rb91x-ngl.h > new file mode 100644 > index 0000000000..5360aa7548 > --- /dev/null > +++ b/target/linux/ath79/files/include/mfd/rb91x-ngl.h > @@ -0,0 +1,59 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * MFD driver for the MikroTik RouterBoard 91xG NAND controlled > + * through GPIOs multiplexed with latch (rb91x-nand-gpio-latch). > + * > + * Copyright (C) 2021 Denis Kalashnikov <[email protected]> */ > + > +#include <linux/mutex.h> > + > +enum rb91x_ngl_gpios { > + /* NAND control gpios */ > + RB91X_NGL_NAND_NCE, /* nCE -- Chip Enable, Active Low */ > + RB91X_NGL_NAND_CLE, /* CLE -- Command Latch Enable */ > + RB91X_NGL_NAND_ALE, /* ALE -- Address Latch Enable */ > + RB91X_NGL_NAND_NRW, /* nRW -- Read/Write Enable, Active Low > */ > + RB91X_NGL_NAND_RDY, /* RDY -- NAND Ready */ > + RB91X_NGL_NAND_READ, /* READ */ > + > + RB91X_NGL_NLE, /* nLE -- Latch Enable, Active Low */ > + > + /* NAND data gpios */ > + RB91X_NGL_NAND_DATA0, > + > + /* Latch gpios */ > + RB91X_NGL_LATCH_GPIO0 = RB91X_NGL_NAND_DATA0 + 32, > + > + RB91X_NGL_GPIOS = RB91X_NGL_LATCH_GPIO0 + 32, /* Total > number of gpios > +*/ }; > + > +struct rb91x_ngl { > + /* Public */ > + > + /* API for RB91x NAND controller driver */ > + void (*gpio_set_value)(struct rb91x_ngl *ngl, int offset, int val); > + void (*gpio_direction_input)(struct rb91x_ngl *ngl, int offset); > + void (*gpio_direction_output)(struct rb91x_ngl *ngl, int offset, > + int val); > + int (*gpio_get_value)(struct rb91x_ngl *ngl, int offset); > + void (*latch_lock)(struct rb91x_ngl *ngl); > + void (*latch_unlock)(struct rb91x_ngl *ngl); > + int (*nand_datas_count)(struct rb91x_ngl *ngl); > + > + /* API for RB91x gpio latch controller driver */ > + void (*latch_gpio_set_value)(struct rb91x_ngl *ngl, int offset, > + int val); > + int (*latch_gpios_count)(struct rb91x_ngl *ngl); > + > + > + /* Private */ > + > + /* > + * To synchronize access of NAND driver and GPIO driver > + * to shared gpio lines. > + */ > + struct mutex mutex; > + > + int gpio[RB91X_NGL_GPIOS]; > +}; > diff --git a/target/linux/ath79/mikrotik/config-default > b/target/linux/ath79/mikrotik/config-default > index 1e637bdfd3..67c980a491 100644 > --- a/target/linux/ath79/mikrotik/config-default > +++ b/target/linux/ath79/mikrotik/config-default > @@ -8,6 +8,7 @@ CONFIG_LEDS_RESET=y > CONFIG_LZO_DECOMPRESS=y > CONFIG_MDIO_GPIO=y > CONFIG_MFD_RB4XX_CPLD=y > +CONFIG_MFD_RB91X_NGL=y > CONFIG_MIKROTIK=y > CONFIG_MIKROTIK_RB_SYSFS=y > CONFIG_MTD_NAND=y > 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..a85db0892c > --- /dev/null > +++ b/target/linux/ath79/patches-5.4/939-mikrotik-rb91x.patch > @@ -0,0 +1,21 @@ > +--- a/drivers/mfd/Kconfig > ++++ b/drivers/mfd/Kconfig > +@@ -2020,5 +2020,10 @@ config MFD_RB4XX_CPLD > + Enables support for the CPLD chip (NAND & GPIO) on Mikrotik > + Routerboard RB4xx series. > + > ++config MFD_RB91X_NGL > ++ tristate "Mikrotik RB91x NAND and GPIO driver > ++ select MFD_CORE > ++ depends on ATH79 || COMPILE_TEST > ++ > + endmenu > + endif > +--- a/drivers/mfd/Makefile > ++++ b/drivers/mfd/Makefile > +@@ -257,3 +257,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX) += > rohm-b > + obj-$(CONFIG_MFD_STMFX) += stmfx.o > + > + obj-$(CONFIG_MFD_RB4XX_CPLD) += rb4xx-cpld.o > ++ > ++obj-$(CONFIG_MFD_RB91X_NGL) += rb91x-ngl.o > -- > 2.26.3 > > > _______________________________________________ > openwrt-devel mailing list > [email protected] > https://lists.openwrt.org/mailman/listinfo/openwrt-devel
openpgp-digital-signature.asc
Description: PGP signature
_______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/mailman/listinfo/openwrt-devel
