Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/allwinner/a10_gpio.c
Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
#include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
#include <dev/fdt/fdt_pinctrl.h> | #include <dev/fdt/fdt_pinctrl.h> | ||||
#include <dev/gpio/gpiobusvar.h> | #include <dev/gpio/gpiobusvar.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <arm/allwinner/allwinner_machdep.h> | #include <arm/allwinner/allwinner_machdep.h> | ||||
#include <arm/allwinner/allwinner_pinctrl.h> | #include <arm/allwinner/allwinner_pinctrl.h> | ||||
#include <dev/extres/clk/clk.h> | |||||
#include <dev/extres/hwreset/hwreset.h> | |||||
#include "gpio_if.h" | #include "gpio_if.h" | ||||
/* | |||||
* A10 have 9 banks of gpio. | |||||
* 32 pins per bank: | |||||
* PA0 - PA17 | PB0 - PB23 | PC0 - PC24 | |||||
* PD0 - PD27 | PE0 - PE31 | PF0 - PF5 | |||||
* PG0 - PG9 | PH0 - PH27 | PI0 - PI12 | |||||
*/ | |||||
#define A10_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ | #define A10_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ | ||||
GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN) | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN) | ||||
#define A10_GPIO_NONE 0 | #define A10_GPIO_NONE 0 | ||||
#define A10_GPIO_PULLUP 1 | #define A10_GPIO_PULLUP 1 | ||||
#define A10_GPIO_PULLDOWN 2 | #define A10_GPIO_PULLDOWN 2 | ||||
#define A10_GPIO_INPUT 0 | #define A10_GPIO_INPUT 0 | ||||
#define A10_GPIO_OUTPUT 1 | #define A10_GPIO_OUTPUT 1 | ||||
#define AW_GPIO_DRV_MASK 0x3 | #define AW_GPIO_DRV_MASK 0x3 | ||||
#define AW_GPIO_PUD_MASK 0x3 | #define AW_GPIO_PUD_MASK 0x3 | ||||
static struct ofw_compat_data compat_data[] = { | #define AW_PINCTRL 1 | ||||
{"allwinner,sun4i-a10-pinctrl", 1}, | #define AW_R_PINCTRL 2 | ||||
{"allwinner,sun7i-a20-pinctrl", 1}, | |||||
{"allwinner,sun6i-a31-pinctrl", 1}, | |||||
{"allwinner,sun6i-a31s-pinctrl", 1}, | |||||
{NULL, 0} | |||||
}; | |||||
struct a10_gpio_softc { | |||||
device_t sc_dev; | |||||
device_t sc_busdev; | |||||
struct mtx sc_mtx; | |||||
struct resource * sc_mem_res; | |||||
struct resource * sc_irq_res; | |||||
bus_space_tag_t sc_bst; | |||||
bus_space_handle_t sc_bsh; | |||||
void * sc_intrhand; | |||||
const struct allwinner_padconf * padconf; | |||||
}; | |||||
/* Defined in a10_padconf.c */ | /* Defined in a10_padconf.c */ | ||||
#ifdef SOC_ALLWINNER_A10 | #ifdef SOC_ALLWINNER_A10 | ||||
extern const struct allwinner_padconf a10_padconf; | extern const struct allwinner_padconf a10_padconf; | ||||
#endif | #endif | ||||
/* Defined in a20_padconf.c */ | /* Defined in a20_padconf.c */ | ||||
#ifdef SOC_ALLWINNER_A20 | #ifdef SOC_ALLWINNER_A20 | ||||
extern const struct allwinner_padconf a20_padconf; | extern const struct allwinner_padconf a20_padconf; | ||||
#endif | #endif | ||||
/* Defined in a31_padconf.c */ | /* Defined in a31_padconf.c */ | ||||
#ifdef SOC_ALLWINNER_A31 | #ifdef SOC_ALLWINNER_A31 | ||||
extern const struct allwinner_padconf a31_padconf; | extern const struct allwinner_padconf a31_padconf; | ||||
#endif | #endif | ||||
/* Defined in a31s_padconf.c */ | /* Defined in a31s_padconf.c */ | ||||
#ifdef SOC_ALLWINNER_A31S | #ifdef SOC_ALLWINNER_A31S | ||||
extern const struct allwinner_padconf a31s_padconf; | extern const struct allwinner_padconf a31s_padconf; | ||||
#endif | #endif | ||||
#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) | |||||
extern const struct allwinner_padconf a31_r_padconf; | |||||
#endif | |||||
static struct ofw_compat_data compat_data[] = { | |||||
#ifdef SOC_ALLWINNER_A10 | |||||
{"allwinner,sun4i-a10-pinctrl", (uintptr_t)&a10_padconf}, | |||||
#endif | |||||
#ifdef SOC_ALLWINNER_A20 | |||||
{"allwinner,sun7i-a20-pinctrl", (uintptr_t)&a20_padconf}, | |||||
#endif | |||||
#ifdef SOC_ALLWINNER_A31 | |||||
{"allwinner,sun6i-a31-pinctrl", (uintptr_t)&a31_padconf}, | |||||
{"allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&a31_r_padconf}, | |||||
jmcneill: Instead of the ifndef below, why don't we just say `#if defined(SOC_ALLWINNER_A31) || defined… | |||||
Done Inline ActionsBecause sometimes I'm stupid that's why :) manu_bidouilliste.com: Because sometimes I'm stupid that's why :)
I'll change that | |||||
#endif | |||||
#ifdef SOC_ALLWINNER_A31S | |||||
{"allwinner,sun6i-a31s-pinctrl", (uintptr_t)&a31s_padconf}, | |||||
#endif | |||||
#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) | |||||
{"allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&a31_r_padconf}, | |||||
jmcneillUnsubmitted Done Inline ActionsThis compat string is duplicated on line 111 jmcneill: This compat string is duplicated on line 111 | |||||
#endif | |||||
{NULL, 0} | |||||
}; | |||||
struct a10_gpio_softc { | |||||
device_t sc_dev; | |||||
device_t sc_busdev; | |||||
struct mtx sc_mtx; | |||||
struct resource * sc_mem_res; | |||||
struct resource * sc_irq_res; | |||||
bus_space_tag_t sc_bst; | |||||
bus_space_handle_t sc_bsh; | |||||
void * sc_intrhand; | |||||
const struct allwinner_padconf * padconf; | |||||
}; | |||||
#define A10_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) | #define A10_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) | ||||
#define A10_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) | #define A10_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) | ||||
#define A10_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) | #define A10_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) | ||||
#define A10_GPIO_GP_CFG(_bank, _idx) 0x00 + ((_bank) * 0x24) + ((_idx) << 2) | #define A10_GPIO_GP_CFG(_bank, _idx) 0x00 + ((_bank) * 0x24) + ((_idx) << 2) | ||||
#define A10_GPIO_GP_DAT(_bank) 0x10 + ((_bank) * 0x24) | #define A10_GPIO_GP_DAT(_bank) 0x10 + ((_bank) * 0x24) | ||||
#define A10_GPIO_GP_DRV(_bank, _idx) 0x14 + ((_bank) * 0x24) + ((_idx) << 2) | #define A10_GPIO_GP_DRV(_bank, _idx) 0x14 + ((_bank) * 0x24) + ((_idx) << 2) | ||||
#define A10_GPIO_GP_PUL(_bank, _idx) 0x1c + ((_bank) * 0x24) + ((_idx) << 2) | #define A10_GPIO_GP_PUL(_bank, _idx) 0x1c + ((_bank) * 0x24) + ((_idx) << 2) | ||||
▲ Show 20 Lines • Show All 392 Lines • ▼ Show 20 Lines | a10_gpio_probe(device_t dev) | ||||
device_set_desc(dev, "Allwinner GPIO/Pinmux controller"); | device_set_desc(dev, "Allwinner GPIO/Pinmux controller"); | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static int | static int | ||||
a10_gpio_attach(device_t dev) | a10_gpio_attach(device_t dev) | ||||
{ | { | ||||
int rid; | int rid, error; | ||||
phandle_t gpio; | phandle_t gpio; | ||||
struct a10_gpio_softc *sc; | struct a10_gpio_softc *sc; | ||||
clk_t clk; | |||||
hwreset_t rst; | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
mtx_init(&sc->sc_mtx, "a10 gpio", "gpio", MTX_SPIN); | mtx_init(&sc->sc_mtx, "a10 gpio", "gpio", MTX_SPIN); | ||||
rid = 0; | rid = 0; | ||||
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | ||||
RF_ACTIVE); | RF_ACTIVE); | ||||
if (!sc->sc_mem_res) { | if (!sc->sc_mem_res) { | ||||
device_printf(dev, "cannot allocate memory window\n"); | device_printf(dev, "cannot allocate memory window\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
sc->sc_bst = rman_get_bustag(sc->sc_mem_res); | sc->sc_bst = rman_get_bustag(sc->sc_mem_res); | ||||
sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); | sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); | ||||
rid = 0; | rid = 0; | ||||
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | ||||
RF_ACTIVE); | RF_ACTIVE); | ||||
if (!sc->sc_irq_res) { | if (!sc->sc_irq_res) { | ||||
device_printf(dev, "cannot allocate interrupt\n"); | device_printf(dev, "cannot allocate interrupt\n"); | ||||
Done Inline ActionsAs discussed on IRC, we should move the padconf values to compat_data[] ocd_data, so something like: static struct ofw_compat_data compat_data[] = { #ifdef SOC_ALLWINNER_A10 { "allwinner,sun4i-a10-pinctrl", (uintptr_t)&a10_padconf }, #endif ... and here we can simply do: sc->padconf = (struct allwinner_padconf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; jmcneill: As discussed on IRC, we should move the padconf values to compat_data[] ocd_data, so something… | |||||
goto fail; | goto fail; | ||||
} | } | ||||
/* Find our node. */ | /* Find our node. */ | ||||
gpio = ofw_bus_get_node(sc->sc_dev); | gpio = ofw_bus_get_node(sc->sc_dev); | ||||
if (!OF_hasprop(gpio, "gpio-controller")) | if (!OF_hasprop(gpio, "gpio-controller")) | ||||
/* Node is not a GPIO controller. */ | /* Node is not a GPIO controller. */ | ||||
goto fail; | goto fail; | ||||
/* Use the right pin data for the current SoC */ | /* Use the right pin data for the current SoC */ | ||||
switch (allwinner_soc_type()) { | sc->padconf = (struct allwinner_padconf *)ofw_bus_search_compatible(dev, | ||||
#ifdef SOC_ALLWINNER_A10 | compat_data)->ocd_data; | ||||
case ALLWINNERSOC_A10: | |||||
sc->padconf = &a10_padconf; | if (hwreset_get_by_ofw_idx(dev, 0, &rst) == 0) { | ||||
break; | error = hwreset_deassert(rst); | ||||
#endif | if (error != 0) { | ||||
#ifdef SOC_ALLWINNER_A20 | device_printf(dev, "cannot de-assert reset\n"); | ||||
case ALLWINNERSOC_A20: | return (error); | ||||
sc->padconf = &a20_padconf; | } | ||||
break; | } | ||||
#endif | |||||
#ifdef SOC_ALLWINNER_A31 | if (clk_get_by_ofw_index(dev, 0, &clk) == 0) { | ||||
case ALLWINNERSOC_A31: | error = clk_enable(clk); | ||||
sc->padconf = &a31_padconf; | if (error != 0) { | ||||
break; | device_printf(dev, "could not enable clock\n"); | ||||
#endif | return (error); | ||||
#ifdef SOC_ALLWINNER_A31S | } | ||||
case ALLWINNERSOC_A31S: | |||||
sc->padconf = &a31s_padconf; | |||||
break; | |||||
#endif | |||||
default: | |||||
return (ENOENT); | |||||
} | } | ||||
Done Inline ActionsShould this be protected with ifdef SOC_ALLWINNER_xxx ? jmcneill: Should this be protected with ifdef SOC_ALLWINNER_xxx ? | |||||
sc->sc_busdev = gpiobus_attach_bus(dev); | sc->sc_busdev = gpiobus_attach_bus(dev); | ||||
if (sc->sc_busdev == NULL) | if (sc->sc_busdev == NULL) | ||||
goto fail; | goto fail; | ||||
/* | /* | ||||
* Register as a pinctrl device | * Register as a pinctrl device | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 88 Lines • Show Last 20 Lines |
Instead of the ifndef below, why don't we just say #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) here? Same for the extern above.