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

Reply via email to