PERFORCE change 196472 for review
Jakub Wojciech Klama
jceel at FreeBSD.org
Thu Jul 21 01:04:10 UTC 2011
http://p4web.freebsd.org/@@196472?ac=10
Change 196472 by jceel at 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 at 28000 {
+ compatible = "lpc,gpio";
+ reg = <0x28000 0x4000>;
+ };
};
ahb6 at 30000000 {
@@ -180,6 +185,13 @@
interrupts = <59>;
interrupt-parent = <&PIC>;
};
+
+ lpcfb at 1040000 {
+ compatible = "lpc,fb";
+ reg = <0x1040000 0x20000>;
+ interrupts = <14>;
+ interrupt-parent = <&PIC>;
+ };
lpe at 1060000 {
compatible = "lpc,ethernet";
@@ -209,7 +221,7 @@
lpcmmc at 98000 {
compatible = "lpc,mmc";
reg = <0x98000 0x4000>;
- interrupts = <15>;
+ interrupts = <15 13>;
interrupt-parent = <&PIC>;
};
};
More information about the p4-projects
mailing list