diff mbox series

gpio: driver for the NXP 74HC153 chip

Message ID 20210223195326.1355245-2-sandberg@mailfence.com
State New
Headers show
Series gpio: driver for the NXP 74HC153 chip | expand

Commit Message

Mauri Sandberg Feb. 23, 2021, 7:53 p.m. UTC
Support for NXP 74HC153 Dual 4-input Multiplexer. This provides a GPIO
interface supporting input mode only

74HCT153 is a dual 4-input multiplexer. The device features independent
enable inputs (nE) and common data select inputs (S0 and S1). For each
multiplexer, the select inputs select one of the four binary inputs and
routes it to the multiplexer output (nY).

Signed-off-by: Mauri Sandberg <sandberg@mailfence.com>
---
 drivers/gpio/Kconfig            |   8 +
 drivers/gpio/Makefile           |   1 +
 drivers/gpio/gpio-nxp-74hc153.c | 291 ++++++++++++++++++++++++++++++++
 3 files changed, 300 insertions(+)
 create mode 100644 drivers/gpio/gpio-nxp-74hc153.c

Comments

Drew Fustini April 2, 2021, 8:27 p.m. UTC | #1
On Tue, Feb 23, 2021 at 11:56 AM Mauri Sandberg <sandberg@mailfence.com> wrote:
>

> Support for NXP 74HC153 Dual 4-input Multiplexer. This provides a GPIO

> interface supporting input mode only


I would like to try this out.   This seems like a commodity part so I
looked for it in a DIP package.  I only see that from TI in the
SN74HC153N.  Do you anticipate a different vendor being a problem?

thanks,
drew
Andy Shevchenko April 3, 2021, 9:39 a.m. UTC | #2
On Wed, Feb 24, 2021 at 2:56 AM kernel test robot <lkp@intel.com> wrote:
>

> Hi Mauri,


Mauri, besides kbuild bot complaints, this patch has several major issues:
 - it doesn't use gpio-mux and mux APIs
 - it supports a single mux chip (or similar ones, like 4->2), however
we would like to have something more generic
 - it uses outdated GPIO APIs
 - it doesn't use managed resources API
 - it has traces of legacy platform data (kbuild bot)

Sorry, but NAK from me. Please, reconsider the design, that we may
discuss even without code. When settled, we may have the first
implementations done.

-- 
With Best Regards,
Andy Shevchenko
Mauri Sandberg April 4, 2021, 2:30 p.m. UTC | #3
> ----------------------------------------

> From: Drew Fustini <drew@beagleboard.org>

> On Tue, Feb 23, 2021 at 11:56 AM Mauri Sandberg <sandberg@mailfence.com> wrote:

> >

> > Support for NXP 74HC153 Dual 4-input Multiplexer. This provides a GPIO

> > interface supporting input mode only

> 

> I would like to try this out.   This seems like a commodity part so I

> looked for it in a DIP package.  I only see that from TI in the

> SN74HC153N.  Do you anticipate a different vendor being a problem?


Oh I am so sorry you guys had to see this. This is based on something I found and assumed to be up to
standards and thought of trying to upstream it with modifications to device tree functionality only. Soon
afterwards I realised its shortcomings in the GPIO api department and being too specific and sent a proposal
what's now known as 'gpio-mux-input'. No further efforts should be put into this.

I do not know how to withdraw a patch. Also, maybe I should have used the same thread with v2 instead
of sending a new patch with new title.

Apologies once again,
Mauri
Drew Fustini April 4, 2021, 3:35 p.m. UTC | #4
On Sun, Apr 4, 2021, 07:30 Mauri Sandberg <sandberg@mailfence.com> wrote:
>

> > ----------------------------------------

> > From: Drew Fustini <drew@beagleboard.org>

> > On Tue, Feb 23, 2021 at 11:56 AM Mauri Sandberg <sandberg@mailfence.com> wrote:

> > >

> > > Support for NXP 74HC153 Dual 4-input Multiplexer. This provides a GPIO

> > > interface supporting input mode only

> >

> > I would like to try this out.   This seems like a commodity part so I

> > looked for it in a DIP package.  I only see that from TI in the

> > SN74HC153N.  Do you anticipate a different vendor being a problem?

>

> Oh I am so sorry you guys had to see this. This is based on something I found and assumed to be up to

> standards and thought of trying to upstream it with modifications to device tree functionality only. Soon

> afterwards I realised its shortcomings in the GPIO api department and being too specific and sent a proposal

> what's now known as 'gpio-mux-input'. No further efforts should be put into this.

>

> I do not know how to withdraw a patch. Also, maybe I should have used the same thread with v2 instead

> of sending a new patch with new title.


No problem, I should not have replied to this old email, I had just
searched for the mention of the IC.

Do you think TI SN74HC153N should be ok for testing the gpio input
multiplexer patch [1]?

Thanks,
Drew

[1] https://lore.kernel.org/linux-gpio/20210325122832.119147-1-sandberg@mailfence.com/
Andy Shevchenko April 4, 2021, 5:17 p.m. UTC | #5
On Sun, Apr 4, 2021 at 6:36 PM Drew Fustini <drew@beagleboard.org> wrote:
> On Sun, Apr 4, 2021, 07:30 Mauri Sandberg <sandberg@mailfence.com> wrote:


...

> Do you think TI SN74HC153N should be ok for testing the gpio input

> multiplexer patch [1]?


Functionally all those *4xxx153yyy are all analogous.
You even may try soviet copy of it, i.e. 555КП11 (cyrillic letters!,
555 can be 1533 or a few more variants).

> [1] https://lore.kernel.org/linux-gpio/20210325122832.119147-1-sandberg@mailfence.com/




-- 
With Best Regards,
Andy Shevchenko
Mauri Sandberg April 5, 2021, 8:25 a.m. UTC | #6
> ----------------------------------------

> From: Andy Shevchenko <andy.shevchenko@gmail.com>

> On Sun, Apr 4, 2021 at 6:36 PM Drew Fustini <drew@beagleboard.org> wrote:

> > Do you think TI SN74HC153N should be ok for testing the gpio input

> > multiplexer patch [1]?

> 

> Functionally all those *4xxx153yyy are all analogous.

> You even may try soviet copy of it, i.e. 555КП11 (cyrillic letters!,

> 555 can be 1533 or a few more variants).


I really do hope so. The reason for going for [1] is that it should provide a generic mechanism and
be manufacturer independent. :)

> > [1] https://lore.kernel.org/linux-gpio/20210325122832.119147-1-sandberg@mailfence.com/
Andy Shevchenko April 5, 2021, 9:11 a.m. UTC | #7
On Mon, Apr 5, 2021 at 11:25 AM Mauri Sandberg <sandberg@mailfence.com> wrote:
> > From: Andy Shevchenko <andy.shevchenko@gmail.com>

> > On Sun, Apr 4, 2021 at 6:36 PM Drew Fustini <drew@beagleboard.org> wrote:


> I really do hope so. The reason for going for [1] is that it should provide a generic mechanism and

> be manufacturer independent. :)


For some reason I don't see the latest in my mailbox, nevertheless I
have downloaded copy from lore and I'll try to review it sooner than
later.

> > > [1] https://lore.kernel.org/linux-gpio/20210325122832.119147-1-sandberg@mailfence.com/




-- 
With Best Regards,
Andy Shevchenko
diff mbox series

Patch

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index fa225175e68d..62c3aa34ae6e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1645,4 +1645,12 @@  config GPIO_MOCKUP
 
 endmenu
 
+comment "Other GPIO expanders"
+
+config GPIO_NXP_74HC153
+	tristate "NXP 74HC153 Dual 4-input multiplexer"
+	help
+	  Support for NXP 74HC153 Dual 4-input Multiplexer. This
+	  provides a GPIO interface supporting input mode only.
+
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 35e3b6026665..3e4f48e7fd61 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -108,6 +108,7 @@  obj-$(CONFIG_GPIO_MT7621)		+= gpio-mt7621.o
 obj-$(CONFIG_GPIO_MVEBU)		+= gpio-mvebu.o
 obj-$(CONFIG_GPIO_MXC)			+= gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)			+= gpio-mxs.o
+obj-$(CONFIG_GPIO_NXP_74HC153)		+= gpio-nxp-74hc153.o
 obj-$(CONFIG_GPIO_OCTEON)		+= gpio-octeon.o
 obj-$(CONFIG_GPIO_OMAP)			+= gpio-omap.o
 obj-$(CONFIG_GPIO_PALMAS)		+= gpio-palmas.o
diff --git a/drivers/gpio/gpio-nxp-74hc153.c b/drivers/gpio/gpio-nxp-74hc153.c
new file mode 100644
index 000000000000..f683547cfd6b
--- /dev/null
+++ b/drivers/gpio/gpio-nxp-74hc153.c
@@ -0,0 +1,291 @@ 
+/*
+ *  NXP 74HC153 - Dual 4-input multiplexer GPIO driver
+ *
+ *  Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2020 Mauri Sandberg <sandberg@mailfence.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  Example device tree definition:
+ *
+ *  gpio-extender {
+ *    compatible = "nxp,74hc153-gpio";
+ *    gpio-controller;
+ *    #gpio-cells = <2>;
+ *
+ *    // GPIOs used by this node
+ *    gpio-s0 = <&gpio 9 GPIO_ACTIVE_HIGH>;
+ *    gpio-s1 = <&gpio 11 GPIO_ACTIVE_HIGH>;
+ *    gpio-1y = <&gpio 12 GPIO_ACTIVE_HIGH>;
+ *    gpio-2y = <&gpio 14 GPIO_ACTIVE_HIGH>;
+ *  };
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+
+#define NXP_74HC153_NUM_GPIOS   8
+#define NXP_74HC153_S0_MASK     0x1
+#define NXP_74HC153_S1_MASK     0x2
+#define NXP_74HC153_BANK_MASK   0x4
+
+#define NXP_74HC153_DRIVER_NAME "nxp-74hc153"
+
+struct nxp_74hc153_config {
+	unsigned gpio_pin_s0;
+	unsigned gpio_pin_s1;
+	unsigned gpio_pin_1y;
+	unsigned gpio_pin_2y;
+};
+
+struct nxp_74hc153_chip {
+	struct device             *parent;
+	struct gpio_chip          gpio_chip;
+	struct mutex              lock;
+	struct nxp_74hc153_config config;
+};
+
+static struct nxp_74hc153_chip *gpio_to_nxp(struct gpio_chip *gc)
+{
+	return container_of(gc, struct nxp_74hc153_chip, gpio_chip);
+}
+
+static int nxp_74hc153_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	return 0;
+}
+
+static int nxp_74hc153_direction_output(struct gpio_chip *gc,
+					unsigned offset, int val)
+{
+	return -EINVAL;
+}
+
+static int nxp_74hc153_get_value(struct gpio_chip *gc, unsigned offset)
+{
+	struct nxp_74hc153_chip *nxp;
+	struct nxp_74hc153_platform_data *pdata;
+	unsigned s0;
+	unsigned s1;
+	unsigned pin;
+	int ret;
+
+	nxp = gpio_to_nxp(gc);
+	pdata = nxp->parent->platform_data;
+
+	s0 = !!(offset & NXP_74HC153_S0_MASK);
+	s1 = !!(offset & NXP_74HC153_S1_MASK);
+	pin = (offset & NXP_74HC153_BANK_MASK) ? nxp->config.gpio_pin_2y
+	                                       : nxp->config.gpio_pin_1y;
+
+	mutex_lock(&nxp->lock);
+	gpio_set_value(nxp->config.gpio_pin_s0, s0);
+	gpio_set_value(nxp->config.gpio_pin_s1, s1);
+	ret = gpio_get_value(pin);
+	mutex_unlock(&nxp->lock);
+
+	return ret;
+}
+
+static void nxp_74hc153_set_value(struct gpio_chip *gc,
+	unsigned offset, int val)
+{
+	/* not supported */
+}
+
+static int nxp_74hc153_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct nxp_74hc153_chip *nxp;
+	struct gpio_chip *gc;
+	int err;
+	unsigned gpio_s0;
+	unsigned gpio_s1;
+	unsigned gpio_1y;
+        unsigned gpio_2y;
+
+	nxp = kzalloc(sizeof(struct nxp_74hc153_chip), GFP_KERNEL);
+	if (nxp == NULL) {
+		dev_err(&pdev->dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	gpio_s0 = of_get_named_gpio(np, "gpio-s0", 0);
+	gpio_s1 = of_get_named_gpio(np, "gpio-s1", 0);
+	gpio_1y = of_get_named_gpio(np, "gpio-1y", 0);
+	gpio_2y = of_get_named_gpio(np, "gpio-2y", 0);
+
+	if (!gpio_is_valid(gpio_s0) || !gpio_is_valid(gpio_s1) ||
+  	    !gpio_is_valid(gpio_1y) || !gpio_is_valid(gpio_2y)) {
+
+		dev_err(&pdev->dev, "control GPIO(s) are missing\n");
+		err = -EINVAL;
+		goto err_free_nxp;
+	} else {
+		nxp->config.gpio_pin_s0 = gpio_s0;
+		nxp->config.gpio_pin_s1 = gpio_s1;
+		nxp->config.gpio_pin_1y = gpio_1y;
+		nxp->config.gpio_pin_2y = gpio_2y;
+	}
+
+	// apply pin configuration
+	err = gpio_request(nxp->config.gpio_pin_s0, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			nxp->config.gpio_pin_s0, err);
+		goto err_free_nxp;
+	}
+
+	err = gpio_request(nxp->config.gpio_pin_s1, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			nxp->config.gpio_pin_s1, err);
+		goto err_free_s0;
+	}
+
+	err = gpio_request(nxp->config.gpio_pin_1y, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			nxp->config.gpio_pin_1y, err);
+		goto err_free_s1;
+	}
+
+	err = gpio_request(nxp->config.gpio_pin_2y, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			nxp->config.gpio_pin_2y, err);
+		goto err_free_1y;
+	}
+
+	err = gpio_direction_output(nxp->config.gpio_pin_s0, 0);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			nxp->config.gpio_pin_s0, err);
+		goto err_free_2y;
+	}
+
+	err = gpio_direction_output(nxp->config.gpio_pin_s1, 0);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			nxp->config.gpio_pin_s1, err);
+		goto err_free_2y;
+	}
+
+	err = gpio_direction_input(nxp->config.gpio_pin_1y);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			nxp->config.gpio_pin_1y, err);
+		goto err_free_2y;
+	}
+
+	err = gpio_direction_input(nxp->config.gpio_pin_2y);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			nxp->config.gpio_pin_2y, err);
+		goto err_free_2y;
+	}
+
+	nxp->parent = &pdev->dev;
+	mutex_init(&nxp->lock);
+
+	gc = &nxp->gpio_chip;
+
+	gc->direction_input  = nxp_74hc153_direction_input;
+	gc->direction_output = nxp_74hc153_direction_output;
+	gc->get = nxp_74hc153_get_value;
+	gc->set = nxp_74hc153_set_value;
+	gc->can_sleep = 1;
+
+	gc->base = -1;
+	gc->ngpio = NXP_74HC153_NUM_GPIOS;
+	gc->label = dev_name(nxp->parent);
+	gc->parent = nxp->parent;
+	gc->owner = THIS_MODULE;
+	gc->of_node = np;
+
+	err = gpiochip_add(&nxp->gpio_chip);
+	if (err) {
+		dev_err(&pdev->dev, "unable to add gpio chip, err=%d\n", err);
+		goto err_free_2y;
+	}
+
+	platform_set_drvdata(pdev, nxp);
+	return 0;
+
+err_free_2y:
+	gpio_free(nxp->config.gpio_pin_2y);
+err_free_1y:
+	gpio_free(nxp->config.gpio_pin_1y);
+err_free_s1:
+	gpio_free(nxp->config.gpio_pin_s1);
+err_free_s0:
+	gpio_free(nxp->config.gpio_pin_s0);
+err_free_nxp:
+	kfree(nxp);
+	return err;
+}
+
+static int nxp_74hc153_remove(struct platform_device *pdev)
+{
+	struct nxp_74hc153_chip *nxp = platform_get_drvdata(pdev);
+
+	if (nxp) {
+		gpiochip_remove(&nxp->gpio_chip);
+		gpio_free(nxp->config.gpio_pin_2y);
+		gpio_free(nxp->config.gpio_pin_1y);
+		gpio_free(nxp->config.gpio_pin_s1);
+		gpio_free(nxp->config.gpio_pin_s0);
+
+		kfree(nxp);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return 0;
+}
+
+static struct of_device_id nxp_74hc153_id[] = {
+	{
+		.compatible = "nxp,74hc153-gpio",
+		.data = NULL,
+	}, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nxp_74hc153_id);
+
+static struct platform_driver nxp_74hc153_driver = {
+	.probe          = nxp_74hc153_probe,
+	.remove         = nxp_74hc153_remove,
+	.driver = {
+		.name   = NXP_74HC153_DRIVER_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = nxp_74hc153_id,
+	},
+};
+
+static int __init nxp_74hc153_init(void)
+{
+	return platform_driver_register(&nxp_74hc153_driver);
+}
+subsys_initcall(nxp_74hc153_init);
+
+static void __exit nxp_74hc153_exit(void)
+{
+	platform_driver_unregister(&nxp_74hc153_driver);
+}
+module_exit(nxp_74hc153_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("GPIO expander driver for NXP 74HC153");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" NXP_74HC153_DRIVER_NAME);