Module Name: src
Committed By: khorben
Date: Sun May 12 00:42:50 UTC 2013
Modified Files:
src/sys/arch/evbarm/conf [khorben-n900]: N900
src/sys/dev/i2c [khorben-n900]: tps65950.c tps65950reg.h
Log Message:
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.
To generate a diff of this commit:
cvs rdiff -u -r1.13.2.3 -r1.13.2.4 src/sys/arch/evbarm/conf/N900
cvs rdiff -u -r1.3.10.2 -r1.3.10.3 src/sys/dev/i2c/tps65950.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/dev/i2c/tps65950reg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/evbarm/conf/N900
diff -u src/sys/arch/evbarm/conf/N900:1.13.2.3 src/sys/arch/evbarm/conf/N900:1.13.2.4
--- src/sys/arch/evbarm/conf/N900:1.13.2.3 Sat May 11 18:22:47 2013
+++ src/sys/arch/evbarm/conf/N900 Sun May 12 00:42:50 2013
@@ -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 @@ iic* at omapiic?
# 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
Index: src/sys/dev/i2c/tps65950.c
diff -u src/sys/dev/i2c/tps65950.c:1.3.10.2 src/sys/dev/i2c/tps65950.c:1.3.10.3
--- src/sys/dev/i2c/tps65950.c:1.3.10.2 Sat May 11 18:22:47 2013
+++ src/sys/dev/i2c/tps65950.c Sun May 12 00:42:50 2013
@@ -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 <[email protected]>
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: tps65950.c,v
#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 tps65950_softc {
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_intr_work(struct wo
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 @@ tps65950_attach(device_t parent, device_
(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_intr_work(struct work *work, vo
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 @@ tps65950_pih_intr_work(struct work *work
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;
+ bit = pin - 16;
+ }
+ else
+ return;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+ tps65950_read_1(sc, reg, &val);
+ new = val;
+ switch (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ case GPIO_PIN_INPUT: new &= ~(1 << bit); break;
+ case GPIO_PIN_OUTPUT: new |= (1 << bit); break;
+ default: break;
+ }
+ if (new != val)
+ tps65950_write_1(sc, reg, new);
+ iic_release_bus(sc->sc_i2c, 0);
+}
+
+static void
+tps65950_gpio_pic_block_irqs(struct pic_softc *pic, size_t irq_base,
+ uint32_t irq_mask)
+{
+ struct tps65950_softc *sc = PIC_TO_SOFTC(pic);
+ int i;
+ const uint32_t reg[3] = { TPS65950_GPIO_GPIO_IMR1A,
+ TPS65950_GPIO_GPIO_IMR2A, TPS65950_GPIO_GPIO_IMR3A };
+ uint8_t u8;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+ for (i = 0; i < 3; i++) {
+ tps65950_read_1(sc, reg[i], &u8);
+ u8 &= ~((irq_mask >> (i * 8)) & 0xff);
+ tps65950_write_1(sc, reg[i], u8);
+ }
+ iic_release_bus(sc->sc_i2c, 0);
+}
+
+static void
+tps65950_gpio_pic_unblock_irqs(struct pic_softc *pic, size_t irq_base,
+ uint32_t irq_mask)
+{
+ struct tps65950_softc *sc = PIC_TO_SOFTC(pic);
+ int i;
+ const uint32_t reg[3] = { TPS65950_GPIO_GPIO_IMR1A,
+ TPS65950_GPIO_GPIO_IMR2A, TPS65950_GPIO_GPIO_IMR3A };
+ uint8_t u8;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+ for (i = 0; i < 3; i++) {
+ tps65950_read_1(sc, reg[i], &u8);
+ u8 |= (irq_mask >> (i * 8)) & 0xff;
+ tps65950_write_1(sc, reg[i], u8);
+ }
+ iic_release_bus(sc->sc_i2c, 0);
+}
+
+static int
+tps65950_gpio_pic_find_pending_irqs(struct pic_softc *pic)
+{
+ struct tps65950_softc *sc = PIC_TO_SOFTC(pic);
+ uint32_t pending;
+ uint8_t u8;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+ tps65950_read_1(sc, TPS65950_GPIO_GPIO_ISR1A, &u8);
+ pending = u8;
+ tps65950_read_1(sc, TPS65950_GPIO_GPIO_ISR2A, &u8);
+ pending |= (u8 << 8);
+ tps65950_read_1(sc, TPS65950_GPIO_GPIO_ISR3A, &u8);
+ pending |= ((u8 & 0x3) << 16);
+ iic_release_bus(sc->sc_i2c, 0);
+ aprint_normal_dev(sc->sc_dev, "%s() 0x%08x\n", __func__, pending);
+ return pending;
+}
+
+static void
+tps65950_gpio_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
+{
+ struct tps65950_softc *sc = PIC_TO_SOFTC(pic);
+ int index;
+ int shift;
+ const uint32_t edge[5] = { TPS65950_GPIO_GPIO_EDR1,
+ TPS65950_GPIO_GPIO_EDR2, TPS65950_GPIO_GPIO_EDR3,
+ TPS65950_GPIO_GPIO_EDR4, TPS65950_GPIO_GPIO_EDR5 };
+ uint32_t reg;
+ uint8_t bits;
+ uint8_t u8;
+
+ index = is->is_irq / 4;
+ shift = (is->is_irq % 4) * 2;
+ switch (is->is_type) {
+ case IST_LEVEL_LOW:
+ case IST_LEVEL_HIGH:
+ /* FIXME implement */
+ return;
+ case IST_EDGE_FALLING:
+ reg = edge[index];
+ bits = 0x1;
+ break;
+ case IST_EDGE_RISING:
+ reg = edge[index];
+ bits = 0x2;
+ break;
+ case IST_EDGE_BOTH:
+ reg = edge[index];
+ bits = 0x3;
+ break;
+ default:
+ return;
+ }
+ iic_acquire_bus(sc->sc_i2c, 0);
+ tps65950_read_1(sc, reg, &u8);
+ u8 |= bits << shift;
+ tps65950_write_1(sc, reg, u8);
+ iic_release_bus(sc->sc_i2c, 0);
+}
+#endif /* NGPIO > 0 */
+
static void
tps65950_rtc_attach(struct tps65950_softc *sc)
{
Index: src/sys/dev/i2c/tps65950reg.h
diff -u src/sys/dev/i2c/tps65950reg.h:1.1.2.2 src/sys/dev/i2c/tps65950reg.h:1.1.2.3
--- src/sys/dev/i2c/tps65950reg.h:1.1.2.2 Sat May 11 18:22:47 2013
+++ src/sys/dev/i2c/tps65950reg.h Sun May 12 00:42:50 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tps65950reg.h,v 1.1.2.2 2013/05/11 18:22:47 khorben Exp $ */
+/* $NetBSD: tps65950reg.h,v 1.1.2.3 2013/05/12 00:42:50 khorben Exp $ */
/*-
* Copyright (c) 2012 Jared D. McNeill <[email protected]>
@@ -40,7 +40,54 @@
#define TPS65950_ADDR_ID4 0x4b /* GP */
#define TPS65950_ADDR_ID5 0x12 /* SmartReflex */
-/* ID2 */
+/* ID2: GPIO */
+#define TPS65950_GPIO_BASE 0x98
+#define TPS65950_GPIO_GPIODATAIN1 (TPS65950_GPIO_BASE + 0x01)
+#define TPS65950_GPIO_GPIODATAIN2 (TPS65950_GPIO_BASE + 0x02)
+#define TPS65950_GPIO_GPIODATAIN3 (TPS65950_GPIO_BASE + 0x03)
+#define TPS65950_GPIO_GPIODATADIR1 (TPS65950_GPIO_BASE + 0x04)
+#define TPS65950_GPIO_GPIODATADIR2 (TPS65950_GPIO_BASE + 0x05)
+#define TPS65950_GPIO_GPIODATADIR3 (TPS65950_GPIO_BASE + 0x06)
+#define TPS65950_GPIO_GPIODATAOUT1 (TPS65950_GPIO_BASE + 0x07)
+#define TPS65950_GPIO_GPIODATAOUT2 (TPS65950_GPIO_BASE + 0x08)
+#define TPS65950_GPIO_GPIODATAOUT3 (TPS65950_GPIO_BASE + 0x09)
+#define TPS65950_GPIO_CLEARGPIODATAOUT1 (TPS65950_GPIO_BASE + 0x0a)
+#define TPS65950_GPIO_CLEARGPIODATAOUT2 (TPS65950_GPIO_BASE + 0x0b)
+#define TPS65950_GPIO_CLEARGPIODATAOUT3 (TPS65950_GPIO_BASE + 0x0c)
+#define TPS65950_GPIO_SETGPIODATAOUT1 (TPS65950_GPIO_BASE + 0x0d)
+#define TPS65950_GPIO_SETGPIODATAOUT2 (TPS65950_GPIO_BASE + 0x0e)
+#define TPS65950_GPIO_SETGPIODATAOUT3 (TPS65950_GPIO_BASE + 0x0f)
+#define TPS65950_GPIO_GPIO_DEBEN1 (TPS65950_GPIO_BASE + 0x10)
+#define TPS65950_GPIO_GPIO_DEBEN2 (TPS65950_GPIO_BASE + 0x11)
+#define TPS65950_GPIO_GPIO_DEBEN3 (TPS65950_GPIO_BASE + 0x12)
+#define TPS65950_GPIO_GPIO_CTRL (TPS65950_GPIO_BASE + 0x13)
+#define TPS65950_GPIO_GPIOPUPDCTR1 (TPS65950_GPIO_BASE + 0x14)
+#define TPS65950_GPIO_GPIOPUPDCTR2 (TPS65950_GPIO_BASE + 0x15)
+#define TPS65950_GPIO_GPIOPUPDCTR3 (TPS65950_GPIO_BASE + 0x16)
+#define TPS65950_GPIO_GPIOPUPDCTR4 (TPS65950_GPIO_BASE + 0x17)
+#define TPS65950_GPIO_GPIOPUPDCTR5 (TPS65950_GPIO_BASE + 0x18)
+#define TPS65950_GPIO_GPIO_ISR1A (TPS65950_GPIO_BASE + 0x19)
+#define TPS65950_GPIO_GPIO_ISR2A (TPS65950_GPIO_BASE + 0x1a)
+#define TPS65950_GPIO_GPIO_ISR3A (TPS65950_GPIO_BASE + 0x1b)
+#define TPS65950_GPIO_GPIO_IMR1A (TPS65950_GPIO_BASE + 0x1c)
+#define TPS65950_GPIO_GPIO_IMR2A (TPS65950_GPIO_BASE + 0x1d)
+#define TPS65950_GPIO_GPIO_IMR3A (TPS65950_GPIO_BASE + 0x1e)
+#define TPS65950_GPIO_GPIO_ISR1B (TPS65950_GPIO_BASE + 0x1f)
+#define TPS65950_GPIO_GPIO_ISR2B (TPS65950_GPIO_BASE + 0x20)
+#define TPS65950_GPIO_GPIO_ISR3B (TPS65950_GPIO_BASE + 0x21)
+#define TPS65950_GPIO_GPIO_IMR1B (TPS65950_GPIO_BASE + 0x22)
+#define TPS65950_GPIO_GPIO_IMR2B (TPS65950_GPIO_BASE + 0x23)
+#define TPS65950_GPIO_GPIO_IMR3B (TPS65950_GPIO_BASE + 0x24)
+#define TPS65950_GPIO_GPIO_EDR1 (TPS65950_GPIO_BASE + 0x28)
+#define TPS65950_GPIO_GPIO_EDR2 (TPS65950_GPIO_BASE + 0x29)
+#define TPS65950_GPIO_GPIO_EDR3 (TPS65950_GPIO_BASE + 0x2a)
+#define TPS65950_GPIO_GPIO_EDR4 (TPS65950_GPIO_BASE + 0x2b)
+#define TPS65950_GPIO_GPIO_EDR5 (TPS65950_GPIO_BASE + 0x2c)
+#define TPS65950_GPIO_GPIO_SIH_CTRL (TPS65950_GPIO_BASE + 0x2d)
+#define TPS65950_GPIO_PMBR1 (TPS65950_GPIO_BASE + 0x2f)
+#define TPS65950_GPIO_PMBR2 (TPS65950_GPIO_BASE + 0x30)
+
+/* ID2: IDCODE */
#define TPS65950_ID2_IDCODE_7_0 0x85
#define TPS65950_ID2_IDCODE_15_8 0x86
#define TPS65950_ID2_IDCODE_23_16 0x87