diff options
Diffstat (limited to 'drivers/pinctrl/uniphier/pinctrl-uniphier-core.c')
-rw-r--r-- | drivers/pinctrl/uniphier/pinctrl-uniphier-core.c | 298 |
1 files changed, 180 insertions, 118 deletions
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c index 9674009..9b2ee71 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -14,6 +14,7 @@ #include <linux/export.h> #include <linux/mfd/syscon.h> +#include <linux/of.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinctrl.h> @@ -26,8 +27,10 @@ #include "pinctrl-uniphier.h" struct uniphier_pinctrl_priv { + struct pinctrl_desc pctldesc; struct pinctrl_dev *pctldev; struct regmap *regmap; + unsigned int regbase; struct uniphier_pinctrl_socdata *socdata; }; @@ -63,16 +66,22 @@ static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { - const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset]; - const char *pull_dir, *drv_str; + const struct pin_desc *desc = pin_desc_get(pctldev, offset); + const char *pull_dir, *drv_type; - switch (uniphier_pin_get_pull_dir(pin->drv_data)) { + switch (uniphier_pin_get_pull_dir(desc->drv_data)) { case UNIPHIER_PIN_PULL_UP: pull_dir = "UP"; break; case UNIPHIER_PIN_PULL_DOWN: pull_dir = "DOWN"; break; + case UNIPHIER_PIN_PULL_UP_FIXED: + pull_dir = "UP(FIXED)"; + break; + case UNIPHIER_PIN_PULL_DOWN_FIXED: + pull_dir = "DOWN(FIXED)"; + break; case UNIPHIER_PIN_PULL_NONE: pull_dir = "NONE"; break; @@ -80,30 +89,33 @@ static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, BUG(); } - switch (uniphier_pin_get_drv_str(pin->drv_data)) { - case UNIPHIER_PIN_DRV_4_8: - drv_str = "4/8(mA)"; + switch (uniphier_pin_get_drv_type(desc->drv_data)) { + case UNIPHIER_PIN_DRV_1BIT: + drv_type = "4/8(mA)"; + break; + case UNIPHIER_PIN_DRV_2BIT: + drv_type = "8/12/16/20(mA)"; break; - case UNIPHIER_PIN_DRV_8_12_16_20: - drv_str = "8/12/16/20(mA)"; + case UNIPHIER_PIN_DRV_3BIT: + drv_type = "4/5/7/9/11/12/14/16(mA)"; break; - case UNIPHIER_PIN_DRV_FIXED_4: - drv_str = "4(mA)"; + case UNIPHIER_PIN_DRV_FIXED4: + drv_type = "4(mA)"; break; - case UNIPHIER_PIN_DRV_FIXED_5: - drv_str = "5(mA)"; + case UNIPHIER_PIN_DRV_FIXED5: + drv_type = "5(mA)"; break; - case UNIPHIER_PIN_DRV_FIXED_8: - drv_str = "8(mA)"; + case UNIPHIER_PIN_DRV_FIXED8: + drv_type = "8(mA)"; break; case UNIPHIER_PIN_DRV_NONE: - drv_str = "NONE"; + drv_type = "NONE"; break; default: BUG(); } - seq_printf(s, " PULL_DIR=%s DRV_STR=%s", pull_dir, drv_str); + seq_printf(s, " PULL_DIR=%s DRV_TYPE=%s", pull_dir, drv_type); } #endif @@ -119,12 +131,12 @@ static const struct pinctrl_ops uniphier_pctlops = { }; static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, - const struct pinctrl_pin_desc *pin, + const struct pin_desc *desc, enum pin_config_param param) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); enum uniphier_pin_pull_dir pull_dir = - uniphier_pin_get_pull_dir(pin->drv_data); + uniphier_pin_get_pull_dir(desc->drv_data); unsigned int pupdctrl, reg, shift, val; unsigned int expected = 1; int ret; @@ -154,12 +166,12 @@ static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, BUG(); } - pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); + pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data); reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; shift = pupdctrl % 32; - ret = regmap_read(priv->regmap, reg, &val); + ret = regmap_read(priv->regmap, priv->regbase + reg, &val); if (ret) return ret; @@ -169,34 +181,42 @@ static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, } static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, - const struct pinctrl_pin_desc *pin, + const struct pin_desc *desc, u16 *strength) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); - enum uniphier_pin_drv_str drv_str = - uniphier_pin_get_drv_str(pin->drv_data); - const unsigned int strength_4_8[] = {4, 8}; - const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20}; + enum uniphier_pin_drv_type type = + uniphier_pin_get_drv_type(desc->drv_data); + const unsigned int strength_1bit[] = {4, 8}; + const unsigned int strength_2bit[] = {8, 12, 16, 20}; + const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16}; const unsigned int *supported_strength; unsigned int drvctrl, reg, shift, mask, width, val; int ret; - switch (drv_str) { - case UNIPHIER_PIN_DRV_4_8: - supported_strength = strength_4_8; + switch (type) { + case UNIPHIER_PIN_DRV_1BIT: + supported_strength = strength_1bit; + reg = UNIPHIER_PINCTRL_DRVCTRL_BASE; width = 1; break; - case UNIPHIER_PIN_DRV_8_12_16_20: - supported_strength = strength_8_12_16_20; + case UNIPHIER_PIN_DRV_2BIT: + supported_strength = strength_2bit; + reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE; width = 2; break; - case UNIPHIER_PIN_DRV_FIXED_4: + case UNIPHIER_PIN_DRV_3BIT: + supported_strength = strength_3bit; + reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE; + width = 4; + break; + case UNIPHIER_PIN_DRV_FIXED4: *strength = 4; return 0; - case UNIPHIER_PIN_DRV_FIXED_5: + case UNIPHIER_PIN_DRV_FIXED5: *strength = 5; return 0; - case UNIPHIER_PIN_DRV_FIXED_8: + case UNIPHIER_PIN_DRV_FIXED8: *strength = 8; return 0; default: @@ -204,17 +224,14 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, return -EINVAL; } - drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); + drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); drvctrl *= width; - reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : - UNIPHIER_PINCTRL_DRVCTRL_BASE; - reg += drvctrl / 32 * 4; shift = drvctrl % 32; mask = (1U << width) - 1; - ret = regmap_read(priv->regmap, reg, &val); + ret = regmap_read(priv->regmap, priv->regbase + reg, &val); if (ret) return ret; @@ -224,10 +241,10 @@ static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, } static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, - const struct pinctrl_pin_desc *pin) + const struct pin_desc *desc) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); - unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); + unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data); unsigned int val; int ret; @@ -235,7 +252,8 @@ static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, /* This pin is always input-enabled. */ return 0; - ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val); + ret = regmap_read(priv->regmap, + priv->regbase + UNIPHIER_PINCTRL_IECTRL, &val); if (ret) return ret; @@ -246,7 +264,7 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs) { - const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; + const struct pin_desc *desc = pin_desc_get(pctldev, pin); enum pin_config_param param = pinconf_to_config_param(*configs); bool has_arg = false; u16 arg; @@ -256,14 +274,14 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: - ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param); + ret = uniphier_conf_pin_bias_get(pctldev, desc, param); break; case PIN_CONFIG_DRIVE_STRENGTH: - ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg); + ret = uniphier_conf_pin_drive_get(pctldev, desc, &arg); has_arg = true; break; case PIN_CONFIG_INPUT_ENABLE: - ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc); + ret = uniphier_conf_pin_input_enable_get(pctldev, desc); break; default: /* unsupported parameter */ @@ -278,13 +296,12 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, } static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, - const struct pinctrl_pin_desc *pin, - enum pin_config_param param, - u16 arg) + const struct pin_desc *desc, + enum pin_config_param param, u16 arg) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); enum uniphier_pin_pull_dir pull_dir = - uniphier_pin_get_pull_dir(pin->drv_data); + uniphier_pin_get_pull_dir(desc->drv_data); unsigned int pupdctrl, reg, shift; unsigned int val = 1; @@ -295,8 +312,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { dev_err(pctldev->dev, - "can not disable pull register for pin %u (%s)\n", - pin->number, pin->name); + "can not disable pull register for pin %s\n", + desc->name); return -EINVAL; } val = 0; @@ -306,8 +323,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, return 0; if (pull_dir != UNIPHIER_PIN_PULL_UP) { dev_err(pctldev->dev, - "pull-up is unsupported for pin %u (%s)\n", - pin->number, pin->name); + "pull-up is unsupported for pin %s\n", + desc->name); return -EINVAL; } if (arg == 0) { @@ -320,8 +337,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, return 0; if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { dev_err(pctldev->dev, - "pull-down is unsupported for pin %u (%s)\n", - pin->number, pin->name); + "pull-down is unsupported for pin %s\n", + desc->name); return -EINVAL; } if (arg == 0) { @@ -332,8 +349,8 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: if (pull_dir == UNIPHIER_PIN_PULL_NONE) { dev_err(pctldev->dev, - "pull-up/down is unsupported for pin %u (%s)\n", - pin->number, pin->name); + "pull-up/down is unsupported for pin %s\n", + desc->name); return -EINVAL; } @@ -344,39 +361,48 @@ static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, BUG(); } - pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); + pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data); reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; shift = pupdctrl % 32; - return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift); + return regmap_update_bits(priv->regmap, priv->regbase + reg, + 1 << shift, val << shift); } static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, - const struct pinctrl_pin_desc *pin, + const struct pin_desc *desc, u16 strength) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); - enum uniphier_pin_drv_str drv_str = - uniphier_pin_get_drv_str(pin->drv_data); - const unsigned int strength_4_8[] = {4, 8, -1}; - const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1}; + enum uniphier_pin_drv_type type = + uniphier_pin_get_drv_type(desc->drv_data); + const unsigned int strength_1bit[] = {4, 8, -1}; + const unsigned int strength_2bit[] = {8, 12, 16, 20, -1}; + const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16, -1}; const unsigned int *supported_strength; unsigned int drvctrl, reg, shift, mask, width, val; - switch (drv_str) { - case UNIPHIER_PIN_DRV_4_8: - supported_strength = strength_4_8; + switch (type) { + case UNIPHIER_PIN_DRV_1BIT: + supported_strength = strength_1bit; + reg = UNIPHIER_PINCTRL_DRVCTRL_BASE; width = 1; break; - case UNIPHIER_PIN_DRV_8_12_16_20: - supported_strength = strength_8_12_16_20; + case UNIPHIER_PIN_DRV_2BIT: + supported_strength = strength_2bit; + reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE; width = 2; break; + case UNIPHIER_PIN_DRV_3BIT: + supported_strength = strength_3bit; + reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE; + width = 4; + break; default: dev_err(pctldev->dev, - "cannot change drive strength for pin %u (%s)\n", - pin->number, pin->name); + "cannot change drive strength for pin %s\n", + desc->name); return -EINVAL; } @@ -387,49 +413,48 @@ static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, if (val == 0) { dev_err(pctldev->dev, - "unsupported drive strength %u mA for pin %u (%s)\n", - strength, pin->number, pin->name); + "unsupported drive strength %u mA for pin %s\n", + strength, desc->name); return -EINVAL; } val--; - drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); + drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); drvctrl *= width; - reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : - UNIPHIER_PINCTRL_DRVCTRL_BASE; - reg += drvctrl / 32 * 4; shift = drvctrl % 32; mask = (1U << width) - 1; - return regmap_update_bits(priv->regmap, reg, + return regmap_update_bits(priv->regmap, priv->regbase + reg, mask << shift, val << shift); } static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, - const struct pinctrl_pin_desc *pin, + const struct pin_desc *desc, u16 enable) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); - unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); + unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data); + unsigned int reg, mask; - if (enable == 0) { - /* - * Multiple pins share one input enable, so per-pin disabling - * is impossible. - */ - dev_err(pctldev->dev, "unable to disable input\n"); + /* + * Multiple pins share one input enable, per-pin disabling is + * impossible. + */ + if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) && + !enable) return -EINVAL; - } + /* UNIPHIER_PIN_IECTRL_NONE means the pin is always input-enabled */ if (iectrl == UNIPHIER_PIN_IECTRL_NONE) - /* This pin is always input-enabled. nothing to do. */ - return 0; + return enable ? 0 : -EINVAL; + + reg = priv->regbase + UNIPHIER_PINCTRL_IECTRL + iectrl / 32 * 4; + mask = BIT(iectrl % 32); - return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL, - BIT(iectrl), BIT(iectrl)); + return regmap_update_bits(priv->regmap, reg, mask, enable ? mask : 0); } static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, @@ -437,7 +462,7 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, unsigned long *configs, unsigned num_configs) { - const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; + const struct pin_desc *desc = pin_desc_get(pctldev, pin); int i, ret; for (i = 0; i < num_configs; i++) { @@ -450,16 +475,15 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: - ret = uniphier_conf_pin_bias_set(pctldev, pin_desc, + ret = uniphier_conf_pin_bias_set(pctldev, desc, param, arg); break; case PIN_CONFIG_DRIVE_STRENGTH: - ret = uniphier_conf_pin_drive_set(pctldev, pin_desc, - arg); + ret = uniphier_conf_pin_drive_set(pctldev, desc, arg); break; case PIN_CONFIG_INPUT_ENABLE: - ret = uniphier_conf_pin_input_enable(pctldev, - pin_desc, arg); + ret = uniphier_conf_pin_input_enable(pctldev, desc, + arg); break; default: dev_err(pctldev->dev, @@ -531,20 +555,42 @@ static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, } static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, - unsigned muxval) + int muxval) { struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); - unsigned mux_bits = priv->socdata->mux_bits; - unsigned reg_stride = priv->socdata->reg_stride; - unsigned reg, reg_end, shift, mask; + unsigned int mux_bits, reg_stride, reg, reg_end, shift, mask; + bool load_pinctrl; int ret; /* some pins need input-enabling */ ret = uniphier_conf_pin_input_enable(pctldev, - &pctldev->desc->pins[pin], 1); + pin_desc_get(pctldev, pin), 1); if (ret) return ret; + if (muxval < 0) + return 0; /* dedicated pin; nothing to do for pin-mux */ + + if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { + /* + * Mode reg_offset bit_position + * Normal 4 * n shift+3:shift + * Debug 4 * n shift+7:shift+4 + */ + mux_bits = 4; + reg_stride = 8; + load_pinctrl = true; + } else { + /* + * Mode reg_offset bit_position + * Normal 8 * n shift+3:shift + * Debug 8 * n + 4 shift+3:shift + */ + mux_bits = 8; + reg_stride = 4; + load_pinctrl = false; + } + reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; reg_end = reg + reg_stride; shift = pin * mux_bits % 32; @@ -555,16 +601,17 @@ static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, * stored in the offset+4. */ for (; reg < reg_end; reg += 4) { - ret = regmap_update_bits(priv->regmap, reg, + ret = regmap_update_bits(priv->regmap, priv->regbase + reg, mask << shift, muxval << shift); if (ret) return ret; muxval >>= mux_bits; } - if (priv->socdata->load_pinctrl) { + if (load_pinctrl) { ret = regmap_write(priv->regmap, - UNIPHIER_PINCTRL_LOAD_PINMUX, 1); + priv->regbase + UNIPHIER_PINCTRL_LOAD_PINMUX, + 1); if (ret) return ret; } @@ -633,19 +680,16 @@ static const struct pinmux_ops uniphier_pmxops = { }; int uniphier_pinctrl_probe(struct platform_device *pdev, - struct pinctrl_desc *desc, struct uniphier_pinctrl_socdata *socdata) { struct device *dev = &pdev->dev; struct uniphier_pinctrl_priv *priv; + struct device_node *parent; if (!socdata || - !socdata->groups || - !socdata->groups_count || - !socdata->functions || - !socdata->functions_count || - !socdata->mux_bits || - !socdata->reg_stride) { + !socdata->pins || !socdata->npins || + !socdata->groups || !socdata->groups_count || + !socdata->functions || !socdata->functions_count) { dev_err(dev, "pinctrl socdata lacks necessary members\n"); return -EINVAL; } @@ -654,18 +698,36 @@ int uniphier_pinctrl_probe(struct platform_device *pdev, if (!priv) return -ENOMEM; - priv->regmap = syscon_node_to_regmap(dev->of_node); + if (of_device_is_compatible(dev->of_node, "socionext,ph1-ld4-pinctrl") || + of_device_is_compatible(dev->of_node, "socionext,ph1-pro4-pinctrl") || + of_device_is_compatible(dev->of_node, "socionext,ph1-sld8-pinctrl") || + of_device_is_compatible(dev->of_node, "socionext,ph1-pro5-pinctrl") || + of_device_is_compatible(dev->of_node, "socionext,proxstream2-pinctrl") || + of_device_is_compatible(dev->of_node, "socionext,ph1-ld6b-pinctrl")) { + /* old binding */ + priv->regmap = syscon_node_to_regmap(dev->of_node); + } else { + priv->regbase = 0x1000; + parent = of_get_parent(dev->of_node); + priv->regmap = syscon_node_to_regmap(parent); + of_node_put(parent); + } + if (IS_ERR(priv->regmap)) { dev_err(dev, "failed to get regmap\n"); return PTR_ERR(priv->regmap); } priv->socdata = socdata; - desc->pctlops = &uniphier_pctlops; - desc->pmxops = &uniphier_pmxops; - desc->confops = &uniphier_confops; - - priv->pctldev = devm_pinctrl_register(dev, desc, priv); + priv->pctldesc.name = dev->driver->name; + priv->pctldesc.pins = socdata->pins; + priv->pctldesc.npins = socdata->npins; + priv->pctldesc.pctlops = &uniphier_pctlops; + priv->pctldesc.pmxops = &uniphier_pmxops; + priv->pctldesc.confops = &uniphier_confops; + priv->pctldesc.owner = dev->driver->owner; + + priv->pctldev = devm_pinctrl_register(dev, &priv->pctldesc, priv); if (IS_ERR(priv->pctldev)) { dev_err(dev, "failed to register UniPhier pinctrl driver\n"); return PTR_ERR(priv->pctldev); |