2012-08-15 05:37:10 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GPIO on LPC32x0 consist of 4 ports:
|
|
|
|
* - Port0 with 8 input/output pins
|
|
|
|
* - Port1 with 24 input/output pins
|
|
|
|
* - Port2 with 13 input/output pins
|
|
|
|
* - Port3 with:
|
|
|
|
* - 26 input pins (GPI_00..GPI_09 + GPI_15..GPI_23 + GPI_25 + GPI_27..GPI_28)
|
|
|
|
* - 24 output pins (GPO_00..GPO_23)
|
2012-11-07 07:00:59 +00:00
|
|
|
* - 6 input/output pins (GPIO_00..GPIO_05)
|
2012-08-15 05:37:10 +00:00
|
|
|
*
|
|
|
|
* Pins are mapped to logical pin number as follows:
|
|
|
|
* [0..9] -> GPI_00..GPI_09 (port 3)
|
|
|
|
* [10..18] -> GPI_15..GPI_23 (port 3)
|
|
|
|
* [19] -> GPI_25 (port 3)
|
|
|
|
* [20..21] -> GPI_27..GPI_28 (port 3)
|
|
|
|
* [22..45] -> GPO_00..GPO_23 (port 3)
|
|
|
|
* [46..51] -> GPIO_00..GPIO_05 (port 3)
|
|
|
|
* [52..64] -> P2.0..P2.12 (port 2)
|
|
|
|
* [65..88] -> P1.0..P1.23 (port 1)
|
|
|
|
* [89..96] -> P0.0..P0.7 (port 0)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#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/intr.h>
|
|
|
|
#include <machine/fdt.h>
|
|
|
|
|
2015-01-31 19:32:14 +00:00
|
|
|
#include <dev/gpio/gpiobusvar.h>
|
2012-08-15 05:37:10 +00:00
|
|
|
#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;
|
2015-01-31 19:32:14 +00:00
|
|
|
device_t lg_busdev;
|
2012-08-15 05:37:10 +00:00
|
|
|
struct resource * lg_res;
|
|
|
|
bus_space_tag_t lg_bst;
|
|
|
|
bus_space_handle_t lg_bsh;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct lpc_gpio_pinmap
|
|
|
|
{
|
|
|
|
int lp_start_idx;
|
|
|
|
int lp_pin_count;
|
|
|
|
int lp_port;
|
|
|
|
int lp_start_bit;
|
|
|
|
int lp_flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct lpc_gpio_pinmap lpc_gpio_pins[] = {
|
|
|
|
{ 0, 10, 3, 0, GPIO_PIN_INPUT },
|
|
|
|
{ 10, 9, 3, 15, GPIO_PIN_INPUT },
|
|
|
|
{ 19, 1, 3, 25, GPIO_PIN_INPUT },
|
|
|
|
{ 20, 2, 3, 27, GPIO_PIN_INPUT },
|
|
|
|
{ 22, 24, 3, 0, GPIO_PIN_OUTPUT },
|
|
|
|
/*
|
|
|
|
* -1 below is to mark special case for Port3 GPIO pins, as they
|
|
|
|
* have other bits in Port 3 registers as inputs and as outputs
|
|
|
|
*/
|
|
|
|
{ 46, 6, 3, -1, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
|
|
|
|
{ 52, 13, 2, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
|
|
|
|
{ 65, 24, 1, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
|
|
|
|
{ 89, 8, 0, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
|
|
|
|
{ -1, -1, -1, -1, -1 },
|
|
|
|
};
|
|
|
|
|
|
|
|
#define LPC_GPIO_NPINS \
|
|
|
|
(LPC_GPIO_P0_COUNT + LPC_GPIO_P1_COUNT + \
|
|
|
|
LPC_GPIO_P2_COUNT + LPC_GPIO_P3_COUNT)
|
|
|
|
|
|
|
|
#define LPC_GPIO_PIN_IDX(_map, _idx) \
|
|
|
|
(_idx - _map->lp_start_idx)
|
|
|
|
|
|
|
|
#define LPC_GPIO_PIN_BIT(_map, _idx) \
|
|
|
|
(_map->lp_start_bit + LPC_GPIO_PIN_IDX(_map, _idx))
|
|
|
|
|
|
|
|
static int lpc_gpio_probe(device_t);
|
|
|
|
static int lpc_gpio_attach(device_t);
|
|
|
|
static int lpc_gpio_detach(device_t);
|
|
|
|
|
2015-01-31 19:32:14 +00:00
|
|
|
static device_t lpc_gpio_get_bus(device_t);
|
2012-08-15 05:37:10 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
static const struct lpc_gpio_pinmap *lpc_gpio_get_pinmap(int);
|
|
|
|
|
|
|
|
static struct lpc_gpio_softc *lpc_gpio_sc = NULL;
|
|
|
|
|
|
|
|
#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)
|
|
|
|
#define lpc_gpio_get_4(_sc, _test, _reg1, _reg2) \
|
|
|
|
lpc_gpio_read_4(_sc, ((_test) ? _reg1 : _reg2))
|
|
|
|
#define lpc_gpio_set_4(_sc, _test, _reg1, _reg2, _val) \
|
|
|
|
lpc_gpio_write_4(_sc, ((_test) ? _reg1 : _reg2), _val)
|
|
|
|
|
|
|
|
static int
|
|
|
|
lpc_gpio_probe(device_t dev)
|
|
|
|
{
|
2014-02-02 19:17:28 +00:00
|
|
|
|
|
|
|
if (!ofw_bus_status_okay(dev))
|
|
|
|
return (ENXIO);
|
|
|
|
|
2012-08-15 05:37:10 +00:00
|
|
|
if (!ofw_bus_is_compatible(dev, "lpc,gpio"))
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
device_set_desc(dev, "LPC32x0 GPIO");
|
|
|
|
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);
|
|
|
|
|
|
|
|
lpc_gpio_sc = sc;
|
|
|
|
|
2015-01-31 19:32:14 +00:00
|
|
|
sc->lg_busdev = gpiobus_attach_bus(dev);
|
|
|
|
if (sc->lg_busdev == NULL) {
|
|
|
|
bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->lg_res);
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
2012-08-15 05:37:10 +00:00
|
|
|
|
2015-01-31 19:32:14 +00:00
|
|
|
return (0);
|
2012-08-15 05:37:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lpc_gpio_detach(device_t dev)
|
|
|
|
{
|
|
|
|
return (EBUSY);
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:32:14 +00:00
|
|
|
static device_t
|
|
|
|
lpc_gpio_get_bus(device_t dev)
|
|
|
|
{
|
|
|
|
struct lpc_gpio_softc *sc;
|
|
|
|
|
|
|
|
sc = device_get_softc(dev);
|
|
|
|
|
|
|
|
return (sc->lg_busdev);
|
|
|
|
}
|
|
|
|
|
2012-08-15 05:37:10 +00:00
|
|
|
static int
|
|
|
|
lpc_gpio_pin_max(device_t dev, int *npins)
|
|
|
|
{
|
|
|
|
*npins = LPC_GPIO_NPINS - 1;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lpc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
|
|
|
|
{
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
|
|
|
|
if (pin > LPC_GPIO_NPINS)
|
|
|
|
return (ENODEV);
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
|
|
|
|
*caps = map->lp_flags;
|
|
|
|
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);
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
uint32_t state;
|
|
|
|
int dir;
|
|
|
|
|
|
|
|
if (pin > LPC_GPIO_NPINS)
|
|
|
|
return (ENODEV);
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
|
|
|
|
/* Check whether it's bidirectional pin */
|
|
|
|
if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
|
|
|
|
(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
|
|
|
|
*flags = map->lp_flags;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (map->lp_port) {
|
|
|
|
case 0:
|
|
|
|
state = lpc_gpio_read_4(sc, LPC_GPIO_P0_DIR_STATE);
|
|
|
|
dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
state = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
|
|
|
|
dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
state = lpc_gpio_read_4(sc, LPC_GPIO_P2_DIR_STATE);
|
|
|
|
dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
state = lpc_gpio_read_4(sc, LPC_GPIO_P2_DIR_STATE);
|
|
|
|
dir = (state & (1 << (25 + LPC_GPIO_PIN_IDX(map, pin))));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("unknown GPIO port");
|
|
|
|
}
|
|
|
|
|
|
|
|
*flags = dir ? GPIO_PIN_OUTPUT : 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);
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
uint32_t dir, state;
|
|
|
|
|
|
|
|
if (pin > LPC_GPIO_NPINS)
|
|
|
|
return (ENODEV);
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
|
|
|
|
/* Check whether it's bidirectional pin */
|
|
|
|
if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
|
|
|
|
(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
|
|
|
|
return (ENOTSUP);
|
|
|
|
|
|
|
|
if (flags & GPIO_PIN_INPUT)
|
|
|
|
dir = 0;
|
|
|
|
|
|
|
|
if (flags & GPIO_PIN_OUTPUT)
|
|
|
|
dir = 1;
|
|
|
|
|
|
|
|
switch (map->lp_port) {
|
|
|
|
case 0:
|
|
|
|
state = (1 << LPC_GPIO_PIN_IDX(map, pin));
|
|
|
|
lpc_gpio_set_4(sc, dir, LPC_GPIO_P0_DIR_SET,
|
|
|
|
LPC_GPIO_P0_DIR_CLR, state);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
state = (1 << LPC_GPIO_PIN_IDX(map, pin));
|
|
|
|
lpc_gpio_set_4(sc, dir, LPC_GPIO_P1_DIR_SET,
|
|
|
|
LPC_GPIO_P0_DIR_CLR, state);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
state = (1 << LPC_GPIO_PIN_IDX(map, pin));
|
|
|
|
lpc_gpio_set_4(sc, dir, LPC_GPIO_P2_DIR_SET,
|
|
|
|
LPC_GPIO_P0_DIR_CLR, state);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
state = (1 << (25 + (pin - map->lp_start_idx)));
|
|
|
|
lpc_gpio_set_4(sc, dir, LPC_GPIO_P2_DIR_SET,
|
|
|
|
LPC_GPIO_P0_DIR_CLR, state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lpc_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
|
|
|
|
{
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
idx = LPC_GPIO_PIN_IDX(map, pin);
|
|
|
|
|
|
|
|
switch (map->lp_port) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
snprintf(name, GPIOMAXNAME - 1, "P%d.%d", map->lp_port,
|
|
|
|
map->lp_start_bit + LPC_GPIO_PIN_IDX(map, pin));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (map->lp_start_bit == -1) {
|
|
|
|
snprintf(name, GPIOMAXNAME - 1, "GPIO_%02d", idx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(name, GPIOMAXNAME - 1, "GP%c_%02d",
|
|
|
|
(map->lp_flags & GPIO_PIN_INPUT) ? 'I' : 'O',
|
|
|
|
map->lp_start_bit + idx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
uint32_t state, flags;
|
|
|
|
int dir;
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
|
|
|
|
if (lpc_gpio_pin_getflags(dev, pin, &flags))
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
if (flags & GPIO_PIN_OUTPUT)
|
|
|
|
dir = 1;
|
|
|
|
|
|
|
|
if (flags & GPIO_PIN_INPUT)
|
|
|
|
dir = 0;
|
|
|
|
|
|
|
|
switch (map->lp_port) {
|
|
|
|
case 0:
|
|
|
|
state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P0_OUTP_STATE,
|
|
|
|
LPC_GPIO_P0_INP_STATE);
|
|
|
|
*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
|
|
|
|
case 1:
|
|
|
|
state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P1_OUTP_STATE,
|
|
|
|
LPC_GPIO_P1_INP_STATE);
|
|
|
|
*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
|
|
|
|
case 2:
|
|
|
|
state = lpc_gpio_read_4(sc, LPC_GPIO_P2_INP_STATE);
|
|
|
|
*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
|
|
|
|
case 3:
|
|
|
|
state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P3_OUTP_STATE,
|
|
|
|
LPC_GPIO_P3_INP_STATE);
|
|
|
|
if (map->lp_start_bit == -1) {
|
|
|
|
if (dir)
|
|
|
|
*value = !!(state & (1 << (25 +
|
|
|
|
LPC_GPIO_PIN_IDX(map, pin))));
|
|
|
|
else
|
|
|
|
*value = !!(state & (1 << (10 +
|
|
|
|
LPC_GPIO_PIN_IDX(map, pin))));
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, 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);
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
uint32_t state, flags;
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
|
|
|
|
if (lpc_gpio_pin_getflags(dev, pin, &flags))
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
if ((flags & GPIO_PIN_OUTPUT) == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
state = (1 << LPC_GPIO_PIN_BIT(map, pin));
|
|
|
|
|
|
|
|
switch (map->lp_port) {
|
|
|
|
case 0:
|
|
|
|
lpc_gpio_set_4(sc, value, LPC_GPIO_P0_OUTP_SET,
|
|
|
|
LPC_GPIO_P0_OUTP_CLR, state);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
lpc_gpio_set_4(sc, value, LPC_GPIO_P1_OUTP_SET,
|
|
|
|
LPC_GPIO_P1_OUTP_CLR, state);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
lpc_gpio_set_4(sc, value, LPC_GPIO_P2_OUTP_SET,
|
|
|
|
LPC_GPIO_P2_OUTP_CLR, state);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (map->lp_start_bit == -1)
|
|
|
|
state = (1 << (25 + LPC_GPIO_PIN_IDX(map, pin)));
|
|
|
|
|
|
|
|
lpc_gpio_set_4(sc, value, LPC_GPIO_P3_OUTP_SET,
|
|
|
|
LPC_GPIO_P3_OUTP_CLR, state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lpc_gpio_pin_toggle(device_t dev, uint32_t pin)
|
|
|
|
{
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
uint32_t flags;
|
|
|
|
|
|
|
|
map = lpc_gpio_get_pinmap(pin);
|
|
|
|
|
|
|
|
if (lpc_gpio_pin_getflags(dev, pin, &flags))
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
if ((flags & GPIO_PIN_OUTPUT) == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
panic("not implemented yet");
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct lpc_gpio_pinmap *
|
|
|
|
lpc_gpio_get_pinmap(int pin)
|
|
|
|
{
|
|
|
|
const struct lpc_gpio_pinmap *map;
|
|
|
|
|
|
|
|
for (map = &lpc_gpio_pins[0]; map->lp_start_idx != -1; map++) {
|
|
|
|
if (pin >= map->lp_start_idx &&
|
|
|
|
pin < map->lp_start_idx + map->lp_pin_count)
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
|
|
|
panic("pin number %d out of range", pin);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lpc_gpio_set_flags(device_t dev, int pin, int flags)
|
|
|
|
{
|
|
|
|
if (lpc_gpio_sc == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
return lpc_gpio_pin_setflags(lpc_gpio_sc->lg_dev, pin, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lpc_gpio_set_state(device_t dev, int pin, int state)
|
|
|
|
{
|
|
|
|
if (lpc_gpio_sc == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
return lpc_gpio_pin_set(lpc_gpio_sc->lg_dev, pin, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lpc_gpio_get_state(device_t dev, int pin, int *state)
|
|
|
|
{
|
|
|
|
if (lpc_gpio_sc == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
return lpc_gpio_pin_get(lpc_gpio_sc->lg_dev, pin, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-05-10 21:30:19 +00:00
|
|
|
lpc_gpio_init()
|
2012-08-15 05:37:10 +00:00
|
|
|
{
|
2014-01-05 18:40:06 +00:00
|
|
|
bus_space_tag_t bst;
|
|
|
|
bus_space_handle_t bsh;
|
|
|
|
|
|
|
|
bst = fdtbus_bs_tag;
|
|
|
|
|
2012-08-15 05:37:10 +00:00
|
|
|
/* Preset SPI devices CS pins to one */
|
2014-01-05 18:40:06 +00:00
|
|
|
bus_space_map(bst, LPC_GPIO_PHYS_BASE, LPC_GPIO_SIZE, 0, &bsh);
|
|
|
|
bus_space_write_4(bst, bsh, LPC_GPIO_P3_OUTP_SET,
|
2012-08-15 05:37:10 +00:00
|
|
|
1 << (SSD1289_CS_PIN - LPC_GPIO_GPO_00(0)) |
|
|
|
|
1 << (SSD1289_DC_PIN - LPC_GPIO_GPO_00(0)) |
|
|
|
|
1 << (ADS7846_CS_PIN - LPC_GPIO_GPO_00(0)));
|
2014-01-05 18:40:06 +00:00
|
|
|
bus_space_unmap(bst, bsh, LPC_GPIO_SIZE);
|
2012-08-15 05:37:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
2015-01-31 19:32:14 +00:00
|
|
|
DEVMETHOD(gpio_get_bus, lpc_gpio_get_bus),
|
2012-08-15 05:37:10 +00:00
|
|
|
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);
|