Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/khorben-n900]: src/sys Added GPIO support to the TPS65950 companion chip...



details:   https://anonhg.NetBSD.org/src/rev/276d9518139e
branches:  khorben-n900
changeset: 786704:276d9518139e
user:      khorben <khorben%NetBSD.org@localhost>
date:      Sun May 12 00:42:50 2013 +0000

description:
Added GPIO support to the TPS65950 companion chip. I haven't been able to
test it properly thus far unfortunately.

XXX Implement level-triggered interrupts.

diffstat:

 sys/arch/evbarm/conf/N900 |    7 +-
 sys/dev/i2c/tps65950.c    |  340 +++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/i2c/tps65950reg.h |   51 ++++++-
 3 files changed, 391 insertions(+), 7 deletions(-)

diffs (truncated from 486 to 300 lines):

diff -r c8ea6de5fea1 -r 276d9518139e sys/arch/evbarm/conf/N900
--- a/sys/arch/evbarm/conf/N900 Sat May 11 18:22:47 2013 +0000
+++ b/sys/arch/evbarm/conf/N900 Sun May 12 00:42:50 2013 +0000
@@ -1,5 +1,5 @@
 #
-#      $NetBSD: N900,v 1.13.2.3 2013/05/11 18:22:47 khorben Exp $
+#      $NetBSD: N900,v 1.13.2.4 2013/05/12 00:42:50 khorben Exp $
 #
 #      N900 -- Nokia N900 Kernel
 #
@@ -248,9 +248,12 @@
 # I2C devices
 # Power Management and System Companion Device
 tps65950pm0    at iic0 addr 0x48
-tps65950pm1    at iic0 addr 0x49 intr 7
+tps65950pm1    at iic0 addr 0x49 intrbase 288 intr 7
 tps65950pm2    at iic0 addr 0x4a
 tps65950pm3    at iic0 addr 0x4b
+#tps65950pm4   at iic1 addr 0x12
+
+gpio*          at tps65950pm1
 
 # SPI devices
 omapspi0       at obio0 addr 0x48098000 size 0x1000 intr 65
diff -r c8ea6de5fea1 -r 276d9518139e sys/dev/i2c/tps65950.c
--- a/sys/dev/i2c/tps65950.c    Sat May 11 18:22:47 2013 +0000
+++ b/sys/dev/i2c/tps65950.c    Sun May 12 00:42:50 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tps65950.c,v 1.3.10.2 2013/05/11 18:22:47 khorben Exp $ */
+/* $NetBSD: tps65950.c,v 1.3.10.3 2013/05/12 00:42:50 khorben Exp $ */
 
 /*-
  * Copyright (c) 2012 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -31,7 +31,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tps65950.c,v 1.3.10.2 2013/05/11 18:22:47 khorben Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tps65950.c,v 1.3.10.3 2013/05/12 00:42:50 khorben Exp $");
+
+#define _INTR_PRIVATE
+
+#include "gpio.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -45,6 +49,12 @@
 
 #include <dev/i2c/i2cvar.h>
 
+#if NGPIO > 0
+#include <arm/pic/picvar.h>
+#include <sys/gpio.h>
+#include <dev/gpio/gpiovar.h>
+#endif /* NGPIO > 0 */
+
 #include <dev/clock_subr.h>
 #include <dev/sysmon/sysmonvar.h>
 
@@ -68,6 +78,17 @@
        struct work             sc_work;
        bool                    sc_queued;
 
+#if NGPIO > 0
+       /* GPIO */
+       struct gpio_chipset_tag sc_gpio;
+       gpio_pin_t              sc_gpio_pins[18];
+       struct pic_softc        sc_gpio_pic;
+
+#define PIC_TO_SOFTC(pic) \
+       ((struct tps65950_softc *)((char *)(pic) - \
+               offsetof(struct tps65950_softc, sc_gpio_pic)))
+#endif /* NGPIO > 0 */
+
        /* WATCHDOG */
        struct sysmon_wdog sc_smw;
        struct todr_chip_handle sc_todr;
@@ -93,6 +114,31 @@
 static void    tps65950_pih_attach(struct tps65950_softc *, int);
 static void    tps65950_pih_intr_work(struct work *, void *);
 
+#if NGPIO > 0
+static void    tps65950_gpio_attach(struct tps65950_softc *, int);
+
+static void    tps65950_gpio_intr(struct tps65950_softc *);
+
+static int     tps65950_gpio_pin_read(void *, int);
+static void    tps65950_gpio_pin_write(void *, int, int);
+static void    tps65950_gpio_pin_ctl(void *, int, int);
+
+static void    tps65950_gpio_pic_block_irqs(struct pic_softc *, size_t,
+               uint32_t);
+static void    tps65950_gpio_pic_unblock_irqs(struct pic_softc *, size_t,
+               uint32_t);
+static int     tps65950_gpio_pic_find_pending_irqs(struct pic_softc *);
+static void    tps65950_gpio_pic_establish_irq(struct pic_softc *,
+               struct intrsource *);
+
+const struct pic_ops tps65950_gpio_pic_ops = {
+       .pic_block_irqs = tps65950_gpio_pic_block_irqs,
+       .pic_unblock_irqs = tps65950_gpio_pic_unblock_irqs,
+       .pic_find_pending_irqs = tps65950_gpio_pic_find_pending_irqs,
+       .pic_establish_irq = tps65950_gpio_pic_establish_irq
+};
+#endif /* NGPIO > 0 */
+
 static void    tps65950_rtc_attach(struct tps65950_softc *);
 static int     tps65950_rtc_enable(struct tps65950_softc *, bool);
 static int     tps65950_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
@@ -151,8 +197,15 @@
                         (buf[2] << 16) | (buf[3] << 24);
                aprint_normal(": IDCODE %08X", idcode);
 
-               aprint_normal(": PIH\n");
+               aprint_normal(": PIH");
                tps65950_pih_attach(sc, ia->ia_intr);
+
+#if NGPIO > 0
+               aprint_normal(", GPIO");
+               tps65950_gpio_attach(sc, ia->ia_intrbase);
+#else
+               aprint_normal("\n");
+#endif /* NGPIO > 0 */
                break;
        case TPS65950_ADDR_ID3:
                aprint_normal(": LED\n");
@@ -312,6 +365,12 @@
        tps65950_read_1(sc, TPS65950_PIH_REG_ISR_P1, &u8);
        tps65950_write_1(sc, TPS65950_PIH_REG_ISR_P1, u8);
 
+       /* dispatch the interrupt */
+#if NGPIO > 0
+       if (u8 & TPS65950_PIH_REG_ISR_P1_ISR0)
+               tps65950_gpio_intr(sc);
+#endif /* NGPIO > 0 */
+
        iic_release_bus(sc->sc_i2c, 0);
 
        /* allow the workqueue to be entered again */
@@ -365,6 +424,281 @@
        intr_enable(sc->sc_intr);
 }
 
+#if NGPIO > 0
+static void
+tps65950_gpio_attach(struct tps65950_softc *sc, int intrbase)
+{
+       struct gpio_chipset_tag * const gp = &sc->sc_gpio;
+       struct gpiobus_attach_args gba;
+       gpio_pin_t *pins;
+       uint32_t mask;
+       int pin;
+
+       /* disable interrupts */
+       iic_acquire_bus(sc->sc_i2c, 0);
+       tps65950_write_1(sc, TPS65950_GPIO_GPIO_IMR1A, 0);
+       tps65950_write_1(sc, TPS65950_GPIO_GPIO_IMR2A, 0);
+       tps65950_write_1(sc, TPS65950_GPIO_GPIO_IMR3A, 0);
+       iic_release_bus(sc->sc_i2c, 0);
+
+       /* map interrupts */
+       if (sc->sc_intr == NULL || intrbase < 0) {
+               aprint_normal("\n");
+               aprint_error_dev(sc->sc_dev, "couldn't map GPIO interrupts\n");
+               return;
+       } else {
+               sc->sc_gpio_pic.pic_ops = &tps65950_gpio_pic_ops;
+               strlcpy(sc->sc_gpio_pic.pic_name, device_xname(sc->sc_dev),
+                               sizeof(sc->sc_gpio_pic.pic_name));
+               sc->sc_gpio_pic.pic_maxsources = 18;
+               pic_add(&sc->sc_gpio_pic, intrbase);
+               aprint_normal(": interrupts %d..%d\n", intrbase, intrbase + 17);
+       }
+
+       gp->gp_cookie = sc;
+       gp->gp_pin_read = tps65950_gpio_pin_read;
+       gp->gp_pin_write = tps65950_gpio_pin_write;
+       gp->gp_pin_ctl = tps65950_gpio_pin_ctl;
+
+       gba.gba_gc = gp;
+       gba.gba_pins = sc->sc_gpio_pins;
+       gba.gba_npins = __arraycount(sc->sc_gpio_pins);
+
+       for (pin = 0, mask = 1, pins = sc->sc_gpio_pins;
+                       pin < 18; pin++, mask <<= 1, pins++) {
+               pins->pin_num = pin;
+               pins->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+               pins->pin_flags = GPIO_PIN_INPUT;
+               pins->pin_state = GPIO_PIN_HIGH;
+       }
+
+       config_found_ia(sc->sc_dev, "gpiobus", &gba, gpiobus_print);
+}
+
+static void
+tps65950_gpio_intr(struct tps65950_softc *sc)
+{
+       pic_handle_intr(&sc->sc_gpio_pic);
+}
+
+static int
+tps65950_gpio_pin_read(void *v, int pin)
+{
+       struct tps65950_softc *sc = v;
+       uint8_t reg;
+       uint8_t bit;
+       uint8_t val;
+
+       if (pin < 0)
+               return ENODEV;
+       else if (pin < 8)
+       {
+               reg = TPS65950_GPIO_GPIODATAIN1;
+               bit = pin;
+       }
+       else if (pin < 16)
+       {
+               reg = TPS65950_GPIO_GPIODATAIN2;
+               bit = pin - 8;
+       }
+       else if (pin < 18)
+       {
+               reg = TPS65950_GPIO_GPIODATAIN3;
+               bit = pin - 16;
+       }
+       else
+               return ENODEV;
+
+       iic_acquire_bus(sc->sc_i2c, 0);
+       tps65950_read_1(sc, reg, &val);
+       iic_release_bus(sc->sc_i2c, 0);
+
+       return val & (1 << bit);
+}
+
+static void
+tps65950_gpio_pin_write(void *v, int pin, int value)
+{
+       struct tps65950_softc *sc = v;
+       uint8_t reg;
+       uint8_t bit;
+       uint8_t val;
+       uint8_t new;
+
+       if (pin < 0)
+               return;
+       else if (pin < 8)
+       {
+               reg = TPS65950_GPIO_GPIODATAOUT1;
+               bit = pin;
+       }
+       else if (pin < 16)
+       {
+               reg = TPS65950_GPIO_GPIODATAOUT2;
+               bit = pin - 8;
+       }
+       else if (pin < 18)
+       {
+               reg = TPS65950_GPIO_GPIODATAOUT3;
+               bit = pin - 16;
+       }
+       else
+               return;
+
+       iic_acquire_bus(sc->sc_i2c, 0);
+       tps65950_read_1(sc, reg, &val);
+       new = val;
+       if (value)
+               new |= (1 << bit);
+       else
+               new &= ~(1 << bit);
+       if (new != val)
+               tps65950_write_1(sc, reg, new);
+       iic_release_bus(sc->sc_i2c, 0);
+}
+
+static void
+tps65950_gpio_pin_ctl(void *v, int pin, int flags)
+{
+       struct tps65950_softc *sc = v;
+       uint8_t reg;
+       uint8_t bit;
+       uint8_t val;
+       uint8_t new;
+
+       if (pin < 0)
+               return;
+       else if (pin < 8)
+       {
+               reg = TPS65950_GPIO_GPIODATADIR1;
+               bit = pin;
+       }
+       else if (pin < 16)
+       {
+               reg = TPS65950_GPIO_GPIODATADIR2;
+               bit = pin - 8;
+       }
+       else if (pin < 18)
+       {
+               reg = TPS65950_GPIO_GPIODATADIR3;



Home | Main Index | Thread Index | Old Index