[U-Boot] [PATCH 3/8] drivers/misc: add stmpe2401 port extender and keypad controller
Alessandro Rubini
rubini-list at gnudd.com
Fri Oct 9 13:17:11 CEST 2009
From: Alessandro Rubini <rubini at unipv.it>
Signed-off-by: Alessandro Rubini <rubini at unipv.it>
Acked-by: Andrea Gallo <andrea.gallo at stericsson.com>
---
drivers/misc/Makefile | 1 +
drivers/misc/stmpe2401.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++
include/stmpe2401.h | 66 +++++++++++++++++
3 files changed, 243 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/stmpe2401.c
create mode 100644 include/stmpe2401.h
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f6df60f..76c009a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -30,6 +30,7 @@ COBJS-$(CONFIG_DS4510) += ds4510.o
COBJS-$(CONFIG_FSL_LAW) += fsl_law.o
COBJS-$(CONFIG_NS87308) += ns87308.o
COBJS-$(CONFIG_STATUS_LED) += status_led.o
+COBJS-$(CONFIG_STMPE2401) += stmpe2401.o
COBJS-$(CONFIG_TWL4030_LED) += twl4030_led.o
COBJS := $(COBJS-y)
diff --git a/drivers/misc/stmpe2401.c b/drivers/misc/stmpe2401.c
new file mode 100644
index 0000000..9bab1b4
--- /dev/null
+++ b/drivers/misc/stmpe2401.c
@@ -0,0 +1,176 @@
+/*
+ * board/st/nhk8815/egpio.c: extended gpio as found on nhk8815 board
+ *
+ * Copyright 2009 Alessandro Rubini <rubini at unipv.it>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <i2c.h>
+#include <stmpe2401.h>
+
+/*
+ * First, an interface to set and read registers, used in this file as well
+ */
+int pe_getreg(int addr, int reg)
+{
+ unsigned char val8 = reg;
+ int ret;
+
+ ret = i2c_read(addr, reg, 1 /* len */, &val8, 1);
+ if (ret < 0) return ret;
+ return val8;
+}
+
+int pe_setreg(int addr, int reg, int val)
+{
+ unsigned char val8 = val;
+
+ return i2c_write(addr, reg, 1, &val8, 1);
+}
+
+/*
+ * Generic higher-level GPIO interface
+ */
+int pe_gpio_af(int addr, int pin, int af)
+{
+ int regval;
+
+ regval = pe_getreg(addr, PE_GPIO_AFR(pin));
+ if (regval < 0) return regval;
+ regval &= ~PE_GPIO_AF_MASK(pin);
+ regval |= af << PE_GPIO_AF_SHIFT(pin);
+ return pe_setreg(addr, PE_GPIO_AFR(pin), regval);
+}
+
+int pe_gpio_dir(int addr, int pin, int dir)
+{
+ int regval;
+
+ /* 0 == input, 1 == output */
+ regval = pe_getreg(addr, PE_GPIO_GPDR(pin));
+ if (regval < 0) return regval;
+ regval &= ~PE_GPIO_MASK(pin);
+ if (dir) regval |= PE_GPIO_MASK(pin);
+ return pe_setreg(addr, PE_GPIO_GPDR(pin), regval);
+}
+
+int pe_gpio_pud(int addr, int pin, int pu, int pd)
+{
+ int regval, mask = PE_GPIO_MASK(pin);
+
+ /* change pullup */
+ regval = pe_getreg(addr, PE_GPIO_GPPUR(pin));
+ if (regval < 0) return regval;
+ if (pu) regval |= mask;
+ else regval &= ~mask;
+ regval = pe_setreg(addr, PE_GPIO_GPPUR(pin), regval);
+ if (regval < 0) return regval;
+
+ /* change pulldown */
+ regval = pe_getreg(addr, PE_GPIO_GPPDR(pin));
+ if (regval < 0) return regval;
+ if (pu) regval |= mask;
+ else regval &= ~mask;
+ regval = pe_setreg(addr, PE_GPIO_GPPDR(pin), regval);
+ if (regval < 0) return regval;
+
+ return 0;
+}
+
+int pe_gpio_set(int addr, int pin, int val)
+{
+ int reg;
+
+ if (val) reg = PE_GPIO_GPSR(pin);
+ else reg = PE_GPIO_GPCR(pin);
+
+ return pe_setreg(addr, reg, PE_GPIO_MASK(pin));
+}
+
+int pe_gpio_get(int addr, int pin)
+{
+ int regval;
+
+ regval = pe_getreg(addr, PE_GPIO_GPMR(pin));
+ if (regval < 0) return regval;
+ return (regval & PE_GPIO_MASK(pin)) ? 1 : 0;
+}
+
+/*
+ * Generic higher-level keypad interface: we have 12 rows out, 8 columns in
+ */
+int pe_kpc_init(int addr, int rowmask, int colmask, int debounce_ms)
+{
+ int i;
+ /* note that gpio15 is missing in the rows, so use tables */
+ static unsigned char row_to_gpio[12] = {
+ 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20};
+ static unsigned char col_to_gpio[8] = {
+ 0, 1, 2, 3, 4, 5, 6, 7};
+
+ /* First, configure pins for alternate functions (and pullup) */
+ for (i = 0; i < ARRAY_SIZE(row_to_gpio); i++) {
+ if (rowmask & (1 << i)) {
+ pe_gpio_dir(addr, row_to_gpio[i], 1 /* out */);
+ pe_gpio_af(addr, row_to_gpio[i], PE_GPIO_AF_AF1);
+ pe_gpio_pud(addr, row_to_gpio[i], 0, 0);
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(col_to_gpio); i++) {
+ if (colmask & (1 << i)) {
+ pe_gpio_dir(addr, col_to_gpio[i], 0 /* in */);
+ pe_gpio_af(addr, col_to_gpio[i], PE_GPIO_AF_AF1);
+ pe_gpio_pud(addr, col_to_gpio[i], 1, 0);
+ }
+ }
+
+ /* Set configuration for kpc: no support for dedicated keys */
+ pe_setreg(addr, PE_KPC_COL, colmask);
+ pe_setreg(addr, PE_KPC_ROW_MSB, 0xc0 | (rowmask >> 8));
+ pe_setreg(addr, PE_KPC_ROW_LSB, rowmask & 0xff);
+ pe_setreg(addr, PE_KPC_CTRL_MSB, 0x30 /* scan count is 3 */);
+ pe_setreg(addr, PE_KPC_CTRL_LSB, debounce_ms << 1);
+
+ /* Configure interrupt controller */
+ pe_setreg(addr, PE_ICR_LSB, 0x1); /* level, active low */
+ pe_setreg(addr, PE_IER_LSB, 0x2); /* bit1: keypad */
+
+ /* Start scanning */
+ pe_setreg(addr, PE_KPC_CTRL_LSB, (debounce_ms << 1) | 1);
+ return 0;
+}
+
+int pe_kpc_getkey(int addr, int *row, int *col)
+{
+ int key0, key1;
+
+ /* ack irq: bit 1 is keypad */
+ pe_setreg(addr, PE_ISR_LSB, 0x2);
+ /* get data -- one key only at a time: ignore key1*/
+ key0 = pe_getreg(addr, PE_KPC_DATA0);
+ key1 = pe_getreg(addr, PE_KPC_DATA1);
+ if (key0 & 0x80) /* release: return error */
+ return -1;
+ if ((key0 & 0x78) == 0x78) /* no key reported */
+ return -1;
+ *row = ((key0 & 0x78) >> 3);
+ *col = key0 & 0x07;
+ return 0;
+}
diff --git a/include/stmpe2401.h b/include/stmpe2401.h
new file mode 100644
index 0000000..fe7691e
--- /dev/null
+++ b/include/stmpe2401.h
@@ -0,0 +1,66 @@
+/*
+ * Defines and rototypes for port extender STMPE2401. Use "PE_" as short prefix.
+ */
+
+#ifndef __STMPE2401_H
+#define __STMPE2401_H
+
+/*
+ * registers for the EGPIO blocks: we have groups of three registers,
+ * starting from MSB, so use negative offsets from LSB.
+ */
+#define PE_GPIO_OFFSET(gpio) (- (gpio) / 8)
+#define PE_GPIO_MASK(gpio) (1 << ((gpio) & 7))
+
+#define PE_GPIO_GPMR(gpio) (0xa4 + PE_GPIO_OFFSET(gpio)) /* monitor */
+#define PE_GPIO_GPCR(gpio) (0x88 + PE_GPIO_OFFSET(gpio)) /* clear */
+#define PE_GPIO_GPSR(gpio) (0x85 + PE_GPIO_OFFSET(gpio)) /* set */
+#define PE_GPIO_GPDR(gpio) (0x8b + PE_GPIO_OFFSET(gpio)) /* direction */
+#define PE_GPIO_GPPUR(gpio) (0x97 + PE_GPIO_OFFSET(gpio)) /* pull-up */
+#define PE_GPIO_GPPDR(gpio) (0x9a + PE_GPIO_OFFSET(gpio)) /* pull-down */
+
+/* for alternate function, we have two bits per gpio, so 6 registers */
+#define PE_GPIO_AF_OFFSET(gpio) (- (gpio) / 4)
+#define PE_GPIO_AF_SHIFT(gpio) (2 * ((gpio) & 3))
+#define PE_GPIO_AF_MASK(gpio) (3 << PE_GPIO_AF_SHIFT(gpio))
+#define PE_GPIO_AFR(gpio) (0xa0 + PE_GPIO_AF_OFFSET(gpio))
+
+enum egpio_af {
+ PE_GPIO_AF_GPIO = 0,
+ PE_GPIO_AF_AF1,
+ PE_GPIO_AF_AF2,
+ PE_GPIO_AF_AF3
+};
+
+/* keypad controller registers */
+#define PE_KPC_COL 0x60
+#define PE_KPC_ROW_MSB 0x61
+#define PE_KPC_ROW_LSB 0x62
+#define PE_KPC_CTRL_MSB 0x63
+#define PE_KPC_CTRL_LSB 0x64
+#define PE_KPC_DATA0 0x68
+#define PE_KPC_DATA1 0x69
+#define PE_KPC_DATA2 0x6a
+
+/* interrupt controller registers (not all of them: we only need the LSB) */
+#define PE_ICR_LSB 0x11 /* control reg */
+#define PE_IER_LSB 0x13 /* enable reg */
+#define PE_ISR_LSB 0x15 /* status reg */
+
+/*
+ * prototypes of public functions
+ */
+extern int pe_getreg(int addr, int reg);
+extern int pe_setreg(int addr, int reg, int val);
+
+extern int pe_gpio_af(int addr, int gpio, int af);
+extern int pe_gpio_dir(int addr, int gpio, int dir);
+extern int pe_gpio_pud(int addr, int gpio, int pu, int pd);
+extern int pe_gpio_set(int addr, int gpio, int val);
+extern int pe_gpio_get(int addr, int gpio);
+
+/* here, rowmask is bits 0..11 for outputs, colmask is bits 0..7, for inputs */
+extern int pe_kpc_init(int addr, int rowmask, int colmask, int debounce_ms);
+extern int pe_kpc_getkey(int addr, int *row, int *col);
+
+#endif /* __STMPE2401_H */
--
1.6.0.2
More information about the U-Boot
mailing list