diff options
author | Heiko Stübner <heiko@sntech.de> | 2013-10-16 01:08:42 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-10-16 15:33:54 +0200 |
commit | 6ca5274d1d1258b0e84bc1a0d67ca160d8658e5a (patch) | |
tree | 5a26bd97f0a5b8a3a55e27288171337629a53d1c /drivers/pinctrl | |
parent | d1358f90e3b63530a5e0cf4ffa7560b359e9d638 (diff) | |
download | blackbird-op-linux-6ca5274d1d1258b0e84bc1a0d67ca160d8658e5a.tar.gz blackbird-op-linux-6ca5274d1d1258b0e84bc1a0d67ca160d8658e5a.zip |
pinctrl: rockchip: add rk3188 specifics
Besides the pull registers sitting in a separate place, the rk3188 also
has the peculiarity that the pull registers of the first bank are split
and the first half is sitting in the register space of the pmu.
Therefore this adds a special bank-type for the first bank, to handle
the two register sources.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/pinctrl-rockchip.c | 119 |
1 files changed, 112 insertions, 7 deletions
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 91027dd19f89..f5e53a723152 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -64,10 +64,12 @@ enum rockchip_pinctrl_type { enum rockchip_pin_bank_type { COMMON_BANK, + RK3188_BANK0, }; /** * @reg_base: register base of the gpio bank + * @reg_pull: optional separate register for additional pull settings * @clk: clock of the gpio bank * @irq: interrupt of the gpio bank * @pin_base: first pin number @@ -84,6 +86,7 @@ enum rockchip_pin_bank_type { */ struct rockchip_pin_bank { void __iomem *reg_base; + void __iomem *reg_pull; struct clk *clk; int irq; u32 pin_base; @@ -157,6 +160,7 @@ struct rockchip_pmx_func { struct rockchip_pinctrl { void __iomem *reg_base; + void __iomem *reg_pull; struct device *dev; struct rockchip_pin_ctrl *ctrl; struct pinctrl_desc pctl; @@ -379,25 +383,71 @@ static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, *bit = pin_num % RK2928_PULL_PINS_PER_REG; }; +#define RK3188_PULL_BITS_PER_PIN 2 +#define RK3188_PULL_PINS_PER_REG 8 +#define RK3188_PULL_BANK_STRIDE 16 + +static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, void __iomem **reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + /* The first 12 pins of the first bank are located elsewhere */ + if (bank->bank_type == RK3188_BANK0 && pin_num < 12) { + *reg = bank->reg_pull + + ((pin_num / RK3188_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3188_PULL_PINS_PER_REG; + *bit *= RK3188_PULL_BITS_PER_PIN; + } else { + *reg = info->reg_pull - 4; + *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE; + *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4); + + /* + * The bits in these registers have an inverse ordering + * with the lowest pin being in bits 15:14 and the highest + * pin in bits 1:0 + */ + *bit = 7 - (pin_num % RK3188_PULL_PINS_PER_REG); + *bit *= RK3188_PULL_BITS_PER_PIN; + } +} + static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; void __iomem *reg; u8 bit; + u32 data; /* rk3066b does support any pulls */ if (ctrl->type == RK3066B) return PIN_CONFIG_BIAS_DISABLE; + ctrl->pull_calc_reg(bank, pin_num, ®, &bit); + switch (ctrl->type) { case RK2928: - ctrl->pull_calc_reg(bank, pin_num, ®, &bit); return !(readl_relaxed(reg) & BIT(bit)) ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT : PIN_CONFIG_BIAS_DISABLE; case RK3188: - dev_err(info->dev, "pull support for rk31xx not implemented\n"); + data = readl_relaxed(reg) >> bit; + data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1; + + switch (data) { + case 0: + return PIN_CONFIG_BIAS_DISABLE; + case 1: + return PIN_CONFIG_BIAS_PULL_UP; + case 2: + return PIN_CONFIG_BIAS_PULL_DOWN; + case 3: + return PIN_CONFIG_BIAS_BUS_HOLD; + } + + dev_err(info->dev, "unknown pull setting\n"); return -EIO; default: dev_err(info->dev, "unsupported pinctrl type\n"); @@ -422,10 +472,10 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, if (ctrl->type == RK3066B) return pull ? -EINVAL : 0; + ctrl->pull_calc_reg(bank, pin_num, ®, &bit); + switch (ctrl->type) { case RK2928: - ctrl->pull_calc_reg(bank, pin_num, ®, &bit); - spin_lock_irqsave(&bank->slock, flags); data = BIT(bit + 16); @@ -436,8 +486,33 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, spin_unlock_irqrestore(&bank->slock, flags); break; case RK3188: - dev_err(info->dev, "pull support for rk31xx not implemented\n"); - return -EIO; + spin_lock_irqsave(&bank->slock, flags); + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16); + + switch (pull) { + case PIN_CONFIG_BIAS_DISABLE: + break; + case PIN_CONFIG_BIAS_PULL_UP: + data |= (1 << bit); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + data |= (2 << bit); + break; + case PIN_CONFIG_BIAS_BUS_HOLD: + data |= (3 << bit); + break; + default: + dev_err(info->dev, "unsupported pull setting %d\n", + pull); + return -EINVAL; + } + + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); + break; default: dev_err(info->dev, "unsupported pinctrl type\n"); return -EINVAL; @@ -608,6 +683,7 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_BUS_HOLD: if (!rockchip_pinconf_pull_valid(info->ctrl, param)) return -ENOTSUPP; @@ -646,6 +722,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_BUS_HOLD: if (!rockchip_pinconf_pull_valid(info->ctrl, param)) return -ENOTSUPP; @@ -669,6 +746,7 @@ static const struct pinconf_ops rockchip_pinconf_ops = { static const struct of_device_id rockchip_bank_match[] = { { .compatible = "rockchip,gpio-bank" }, + { .compatible = "rockchip,rk3188-gpio-bank0" }, {}, }; @@ -1220,7 +1298,25 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank, if (IS_ERR(bank->reg_base)) return PTR_ERR(bank->reg_base); - bank->bank_type = COMMON_BANK; + /* + * special case, where parts of the pull setting-registers are + * part of the PMU register space + */ + if (of_device_is_compatible(bank->of_node, + "rockchip,rk3188-gpio-bank0")) { + bank->bank_type = RK3188_BANK0; + + if (of_address_to_resource(bank->of_node, 1, &res)) { + dev_err(dev, "cannot find IO resource for bank\n"); + return -ENOENT; + } + + bank->reg_pull = devm_ioremap_resource(dev, &res); + if (IS_ERR(bank->reg_pull)) + return PTR_ERR(bank->reg_pull); + } else { + bank->bank_type = COMMON_BANK; + } bank->irq = irq_of_parse_and_map(bank->of_node, 0); @@ -1306,6 +1402,14 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(info->reg_base)) return PTR_ERR(info->reg_base); + /* The RK3188 has its pull registers in a separate place */ + if (ctrl->type == RK3188) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + info->reg_pull = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->reg_base)) + return PTR_ERR(info->reg_base); + } + ret = rockchip_gpiolib_register(pdev, info); if (ret) return ret; @@ -1383,6 +1487,7 @@ static struct rockchip_pin_ctrl rk3188_pin_ctrl = { .label = "RK3188-GPIO", .type = RK3188, .mux_offset = 0x68, + .pull_calc_reg = rk3188_calc_pull_reg_and_bit, }; static const struct of_device_id rockchip_pinctrl_dt_match[] = { |