Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Jul 2011 01:04:09 GMT
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 196472 for review
Message-ID:  <201107210104.p6L149i2023665@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@196472?ac=10

Change 196472 by jceel@jceel_cyclone on 2011/07/21 01:03:33

	Add initial version of GPIO driver.

Affected files ...

.. //depot/projects/soc2011/jceel_lpc/sys/arm/conf/EA3250#6 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/files.lpc#5 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpc_gpio.c#2 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpcreg.h#4 edit
.. //depot/projects/soc2011/jceel_lpc/sys/boot/fdt/dts/ea3250.dts#6 edit

Differences ...

==== //depot/projects/soc2011/jceel_lpc/sys/arm/conf/EA3250#6 (text+ko) ====

@@ -86,6 +86,12 @@
 device		mmcsd
 device		lpcmmc
 
+device		gpio
+device		gpioled
+device		lpcgpio
+
+#device		lpcfb
+
 # Flattened Device Tree
 options 	FDT
 options 	FDT_DTB_STATIC

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/files.lpc#5 (text+ko) ====

@@ -12,5 +12,7 @@
 arm/lpc/if_lpe.c			optional	lpe
 arm/lpc/lpc_ohci.c			optional	ohci
 arm/lpc/lpc_mmc.c			optional	lpcmmc
+#arm/lpc/lpc_fb.c			optional	lpcfb
+arm/lpc/lpc_gpio.c			optional	lpcgpio
 dev/uart/uart_dev_ns8250.c		optional	uart
 kern/kern_clocksource.c			standard

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpc_gpio.c#2 (text+ko) ====

@@ -26,3 +26,272 @@
  */
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#include "gpio_if.h"
+
+struct lpc_gpio_softc
+{
+	device_t		lg_dev;
+	struct resource *	lg_res;
+	bus_space_tag_t		lg_bst;
+	bus_space_handle_t	lg_bsh;
+};
+
+#define	LPC_GPIO_NPINS		(32 * 2)
+
+static int lpc_gpio_probe(device_t);
+static int lpc_gpio_attach(device_t);
+static int lpc_gpio_detach(device_t);
+
+static int lpc_gpio_pin_max(device_t, int *);
+static int lpc_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
+static int lpc_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
+static int lpc_gpio_pin_setflags(device_t, uint32_t, uint32_t);
+static int lpc_gpio_pin_getname(device_t, uint32_t, char *);
+static int lpc_gpio_pin_get(device_t, uint32_t, uint32_t *);
+static int lpc_gpio_pin_set(device_t, uint32_t, uint32_t);
+static int lpc_gpio_pin_toggle(device_t, uint32_t);
+
+#define	lpc_gpio_read_4(_sc, _reg)		\
+    bus_space_read_4(_sc->lg_bst, _sc->lg_bsh, _reg)
+#define	lpc_gpio_write_4(_sc, _reg, _val)	\
+    bus_space_write_4(_sc->lg_bst, _sc->lg_bsh, _reg, _val)
+
+static int
+lpc_gpio_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,gpio"))
+		return (ENXIO);
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_gpio_attach(device_t dev)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	int rid;
+
+	sc->lg_dev = dev;
+
+	rid = 0;
+	sc->lg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->lg_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->lg_bst = rman_get_bustag(sc->lg_res);
+	sc->lg_bsh = rman_get_bushandle(sc->lg_res);
+
+	device_add_child(dev, "gpioc", device_get_unit(dev));
+	device_add_child(dev, "gpiobus", device_get_unit(dev));
+
+	return (bus_generic_attach(dev));
+}
+
+static int
+lpc_gpio_detach(device_t dev)
+{
+	/* XXX */
+	return (0);
+}
+
+static int
+lpc_gpio_pin_max(device_t dev, int *npins)
+{
+	/* Currently supports only P0 and P1 */
+	*npins = LPC_GPIO_NPINS;
+	return (0);
+}
+
+static int
+lpc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	if (pin > LPC_GPIO_NPINS)
+		return (ENODEV);
+
+	*caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+	return (0);
+}
+
+static int
+lpc_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	uint32_t direction;
+
+	if (pin >= 32) {
+		pin -= 32;
+		direction = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
+	} else {
+		direction = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
+	}
+
+	if (direction & (1 << pin))
+		*flags = GPIO_PIN_OUTPUT;
+	else
+		*flags = GPIO_PIN_INPUT;
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	uint32_t direction, state;
+
+	if (flags & GPIO_PIN_INPUT)
+		direction = 0;
+
+	if (flags & GPIO_PIN_OUTPUT)
+		direction = 1;
+
+	if (pin >= 32) {
+		pin -= 32;
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
+		lpc_gpio_write_4(sc, LPC_GPIO_P1_DIR_SET, state | (direction << pin));
+	} else {
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
+		lpc_gpio_write_4(sc, LPC_GPIO_P1_DIR_SET, state | (direction << pin));
+
+	}
+	
+	return (0);
+}
+
+static int
+lpc_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	snprintf(name, GPIOMAXNAME - 1, "pin%d", pin);
+	return (0);
+}
+
+static int
+lpc_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	uint32_t state;
+
+	if (pin >= 32) {
+		pin -= 32;
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_INP_STATE);
+		*value = (state & (1 << pin));
+	} else {
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P0_INP_STATE);
+		*value = (state & (1 << pin));
+	}
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	uint32_t state;
+
+	if (pin >= 32) {
+		pin -= 32;
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_OUTP_STATE);
+		state = value ? state | (1 << pin) : state & ~(1 << pin);
+		lpc_gpio_write_4(sc, LPC_GPIO_P1_OUTP_SET, state);
+	} else {
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P0_OUTP_STATE);
+		state = value ? state | (1 << pin) : state & ~(1 << pin);
+		lpc_gpio_write_4(sc, LPC_GPIO_P0_OUTP_SET, state | (1 << pin));
+	}
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	uint32_t state;
+
+	if (pin >= 32) {
+		pin -= 32;
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_OUTP_STATE);
+		state = (state & (1 << pin)) ? state & ~(1 << pin) : state | (1 << pin);
+		lpc_gpio_write_4(sc, LPC_GPIO_P1_OUTP_SET, state);
+	} else {
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P0_OUTP_STATE);
+		state = (state & (1 << pin)) ? state & ~(1 << pin) : state | (1 << pin);
+		lpc_gpio_write_4(sc, LPC_GPIO_P0_OUTP_SET, state | (1 << pin));
+	}
+
+	return (0);
+
+}
+
+static device_method_t lpc_gpio_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_gpio_probe),
+	DEVMETHOD(device_attach,	lpc_gpio_attach),
+	DEVMETHOD(device_detach,	lpc_gpio_detach),
+
+	/* GPIO interface */
+	DEVMETHOD(gpio_pin_max,		lpc_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getcaps,	lpc_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_getflags,	lpc_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_setflags,	lpc_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_getname,	lpc_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_set,		lpc_gpio_pin_set),
+	DEVMETHOD(gpio_pin_get,		lpc_gpio_pin_get),
+	DEVMETHOD(gpio_pin_toggle,	lpc_gpio_pin_toggle),
+
+	{ 0, 0 }
+};
+
+static devclass_t lpc_gpio_devclass;
+
+static driver_t lpc_gpio_driver = {
+	"lpcgpio",
+	lpc_gpio_methods,
+	sizeof(struct lpc_gpio_softc),
+};
+
+extern devclass_t gpiobus_devclass, gpioc_devclass;
+extern driver_t gpiobus_driver, gpioc_driver;
+
+DRIVER_MODULE(lpcgpio, simplebus, lpc_gpio_driver, lpc_gpio_devclass, 0, 0);
+DRIVER_MODULE(gpiobus, lpcgpio, gpiobus_driver, gpiobus_devclass, 0, 0);
+DRIVER_MODULE(gpioc, lpcgpio, gpioc_driver, gpioc_devclass, 0, 0);
+MODULE_VERSION(lpcgpio, 1);

==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/lpcreg.h#4 (text+ko) ====

@@ -341,5 +341,61 @@
 #define	LPC_ISP3101_OTG_INTR_RISING	0x0e
 #define	LPC_ISP3101_REG_CLEAR_ADDR	0x01
 
+/*
+ * LCD Controller (from UM10326: LPC32x0 User manual, page 229)
+ */
+#define	LPC_LCD_TIMH			0x00
+#define	LPC_LCD_TIMV			0x04
+#define	LPC_LCD_POL			0x08
+#define	LPC_LCD_LE			0x0c
+#define	LPC_LCD_UPBASE			0x10
+#define	LPC_LCD_LPBASE			0x14
+#define	LPC_LCD_CTRL			0x18
+#define	LPC_LCD_INTMSK			0x1c
+#define	LPC_LCD_INTRAW			0x20
+#define	LPC_LCD_INTSTAT			0x24
+#define	LPC_LCD_INTCLR			0x28
+#define	LPC_LCD_UPCURR			0x2c
+#define	LPC_LCD_LPCURR			0x30
+#define	LPC_LCD_PAL			0x200
+#define	LPC_LCD_CRSR_IMG		0x800
+#define	LPC_LCD_CRSR_CTRL		0xc00
+#define	LPC_LCD_CRSR_CFG		0xc04
+#define	LPC_LCD_CRSR_PAL0		0xc08
+#define	LPC_LCD_CRSR_PAL1		0xc0c
+#define	LPC_LCD_CRSR_XY			0xc10
+#define	LPC_LCD_CRSR_CLIP		0xc14
+#define	LPC_LCD_CRSR_INTMSK		0xc20
+#define	LPC_LCD_CRSR_INTCLR		0xc24
+#define	LPC_LCD_CRSR_INTRAW		0xc28
+#define	LPC_LCD_CRSR_INTSTAT		0xc2c
+
+/*
+ * GPIO (from UM10326: LPC32x0 User manual, page 606)
+ */
+#define	LPC_GPIO_P0_INP_STATE		0x40
+#define	LPC_GPIO_P0_OUTP_SET		0x44
+#define	LPC_GPIO_P0_OUTP_CLR		0x48
+#define	LPC_GPIO_P0_OUTP_STATE		0x4c
+#define	LPC_GPIO_P0_DIR_SET		0x50
+#define	LPC_GPIO_P0_DIR_CLR		0x54
+#define	LPC_GPIO_P0_DIR_STATE		0x58
+#define	LPC_GPIO_P1_INP_STATE		0x60
+#define	LPC_GPIO_P1_OUTP_SET		0x64
+#define	LPC_GPIO_P1_OUTP_CLR		0x68
+#define	LPC_GPIO_P1_OUTP_STATE		0x6c
+#define	LPC_GPIO_P1_DIR_SET		0x70
+#define	LPC_GPIO_P1_DIR_CLR		0x74
+#define	LPC_GPIO_P1_DIR_STATE		0x78
+#define	LPC_GPIO_P2_INP_STATE		0x1c
+#define	LPC_GPIO_P2_OUTP_SET		0x20
+#define	LPC_GPIO_P2_OUTP_CLR		0x24
+#define	LPC_GPIO_P2_DIR_SET		0x10
+#define	LPC_GPIO_P2_DIR_CLR		0x14
+#define	LPC_GPIO_P2_DIR_STATE		0x14
+#define	LPC_GPIO_P3_INP_STATE		0x00
+#define	LPC_GPIO_P3_OUTP_SET		0x04
+#define	LPC_GPIO_P3_OUTP_CLR		0x08
+#define	LPC_GPIO_P3_OUTP_STATE		0x0c
 
 #endif	/* _ARM_LPC_LPCREG_H */

==== //depot/projects/soc2011/jceel_lpc/sys/boot/fdt/dts/ea3250.dts#6 (text+ko) ====

@@ -166,6 +166,11 @@
 			interrupts = <24>;
 			interrupt-parent = <&PIC>;
 		};
+
+		gpio@28000 {
+			compatible = "lpc,gpio";
+			reg = <0x28000 0x4000>;
+		};
 	};
 
 	ahb6@30000000 {
@@ -180,6 +185,13 @@
 			interrupts = <59>;
 			interrupt-parent = <&PIC>;
 		};
+
+		lpcfb@1040000 {
+			compatible = "lpc,fb";
+			reg = <0x1040000 0x20000>;
+			interrupts = <14>;
+			interrupt-parent = <&PIC>;
+		};
 	
 		lpe@1060000 {
 			compatible = "lpc,ethernet";
@@ -209,7 +221,7 @@
 		lpcmmc@98000 {
 			compatible = "lpc,mmc";
 			reg = <0x98000 0x4000>;
-			interrupts = <15>;
+			interrupts = <15 13>;
 			interrupt-parent = <&PIC>;
 		};
 	};



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107210104.p6L149i2023665>