sh: pfc: pin config get/set support.
This implements simple support for adjusting the pin config value via the pinctrl API. The pinconf-generic code is abandoned for now until we've got a chance to revamp the pinmux_type state tracking that's needed by legacy code. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
5440711073
commit
fdd85ec3eb
|
@ -17,7 +17,6 @@ config PINCTRL_SH_PFC
|
||||||
select PINCTRL
|
select PINCTRL
|
||||||
select PINMUX
|
select PINMUX
|
||||||
select PINCONF
|
select PINCONF
|
||||||
select GENERIC_PINCONF
|
|
||||||
|
|
||||||
config GPIO_SH_PFC
|
config GPIO_SH_PFC
|
||||||
tristate "SuperH PFC GPIO support"
|
tristate "SuperH PFC GPIO support"
|
||||||
|
|
|
@ -65,10 +65,17 @@ static int sh_pfc_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
|
||||||
|
unsigned offset)
|
||||||
|
{
|
||||||
|
seq_printf(s, "%s", DRV_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
static struct pinctrl_ops sh_pfc_pinctrl_ops = {
|
static struct pinctrl_ops sh_pfc_pinctrl_ops = {
|
||||||
.get_groups_count = sh_pfc_get_groups_count,
|
.get_groups_count = sh_pfc_get_groups_count,
|
||||||
.get_group_name = sh_pfc_get_group_name,
|
.get_group_name = sh_pfc_get_group_name,
|
||||||
.get_group_pins = sh_pfc_get_group_pins,
|
.get_group_pins = sh_pfc_get_group_pins,
|
||||||
|
.pin_dbg_show = sh_pfc_pin_dbg_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev)
|
static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev)
|
||||||
|
@ -124,6 +131,59 @@ static inline int sh_pfc_config_function(struct sh_pfc *pfc, unsigned offset)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sh_pfc_reconfig_pin(struct sh_pfc *pfc, unsigned offset,
|
||||||
|
int new_type)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int pinmux_type;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&pfc->lock, flags);
|
||||||
|
|
||||||
|
pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if the present config needs to first be de-configured.
|
||||||
|
*/
|
||||||
|
switch (pinmux_type) {
|
||||||
|
case PINMUX_TYPE_GPIO:
|
||||||
|
break;
|
||||||
|
case PINMUX_TYPE_OUTPUT:
|
||||||
|
case PINMUX_TYPE_INPUT:
|
||||||
|
case PINMUX_TYPE_INPUT_PULLUP:
|
||||||
|
case PINMUX_TYPE_INPUT_PULLDOWN:
|
||||||
|
sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dry run
|
||||||
|
*/
|
||||||
|
if (sh_pfc_config_gpio(pfc, offset, new_type,
|
||||||
|
GPIO_CFG_DRYRUN) != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request
|
||||||
|
*/
|
||||||
|
if (sh_pfc_config_gpio(pfc, offset, new_type,
|
||||||
|
GPIO_CFG_REQ) != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
|
||||||
|
pfc->gpios[offset].flags |= new_type;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
spin_unlock_irqrestore(&pfc->lock, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev,
|
static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||||
struct pinctrl_gpio_range *range,
|
struct pinctrl_gpio_range *range,
|
||||||
unsigned offset)
|
unsigned offset)
|
||||||
|
@ -185,49 +245,9 @@ static int sh_pfc_gpio_set_direction(struct pinctrl_dev *pctldev,
|
||||||
unsigned offset, bool input)
|
unsigned offset, bool input)
|
||||||
{
|
{
|
||||||
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
|
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||||
struct sh_pfc *pfc = pmx->pfc;
|
int type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT;
|
||||||
unsigned long flags;
|
|
||||||
int pinmux_type, new_pinmux_type;
|
|
||||||
int ret = -EINVAL;
|
|
||||||
|
|
||||||
new_pinmux_type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT;
|
return sh_pfc_reconfig_pin(pmx->pfc, offset, type);
|
||||||
|
|
||||||
spin_lock_irqsave(&pfc->lock, flags);
|
|
||||||
|
|
||||||
pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
|
|
||||||
|
|
||||||
switch (pinmux_type) {
|
|
||||||
case PINMUX_TYPE_GPIO:
|
|
||||||
break;
|
|
||||||
case PINMUX_TYPE_OUTPUT:
|
|
||||||
case PINMUX_TYPE_INPUT:
|
|
||||||
case PINMUX_TYPE_INPUT_PULLUP:
|
|
||||||
case PINMUX_TYPE_INPUT_PULLDOWN:
|
|
||||||
sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sh_pfc_config_gpio(pfc, offset,
|
|
||||||
new_pinmux_type,
|
|
||||||
GPIO_CFG_DRYRUN) != 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (sh_pfc_config_gpio(pfc, offset,
|
|
||||||
new_pinmux_type,
|
|
||||||
GPIO_CFG_REQ) != 0)
|
|
||||||
BUG();
|
|
||||||
|
|
||||||
pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
|
|
||||||
pfc->gpios[offset].flags |= new_pinmux_type;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
spin_unlock_irqrestore(&pfc->lock, flags);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pinmux_ops sh_pfc_pinmux_ops = {
|
static struct pinmux_ops sh_pfc_pinmux_ops = {
|
||||||
|
@ -244,26 +264,53 @@ static struct pinmux_ops sh_pfc_pinmux_ops = {
|
||||||
static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
|
static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
|
||||||
unsigned long *config)
|
unsigned long *config)
|
||||||
{
|
{
|
||||||
enum pin_config_param param = (enum pin_config_param)(*config);
|
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
struct sh_pfc *pfc = pmx->pfc;
|
||||||
|
|
||||||
switch (param) {
|
*config = pfc->gpios[pin].flags & PINMUX_FLAG_TYPE;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENOTSUPP;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
|
static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
|
||||||
unsigned long config)
|
unsigned long config)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
struct sh_pfc *pfc = pmx->pfc;
|
||||||
|
|
||||||
|
/* Validate the new type */
|
||||||
|
if (config >= PINMUX_FLAG_TYPE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return sh_pfc_reconfig_pin(pmx->pfc, pin, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sh_pfc_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
||||||
|
struct seq_file *s, unsigned pin)
|
||||||
|
{
|
||||||
|
const char *pinmux_type_str[] = {
|
||||||
|
[PINMUX_TYPE_NONE] = "none",
|
||||||
|
[PINMUX_TYPE_FUNCTION] = "function",
|
||||||
|
[PINMUX_TYPE_GPIO] = "gpio",
|
||||||
|
[PINMUX_TYPE_OUTPUT] = "output",
|
||||||
|
[PINMUX_TYPE_INPUT] = "input",
|
||||||
|
[PINMUX_TYPE_INPUT_PULLUP] = "input bias pull up",
|
||||||
|
[PINMUX_TYPE_INPUT_PULLDOWN] = "input bias pull down",
|
||||||
|
};
|
||||||
|
unsigned long config;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = sh_pfc_pinconf_get(pctldev, pin, &config);
|
||||||
|
if (unlikely(rc != 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
seq_printf(s, " %s", pinmux_type_str[config]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pinconf_ops sh_pfc_pinconf_ops = {
|
static struct pinconf_ops sh_pfc_pinconf_ops = {
|
||||||
.is_generic = true,
|
|
||||||
.pin_config_get = sh_pfc_pinconf_get,
|
.pin_config_get = sh_pfc_pinconf_get,
|
||||||
.pin_config_set = sh_pfc_pinconf_set,
|
.pin_config_set = sh_pfc_pinconf_set,
|
||||||
|
.pin_config_dbg_show = sh_pfc_pinconf_dbg_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pinctrl_gpio_range sh_pfc_gpio_range = {
|
static struct pinctrl_gpio_range sh_pfc_gpio_range = {
|
||||||
|
|
Loading…
Reference in New Issue