diff options
Diffstat (limited to 'drivers/pinctrl/sunxi/pinctrl-sunxi.c')
-rw-r--r-- | drivers/pinctrl/sunxi/pinctrl-sunxi.c | 85 |
1 files changed, 63 insertions, 22 deletions
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 5d9184d18c16..8dd25caea2cf 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -603,6 +603,45 @@ static const struct pinconf_ops sunxi_pconf_ops = { .pin_config_group_set = sunxi_pconf_group_set, }; +static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, + unsigned pin, + struct regulator *supply) +{ + u32 val, reg; + int uV; + + if (!pctl->desc->has_io_bias_cfg) + return 0; + + uV = regulator_get_voltage(supply); + if (uV < 0) + return uV; + + /* Might be dummy regulator with no voltage set */ + if (uV == 0) + return 0; + + /* Configured value must be equal or greater to actual voltage */ + if (uV <= 1800000) + val = 0x0; /* 1.8V */ + else if (uV <= 2500000) + val = 0x6; /* 2.5V */ + else if (uV <= 2800000) + val = 0x9; /* 2.8V */ + else if (uV <= 3000000) + val = 0xA; /* 3.0V */ + else + val = 0xD; /* 3.3V */ + + pin -= pctl->desc->pin_base; + + reg = readl(pctl->membase + sunxi_grp_config_reg(pin)); + reg &= ~IO_BIAS_MASK; + writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin)); + + return 0; +} + static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); @@ -698,26 +737,24 @@ static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset) { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); unsigned short bank = offset / PINS_PER_BANK; - struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank]; - struct regulator *reg; + unsigned short bank_offset = bank - pctl->desc->pin_base / + PINS_PER_BANK; + struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; + struct regulator *reg = s_reg->regulator; + char supply[16]; int ret; - reg = s_reg->regulator; - if (!reg) { - char supply[16]; - - snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank); - reg = regulator_get(pctl->dev, supply); - if (IS_ERR(reg)) { - dev_err(pctl->dev, "Couldn't get bank P%c regulator\n", - 'A' + bank); - return PTR_ERR(reg); - } - - s_reg->regulator = reg; - refcount_set(&s_reg->refcount, 1); - } else { + if (reg) { refcount_inc(&s_reg->refcount); + return 0; + } + + snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank); + reg = regulator_get(pctl->dev, supply); + if (IS_ERR(reg)) { + dev_err(pctl->dev, "Couldn't get bank P%c regulator\n", + 'A' + bank); + return PTR_ERR(reg); } ret = regulator_enable(reg); @@ -727,13 +764,15 @@ static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset) goto out; } + sunxi_pinctrl_set_io_bias_cfg(pctl, offset, reg); + + s_reg->regulator = reg; + refcount_set(&s_reg->refcount, 1); + return 0; out: - if (refcount_dec_and_test(&s_reg->refcount)) { - regulator_put(s_reg->regulator); - s_reg->regulator = NULL; - } + regulator_put(s_reg->regulator); return ret; } @@ -742,7 +781,9 @@ static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); unsigned short bank = offset / PINS_PER_BANK; - struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank]; + unsigned short bank_offset = bank - pctl->desc->pin_base / + PINS_PER_BANK; + struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; if (!refcount_dec_and_test(&s_reg->refcount)) return 0; |