/* Check whether the requested parameter is supported for a pin. */ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin, unsigned int param) { int idx = sh_pfc_get_pin_index(pfc, _pin); const struct sh_pfc_pin *pin = &pfc->info->pins[idx]; switch (param) { case PIN_CONFIG_BIAS_DISABLE: return pin->configs & (SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN); case PIN_CONFIG_BIAS_PULL_UP: return pin->configs & SH_PFC_PIN_CFG_PULL_UP; case PIN_CONFIG_BIAS_PULL_DOWN: return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN; case PIN_CONFIG_DRIVE_STRENGTH: return pin->configs & SH_PFC_PIN_CFG_DRIVE_STRENGTH; case PIN_CONFIG_POWER_SOURCE: return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE; default: return false; } }
static int sh_pfc_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc *pfc = pmx->pfc; int new_type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT; int idx = sh_pfc_get_pin_index(pfc, offset); const struct sh_pfc_pin *pin = &pfc->info->pins[idx]; struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; unsigned long flags; unsigned int dir; int ret; /* Check if the requested direction is supported by the pin. Not all SoC * provide pin config data, so perform the check conditionally. */ if (pin->configs) { dir = input ? SH_PFC_PIN_CFG_INPUT : SH_PFC_PIN_CFG_OUTPUT; if (!(pin->configs & dir)) return -EINVAL; } spin_lock_irqsave(&pfc->lock, flags); ret = sh_pfc_config_mux(pfc, pin->enum_id, new_type); if (ret < 0) goto done; cfg->type = new_type; done: spin_unlock_irqrestore(&pfc->lock, flags); return ret; }
static int sh_pfc_pinctrl_group_set(struct udevice *dev, unsigned group_selector, unsigned func_selector) { struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); struct sh_pfc_pinctrl *pmx = &priv->pmx; struct sh_pfc *pfc = &priv->pfc; const struct sh_pfc_pin_group *grp = &priv->pfc.info->groups[group_selector]; unsigned int i; int ret = 0; for (i = 0; i < grp->nr_pins; ++i) { int idx = sh_pfc_get_pin_index(pfc, grp->pins[i]); struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; if (cfg->type != PINMUX_TYPE_NONE) { ret = -EBUSY; goto done; } } for (i = 0; i < grp->nr_pins; ++i) { ret = sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION); if (ret < 0) break; } done: return ret; }
int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) { struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); struct sh_pfc_pinctrl *pmx = &priv->pmx; struct sh_pfc *pfc = &priv->pfc; struct sh_pfc_pin_config *cfg; const struct sh_pfc_pin *pin = NULL; int i, idx; for (i = 1; i < pfc->info->nr_pins; i++) { if (priv->pfc.info->pins[i].pin != pin_selector) continue; pin = &priv->pfc.info->pins[i]; break; } if (!pin) return -EINVAL; idx = sh_pfc_get_pin_index(pfc, pin->pin); cfg = &pmx->configs[idx]; if (cfg->type != PINMUX_TYPE_NONE) return -EBUSY; return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO); }
static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc *pfc = pmx->pfc; int idx = sh_pfc_get_pin_index(pfc, offset); struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; unsigned long flags; int ret; spin_lock_irqsave(&pfc->lock, flags); if (cfg->type != PINMUX_TYPE_NONE) { dev_err(pfc->dev, "Pin %u is busy, can't configure it as GPIO.\n", offset); ret = -EBUSY; goto done; } cfg->type = PINMUX_TYPE_GPIO; ret = 0; done: spin_unlock_irqrestore(&pfc->lock, flags); return ret; }
static int sh_pfc_func_enable(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc *pfc = pmx->pfc; const struct sh_pfc_pin_group *grp = &pfc->info->groups[group]; unsigned long flags; unsigned int i; int ret = 0; spin_lock_irqsave(&pfc->lock, flags); for (i = 0; i < grp->nr_pins; ++i) { int idx = sh_pfc_get_pin_index(pfc, grp->pins[i]); struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; if (cfg->type != PINMUX_TYPE_NONE) { ret = -EBUSY; goto done; } } for (i = 0; i < grp->nr_pins; ++i) { ret = sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION); if (ret < 0) break; } done: spin_unlock_irqrestore(&pfc->lock, flags); return ret; }
static void gpio_get_data_reg(struct sh_pfc_chip *chip, unsigned int offset, struct sh_pfc_gpio_data_reg **reg, unsigned int *bit) { int idx = sh_pfc_get_pin_index(chip->pfc, offset); struct sh_pfc_gpio_pin *gpio_pin = &chip->pins[idx]; *reg = &chip->regs[gpio_pin->dreg]; *bit = gpio_pin->dbit; }
static int gpio_pin_request(struct gpio_chip *gc, unsigned offset) { struct sh_pfc *pfc = gpio_to_pfc(gc); int idx = sh_pfc_get_pin_index(pfc, offset); if (idx < 0 || pfc->info->pins[idx].enum_id == 0) return -EINVAL; return pinctrl_gpio_request(offset); }
static void sh_pfc_gpio_disable_free(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc *pfc = pmx->pfc; int idx = sh_pfc_get_pin_index(pfc, offset); struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; unsigned long flags; spin_lock_irqsave(&pfc->lock, flags); cfg->type = PINMUX_TYPE_NONE; spin_unlock_irqrestore(&pfc->lock, flags); }
static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector, unsigned func_selector) { struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); struct sh_pfc_pinctrl *pmx = &priv->pmx; struct sh_pfc *pfc = &priv->pfc; const struct sh_pfc_pin *pin = &priv->pfc.info->pins[pin_selector]; int idx = sh_pfc_get_pin_index(pfc, pin->pin); struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; if (cfg->type != PINMUX_TYPE_NONE) return -EBUSY; return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_FUNCTION); }
/* Check whether the requested parameter is supported for a pin. */ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin, enum pin_config_param param) { int idx = sh_pfc_get_pin_index(pfc, _pin); const struct sh_pfc_pin *pin = &pfc->info->pins[idx]; switch (param) { case PIN_CONFIG_BIAS_DISABLE: return true; case PIN_CONFIG_BIAS_PULL_UP: return pin->configs & SH_PFC_PIN_CFG_PULL_UP; case PIN_CONFIG_BIAS_PULL_DOWN: return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN; default: return false; } }
static void sh_pfc_func_disable(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc *pfc = pmx->pfc; const struct sh_pfc_pin_group *grp = &pfc->info->groups[group]; unsigned long flags; unsigned int i; spin_lock_irqsave(&pfc->lock, flags); for (i = 0; i < grp->nr_pins; ++i) { int idx = sh_pfc_get_pin_index(pfc, grp->pins[i]); struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; cfg->type = PINMUX_TYPE_NONE; } spin_unlock_irqrestore(&pfc->lock, flags); }