[U-Boot] [PATCH] gpio: add driver for PCA9539 16-bit I2C gpio expander

Chris Packham judge.packham at gmail.com
Mon Dec 6 22:48:42 CET 2010


This adds support for the PCA9539 family of gpio devices which have 16
output pins. The devices are similar to chips that use the pca953x driver
except the register map is expanded (in a non-backwards compatible manner)
to allow for the extra 8 pins.

This driver has one gotcha that you can only set the top or bottom 8 bits
at a time. For example to set the 16 pins to be outputs you need to make
the function calls

  pca9539_set_dir(PCA9539_ADDR, 0xff00, 0x0000);
  pca9539_set_dir(PCA9539_ADDR, 0x00ff, 0x0000);

Signed-off-by: Chris Packham <chris.packham at alliedtelesis.co.nz>
---
Hi,

I have a couple of questions related to my patch. Firstly is anyone
interested in
support for these gpio devices? Secondly is my gotcha acceptable or should I
put some effort into making it handle a 16-bit argument in 1 hit?

I toyed with the idea of making this part of the pca953x driver. I
didn't because
the register layout is different so I'd still need to define PCA9539 specific
functions and macros (although pca953x_reg_write could be re-used). I also
figured that some people may want to define only CONFIG_PCA9539 (that is
the case for me at the moment but the overhead of CONFIG_PCA953X wouldn't
push the size of my image over any boundary).

 drivers/gpio/Makefile  |    1 +
 drivers/gpio/pca9539.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/pca9539.h      |   36 +++++++++++++++++++
 3 files changed, 129 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/pca9539.c
 create mode 100644 include/pca9539.h

diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 398024c..3d7bde5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 COBJS-$(CONFIG_KIRKWOOD_GPIO)	+= kw_gpio.o
 COBJS-$(CONFIG_MXC_GPIO)	+= mxc_gpio.o
 COBJS-$(CONFIG_PCA953X)		+= pca953x.o
+COBJS-$(CONFIG_PCA9539)		+= pca9539.o
 COBJS-$(CONFIG_S5P)		+= s5p_gpio.o

 COBJS	:= $(COBJS-y)
diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca9539.c
new file mode 100644
index 0000000..f27ee1b
--- /dev/null
+++ b/drivers/gpio/pca9539.c
@@ -0,0 +1,92 @@
+/*
+ * Support for NXP's 16-bit I2C gpio expander
+ *
+ * Copyright (c) 2010 Allied Telesis Labs
+ *
+ * Based on pca953x.c
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+#include <common.h>
+#include <i2c.h>
+#include <pca9539.h>
+
+static int pca9539_reg_write(uint8_t chip, uint addr, uint mask, uint data)
+{
+	uint8_t val;
+
+	if (i2c_read(chip, addr, 1, &val, 1))
+		return -1;
+
+	val &= ~mask;
+	val |= data;
+
+	return i2c_write(chip, addr, 1, &val, 1);
+}
+
+/*
+ * Set output value of IO pins in 'mask' to corresponding value in 'data'
+ * 0 = low, 1 = high
+ */
+int pca9539_set_val(uint8_t chip, uint mask, uint data)
+{
+	uint addr = PCA9539_OUT0;
+	if (mask & 0xff00) {
+		addr = PCA9539_OUT1;
+		mask = mask >> 8;
+		data = data >> 8;
+	}
+	return pca9539_reg_write(chip, addr, mask, data);
+}
+
+/*
+ * Set read polarity of IO pins in 'mask' to corresponding value in 'data'
+ * 0 = read pin value, 1 = read inverted pin value
+ */
+int pca9539_set_pol(uint8_t chip, uint mask, uint data)
+{
+	uint addr = PCA9539_POL0;
+	if (mask & 0xff00) {
+		addr = PCA9539_POL1;
+		mask = mask >> 8;
+		data = data >> 8;
+	}
+	return pca9539_reg_write(chip, addr, mask, data);
+}
+
+/*
+ * Set direction of IO pins in 'mask' to corresponding value in 'data'
+ * 0 = output, 1 = input
+ */
+int pca9539_set_dir(uint8_t chip, uint mask, uint data)
+{
+	uint addr = PCA9539_CONF0;
+	if (mask & 0xff00) {
+		addr = PCA9539_CONF1;
+		mask = mask >> 8;
+		data = data >> 8;
+	}
+	return pca9539_reg_write(chip, addr, mask, data);
+}
+
+/*
+ * Read current logic level of all IO pins
+ */
+int pca9539_get_val(uint8_t chip)
+{
+	uint8_t val;
+	int value;
+
+	if (i2c_read(chip, PCA9539_IN0, 1, &val, 1))
+		return -1;
+	value = val;
+
+	if (i2c_read(chip, PCA9539_IN1, 1, &val, 1))
+		return -1;
+	value |= val << 8;
+
+	return value;
+}
diff --git a/include/pca9539.h b/include/pca9539.h
new file mode 100644
index 0000000..83793b1
--- /dev/null
+++ b/include/pca9539.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Allied Telesis Labs
+ *
+ * Based on pca953x.h
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __PCA9539_H_
+#define __PCA9539_H_
+
+#define PCA9539_IN0	0x00
+#define PCA9539_IN1	0x01
+#define PCA9539_OUT0	0x02
+#define PCA9539_OUT1	0x03
+#define PCA9539_POL0	0x04
+#define PCA9539_POL1	0x05
+#define PCA9539_CONF0	0x06
+#define PCA9539_CONF1	0x07
+
+#define PCA9539_OUT_LOW		0
+#define PCA9539_OUT_HIGH	1
+#define PCA9539_POL_NORMAL	0
+#define PCA9539_POL_INVERT	1
+#define PCA9539_DIR_OUT		0
+#define PCA9539_DIR_IN		1
+
+int pca9539_set_val(u8 chip, uint mask, uint data);
+int pca9539_set_pol(u8 chip, uint mask, uint data);
+int pca9539_set_dir(u8 chip, uint mask, uint data);
+int pca9539_get_val(u8 chip);
+
+#endif /* __PCA9539_H_ */
-- 
1.7.3.2


More information about the U-Boot mailing list