linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mauri Sandberg <sandberg@mailfence.com>
To: linux-gpio@vger.kernel.org
Cc: Mauri Sandberg <sandberg@mailfence.com>
Subject: [PATCH] gpio: driver for the NXP 74HC153 chip
Date: Tue, 23 Feb 2021 21:53:26 +0200	[thread overview]
Message-ID: <20210223195326.1355245-2-sandberg@mailfence.com> (raw)
In-Reply-To: <20210223195326.1355245-1-sandberg@mailfence.com>

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

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);
-- 
2.25.1


  reply	other threads:[~2021-02-23 19:55 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-23 19:53 [RFC] Driver for the NXP 74HC153 chip Mauri Sandberg
2021-02-23 19:53 ` Mauri Sandberg [this message]
2021-02-23 23:22   ` [PATCH] gpio: driver " kernel test robot
2021-04-03  9:39     ` Andy Shevchenko
2021-02-23 23:47   ` kernel test robot
2021-04-02 20:27   ` Drew Fustini
2021-04-04 14:30     ` Mauri Sandberg
2021-04-04 15:35       ` Drew Fustini
2021-04-04 17:17         ` Andy Shevchenko
2021-04-05  8:25           ` Mauri Sandberg
2021-04-05  9:11             ` Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210223195326.1355245-2-sandberg@mailfence.com \
    --to=sandberg@mailfence.com \
    --cc=linux-gpio@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).