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

kernel test robot Feb. 23, 2021, 11:22 p.m. UTC | #1
Hi Mauri,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on gpio/for-next]
[also build test WARNING on v5.11 next-20210223]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Mauri-Sandberg/gpio-driver-for-the-NXP-74HC153-chip/20210224-040026
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/04cf14b1b4dad0702e35202513962925fdf8113f
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Mauri-Sandberg/gpio-driver-for-the-NXP-74HC153-chip/20210224-040026
        git checkout 04cf14b1b4dad0702e35202513962925fdf8113f
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpio/gpio-nxp-74hc153.c: In function 'nxp_74hc153_get_value':
>> drivers/gpio/gpio-nxp-74hc153.c:75:36: warning: variable 'pdata' set but not used [-Wunused-but-set-variable]
      75 |  struct nxp_74hc153_platform_data *pdata;
         |                                    ^~~~~


vim +/pdata +75 drivers/gpio/gpio-nxp-74hc153.c

    71	
    72	static int nxp_74hc153_get_value(struct gpio_chip *gc, unsigned offset)
    73	{
    74		struct nxp_74hc153_chip *nxp;
  > 75		struct nxp_74hc153_platform_data *pdata;
    76		unsigned s0;
    77		unsigned s1;
    78		unsigned pin;
    79		int ret;
    80	
    81		nxp = gpio_to_nxp(gc);
    82		pdata = nxp->parent->platform_data;
    83	
    84		s0 = !!(offset & NXP_74HC153_S0_MASK);
    85		s1 = !!(offset & NXP_74HC153_S1_MASK);
    86		pin = (offset & NXP_74HC153_BANK_MASK) ? nxp->config.gpio_pin_2y
    87		                                       : nxp->config.gpio_pin_1y;
    88	
    89		mutex_lock(&nxp->lock);
    90		gpio_set_value(nxp->config.gpio_pin_s0, s0);
    91		gpio_set_value(nxp->config.gpio_pin_s1, s1);
    92		ret = gpio_get_value(pin);
    93		mutex_unlock(&nxp->lock);
    94	
    95		return ret;
    96	}
    97	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Feb. 23, 2021, 11:47 p.m. UTC | #2
Hi Mauri,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on gpio/for-next]
[also build test ERROR on v5.11 next-20210223]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Mauri-Sandberg/gpio-driver-for-the-NXP-74HC153-chip/20210224-040026
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: s390-allmodconfig (attached as .config)
compiler: s390-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/04cf14b1b4dad0702e35202513962925fdf8113f
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Mauri-Sandberg/gpio-driver-for-the-NXP-74HC153-chip/20210224-040026
        git checkout 04cf14b1b4dad0702e35202513962925fdf8113f
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=s390 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpio/gpio-nxp-74hc153.c: In function 'nxp_74hc153_get_value':
   drivers/gpio/gpio-nxp-74hc153.c:75:36: warning: variable 'pdata' set but not used [-Wunused-but-set-variable]
      75 |  struct nxp_74hc153_platform_data *pdata;
         |                                    ^~~~~
   drivers/gpio/gpio-nxp-74hc153.c: In function 'nxp_74hc153_probe':
>> drivers/gpio/gpio-nxp-74hc153.c:216:4: error: 'struct gpio_chip' has no member named 'of_node'
     216 |  gc->of_node = np;
         |    ^~


vim +216 drivers/gpio/gpio-nxp-74hc153.c

   103	
   104	static int nxp_74hc153_probe(struct platform_device *pdev)
   105	{
   106		struct device_node *np = pdev->dev.of_node;
   107		struct nxp_74hc153_chip *nxp;
   108		struct gpio_chip *gc;
   109		int err;
   110		unsigned gpio_s0;
   111		unsigned gpio_s1;
   112		unsigned gpio_1y;
   113	        unsigned gpio_2y;
   114	
   115		nxp = kzalloc(sizeof(struct nxp_74hc153_chip), GFP_KERNEL);
   116		if (nxp == NULL) {
   117			dev_err(&pdev->dev, "no memory for private data\n");
   118			return -ENOMEM;
   119		}
   120	
   121		gpio_s0 = of_get_named_gpio(np, "gpio-s0", 0);
   122		gpio_s1 = of_get_named_gpio(np, "gpio-s1", 0);
   123		gpio_1y = of_get_named_gpio(np, "gpio-1y", 0);
   124		gpio_2y = of_get_named_gpio(np, "gpio-2y", 0);
   125	
   126		if (!gpio_is_valid(gpio_s0) || !gpio_is_valid(gpio_s1) ||
   127	  	    !gpio_is_valid(gpio_1y) || !gpio_is_valid(gpio_2y)) {
   128	
   129			dev_err(&pdev->dev, "control GPIO(s) are missing\n");
   130			err = -EINVAL;
   131			goto err_free_nxp;
   132		} else {
   133			nxp->config.gpio_pin_s0 = gpio_s0;
   134			nxp->config.gpio_pin_s1 = gpio_s1;
   135			nxp->config.gpio_pin_1y = gpio_1y;
   136			nxp->config.gpio_pin_2y = gpio_2y;
   137		}
   138	
   139		// apply pin configuration
   140		err = gpio_request(nxp->config.gpio_pin_s0, dev_name(&pdev->dev));
   141		if (err) {
   142			dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
   143				nxp->config.gpio_pin_s0, err);
   144			goto err_free_nxp;
   145		}
   146	
   147		err = gpio_request(nxp->config.gpio_pin_s1, dev_name(&pdev->dev));
   148		if (err) {
   149			dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
   150				nxp->config.gpio_pin_s1, err);
   151			goto err_free_s0;
   152		}
   153	
   154		err = gpio_request(nxp->config.gpio_pin_1y, dev_name(&pdev->dev));
   155		if (err) {
   156			dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
   157				nxp->config.gpio_pin_1y, err);
   158			goto err_free_s1;
   159		}
   160	
   161		err = gpio_request(nxp->config.gpio_pin_2y, dev_name(&pdev->dev));
   162		if (err) {
   163			dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
   164				nxp->config.gpio_pin_2y, err);
   165			goto err_free_1y;
   166		}
   167	
   168		err = gpio_direction_output(nxp->config.gpio_pin_s0, 0);
   169		if (err) {
   170			dev_err(&pdev->dev,
   171				"unable to set direction of gpio %u, err=%d\n",
   172				nxp->config.gpio_pin_s0, err);
   173			goto err_free_2y;
   174		}
   175	
   176		err = gpio_direction_output(nxp->config.gpio_pin_s1, 0);
   177		if (err) {
   178			dev_err(&pdev->dev,
   179				"unable to set direction of gpio %u, err=%d\n",
   180				nxp->config.gpio_pin_s1, err);
   181			goto err_free_2y;
   182		}
   183	
   184		err = gpio_direction_input(nxp->config.gpio_pin_1y);
   185		if (err) {
   186			dev_err(&pdev->dev,
   187				"unable to set direction of gpio %u, err=%d\n",
   188				nxp->config.gpio_pin_1y, err);
   189			goto err_free_2y;
   190		}
   191	
   192		err = gpio_direction_input(nxp->config.gpio_pin_2y);
   193		if (err) {
   194			dev_err(&pdev->dev,
   195				"unable to set direction of gpio %u, err=%d\n",
   196				nxp->config.gpio_pin_2y, err);
   197			goto err_free_2y;
   198		}
   199	
   200		nxp->parent = &pdev->dev;
   201		mutex_init(&nxp->lock);
   202	
   203		gc = &nxp->gpio_chip;
   204	
   205		gc->direction_input  = nxp_74hc153_direction_input;
   206		gc->direction_output = nxp_74hc153_direction_output;
   207		gc->get = nxp_74hc153_get_value;
   208		gc->set = nxp_74hc153_set_value;
   209		gc->can_sleep = 1;
   210	
   211		gc->base = -1;
   212		gc->ngpio = NXP_74HC153_NUM_GPIOS;
   213		gc->label = dev_name(nxp->parent);
   214		gc->parent = nxp->parent;
   215		gc->owner = THIS_MODULE;
 > 216		gc->of_node = np;
   217	
   218		err = gpiochip_add(&nxp->gpio_chip);
   219		if (err) {
   220			dev_err(&pdev->dev, "unable to add gpio chip, err=%d\n", err);
   221			goto err_free_2y;
   222		}
   223	
   224		platform_set_drvdata(pdev, nxp);
   225		return 0;
   226	
   227	err_free_2y:
   228		gpio_free(nxp->config.gpio_pin_2y);
   229	err_free_1y:
   230		gpio_free(nxp->config.gpio_pin_1y);
   231	err_free_s1:
   232		gpio_free(nxp->config.gpio_pin_s1);
   233	err_free_s0:
   234		gpio_free(nxp->config.gpio_pin_s0);
   235	err_free_nxp:
   236		kfree(nxp);
   237		return err;
   238	}
   239	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Drew Fustini April 2, 2021, 8:27 p.m. UTC | #3
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 | #4
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.
Mauri Sandberg April 4, 2021, 2:30 p.m. UTC | #5
> ----------------------------------------
> 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 | #6
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 | #7
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/
Mauri Sandberg April 5, 2021, 8:25 a.m. UTC | #8
> ----------------------------------------
> 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 | #9
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/
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);