a10_gpio: Add support for more modern pin configuration

a10_gpio previously accepted only {allwinner,}drive and {allwinner,}pull for
drive/bias setting, while newer DTS is using drive-strength and
bias-{disable,pull-up,pull-down} properties. Accept these properties as
well.

Additionally make bias and drive strength optional rather than required; not
setting them should just indicate that we do not need to configure these
properties.

Tested on:	BananaPi-M3 (a83t)
Reviewed by:	manu
Approved by:	emaste (implicit)
Obtained from:	NetBSD (partially)
Differential Revision:	https://reviews.freebsd.org/D13284
This commit is contained in:
Kyle Evans 2017-12-01 20:51:08 +00:00
parent a027c8e958
commit 515694c636
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=326433

View file

@ -203,6 +203,11 @@ struct a10_gpio_softc {
#define A10_GPIO_GP_INT_STA 0x214
#define A10_GPIO_GP_INT_DEB 0x218
static char *a10_gpio_parse_function(phandle_t node);
static const char **a10_gpio_parse_pins(phandle_t node, int *pins_nb);
static uint32_t a10_gpio_parse_bias(phandle_t node);
static int a10_gpio_parse_drive_strength(phandle_t node, uint32_t *drive);
static int a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value);
static int a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
static int a10_gpio_pin_get_locked(struct a10_gpio_softc *sc, uint32_t pin, unsigned int *value);
@ -278,6 +283,9 @@ a10_gpio_set_pud(struct a10_gpio_softc *sc, uint32_t pin, uint32_t state)
{
uint32_t bank, offset, val;
if (a10_gpio_get_pud(sc, pin) == state)
return;
/* Must be called with lock held. */
A10_GPIO_LOCK_ASSERT(sc);
@ -313,6 +321,9 @@ a10_gpio_set_drv(struct a10_gpio_softc *sc, uint32_t pin, uint32_t drive)
{
uint32_t bank, offset, val;
if (a10_gpio_get_drv(sc, pin) == drive)
return;
/* Must be called with lock held. */
A10_GPIO_LOCK_ASSERT(sc);
@ -541,6 +552,75 @@ a10_gpio_pin_get_locked(struct a10_gpio_softc *sc,uint32_t pin,
return (0);
}
static char *
a10_gpio_parse_function(phandle_t node)
{
char *function;
if (OF_getprop_alloc(node, "function", sizeof(*function),
(void **)&function) != -1)
return (function);
if (OF_getprop_alloc(node, "allwinner,function", sizeof(*function),
(void **)&function) != -1)
return (function);
return (NULL);
}
static const char **
a10_gpio_parse_pins(phandle_t node, int *pins_nb)
{
const char **pinlist;
*pins_nb = ofw_bus_string_list_to_array(node, "pins", &pinlist);
if (*pins_nb > 0)
return (pinlist);
*pins_nb = ofw_bus_string_list_to_array(node, "allwinner,pins",
&pinlist);
if (*pins_nb > 0)
return (pinlist);
return (NULL);
}
static uint32_t
a10_gpio_parse_bias(phandle_t node)
{
uint32_t bias;
if (OF_getencprop(node, "pull", &bias, sizeof(bias)) != -1)
return (bias);
if (OF_getencprop(node, "allwinner,pull", &bias, sizeof(bias)) != -1)
return (bias);
if (OF_hasprop(node, "bias-disable"))
return (A10_GPIO_NONE);
if (OF_hasprop(node, "bias-pull-up"))
return (A10_GPIO_PULLUP);
if (OF_hasprop(node, "bias-pull-down"))
return (A10_GPIO_PULLDOWN);
return (A10_GPIO_NONE);
}
static int
a10_gpio_parse_drive_strength(phandle_t node, uint32_t *drive)
{
uint32_t drive_str;
if (OF_getencprop(node, "drive", drive, sizeof(*drive)) != -1)
return (0);
if (OF_getencprop(node, "allwinner,drive", drive, sizeof(*drive)) != -1)
return (0);
if (OF_getencprop(node, "drive-strength", &drive_str,
sizeof(drive_str)) != -1) {
*drive = (drive_str / 10) - 1;
return (0);
}
return (1);
}
static int
a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
{
@ -682,46 +762,29 @@ aw_fdt_configure_pins(device_t dev, phandle_t cfgxref)
char *pin_function = NULL;
uint32_t pin_drive, pin_pull;
int pins_nb, pin_num, pin_func, i, ret;
bool set_drive;
sc = device_get_softc(dev);
node = OF_node_from_xref(cfgxref);
ret = 0;
set_drive = false;
/* Getting all prop for configuring pins */
pins_nb = ofw_bus_string_list_to_array(node, "pins", &pinlist);
if (pins_nb <= 0) {
pins_nb = ofw_bus_string_list_to_array(node, "allwinner,pins",
&pinlist);
if (pins_nb <= 0)
return (ENOENT);
}
if (OF_getprop_alloc(node, "function",
sizeof(*pin_function),
(void **)&pin_function) == -1) {
if (OF_getprop_alloc(node, "allwinner,function",
sizeof(*pin_function),
(void **)&pin_function) == -1) {
ret = ENOENT;
goto out;
}
}
if (OF_getencprop(node, "drive",
&pin_drive, sizeof(pin_drive)) == -1) {
if (OF_getencprop(node, "allwinner,drive",
&pin_drive, sizeof(pin_drive)) == -1) {
ret = ENOENT;
goto out;
}
}
if (OF_getencprop(node, "pull",
&pin_pull, sizeof(pin_pull)) == -1) {
if (OF_getencprop(node, "allwinner,pull",
&pin_pull, sizeof(pin_pull)) == -1) {
ret = ENOENT;
goto out;
}
pinlist = a10_gpio_parse_pins(node, &pins_nb);
if (pinlist == NULL)
return (ENOENT);
pin_function = a10_gpio_parse_function(node);
if (pin_function == NULL) {
ret = ENOENT;
goto out;
}
if (a10_gpio_parse_drive_strength(node, &pin_drive) == 0)
set_drive = true;
pin_pull = a10_gpio_parse_bias(node);
/* Configure each pin to the correct function, drive and pull */
for (i = 0; i < pins_nb; i++) {
pin_num = aw_find_pinnum_by_name(sc, pinlist[i]);
@ -739,12 +802,11 @@ aw_fdt_configure_pins(device_t dev, phandle_t cfgxref)
if (a10_gpio_get_function(sc, pin_num) != pin_func)
a10_gpio_set_function(sc, pin_num, pin_func);
if (a10_gpio_get_drv(sc, pin_num) != pin_drive)
if (set_drive)
a10_gpio_set_drv(sc, pin_num, pin_drive);
if (a10_gpio_get_pud(sc, pin_num) != pin_pull &&
(pin_pull == A10_GPIO_PULLUP ||
pin_pull == A10_GPIO_PULLDOWN))
if (pin_pull != A10_GPIO_NONE)
a10_gpio_set_pud(sc, pin_num, pin_pull);
A10_GPIO_UNLOCK(sc);
}