diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 15:40:03 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 15:40:03 +0900 |
commit | 8a5dc585d50015af9c079ae2d182dc4c1cd22914 (patch) | |
tree | 7544d20587e589bf20c526a5f83205e113cc3e58 /drivers/pinctrl/pinctrl-rockchip.c | |
parent | eeab517b68beb9e044e869bee18e3bdfa60e5aca (diff) | |
parent | 9da8312048edcf246ac1d7ab6aa0293f252de559 (diff) |
Merge tag 'pinctrl-for-v3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control updates from Linus Walleij:
"Main pin control pull request for the v3.13 cycle.
The changes hitting arch/blackfin are ACKed by the Blackfin
maintainer, and the device tree bindings are ACKed to the extent
possible by someone from the device tree maintainers group.
- Blackfin ADI pin control driver, we move yet another architecture
under this subsystem umbrella.
- Incremental updates to the Renesas Super-H PFC pin control driver.
New subdriver for the r8a7791 SoC.
- Non-linear GPIO ranges from the gpiolib side of things, this
enabled simplified device tree bindings by referring entire groups
of pins on some pin controller to act as back-end for a certain
GPIO-chip driver.
- Add the Abilis TB10x pin control driver used on the ARC
architecture. Also the corresponding GPIO driver is merged through
this tree, so the ARC has full support for pins and GPIOs after
this.
- Subdrivers for Freescale i.MX1, i.MX27 and i.MX50 pin controller
instances. The i.MX1 and i.MX27 is an entirely new family
(silicon) of controllers whereas i.MX50 is a variant of the
previous supported controller.
- Then the usual slew of fixes, cleanups and incremental updates"
The ARC DT changes are apparently still pending, that hopefully gets
sorted out in a timely manner.
* tag 'pinctrl-for-v3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (48 commits)
pinctrl: imx50: add pinctrl support code for the IMX50 SoC
pinctrl: at91: copy define to driver
pinctrl: remove minor dead code
pinctrl: imx: fix using pin->input_val wrongly
pinctrl: imx1: fix return value check in imx1_pinctrl_core_probe()
gpio: tb10x: fix return value check in tb10x_gpio_probe()
gpio: tb10x: use module_platform_driver to simplify the code
pinctrl: imx27: imx27 pincontrol driver
pinctrl: imx1 core driver
pinctrl: sh-pfc: r8a7791 PFC support
sh-pfc: r8a7778: Add CAN pin groups
gpio: add TB10x GPIO driver
pinctrl: at91: correct a few typos
pinctrl: mvebu: remove redundant of_match_ptr
pinctrl: tb10x: use module_platform_driver to simplify the code
pinctrl: tb10x: fix the error handling in tb10x_pinctrl_probe()
pinctrl: add documentation for pinctrl_get_group_pins()
pinctrl: rockchip: emulate both edge triggered interrupts
pinctrl: rockchip: add rk3188 specifics
pinctrl: rockchip: remove redundant check
...
Diffstat (limited to 'drivers/pinctrl/pinctrl-rockchip.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-rockchip.c | 292 |
1 files changed, 229 insertions, 63 deletions
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index e0718b7c4abc..e939c28cbf1f 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -56,8 +56,20 @@ #define GPIO_EXT_PORT 0x50 #define GPIO_LS_SYNC 0x60 +enum rockchip_pinctrl_type { + RK2928, + RK3066B, + RK3188, +}; + +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 @@ -74,12 +86,14 @@ */ struct rockchip_pin_bank { void __iomem *reg_base; + void __iomem *reg_pull; struct clk *clk; int irq; u32 pin_base; u8 nr_pins; char *name; u8 bank_num; + enum rockchip_pin_bank_type bank_type; bool valid; struct device_node *of_node; struct rockchip_pinctrl *drvdata; @@ -87,7 +101,7 @@ struct rockchip_pin_bank { struct gpio_chip gpio_chip; struct pinctrl_gpio_range grange; spinlock_t slock; - + u32 toggle_edge_mode; }; #define PIN_BANK(id, pins, label) \ @@ -98,18 +112,16 @@ struct rockchip_pin_bank { } /** - * @pull_auto: some SoCs don't allow pulls to be specified as up or down, but - * instead decide this automatically based on the pad-type. */ struct rockchip_pin_ctrl { struct rockchip_pin_bank *pin_banks; u32 nr_banks; u32 nr_pins; char *label; + enum rockchip_pinctrl_type type; int mux_offset; - int pull_offset; - bool pull_auto; - int pull_bank_stride; + void (*pull_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, + void __iomem **reg, u8 *bit); }; struct rockchip_pin_config { @@ -148,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; @@ -354,31 +367,92 @@ static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) spin_unlock_irqrestore(&bank->slock, flags); } +#define RK2928_PULL_OFFSET 0x118 +#define RK2928_PULL_PINS_PER_REG 16 +#define RK2928_PULL_BANK_STRIDE 8 + +static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, void __iomem **reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *reg = info->reg_base + RK2928_PULL_OFFSET; + *reg += bank->bank_num * RK2928_PULL_BANK_STRIDE; + *reg += (pin_num / RK2928_PULL_PINS_PER_REG) * 4; + + *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->pull_offset) + if (ctrl->type == RK3066B) return PIN_CONFIG_BIAS_DISABLE; - reg = info->reg_base + ctrl->pull_offset; - - if (ctrl->pull_auto) { - reg += bank->bank_num * ctrl->pull_bank_stride; - reg += (pin_num / 16) * 4; - bit = pin_num % 16; + ctrl->pull_calc_reg(bank, pin_num, ®, &bit); + switch (ctrl->type) { + case RK2928: return !(readl_relaxed(reg) & BIT(bit)) ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT : PIN_CONFIG_BIAS_DISABLE; - } else { - dev_err(info->dev, "pull support for rk31xx not implemented\n"); + case RK3188: + 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"); + return -EINVAL; + }; } static int rockchip_set_pull(struct rockchip_pin_bank *bank, @@ -395,22 +469,13 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, bank->bank_num, pin_num, pull); /* rk3066b does support any pulls */ - if (!ctrl->pull_offset) + if (ctrl->type == RK3066B) return pull ? -EINVAL : 0; - reg = info->reg_base + ctrl->pull_offset; - - if (ctrl->pull_auto) { - if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && - pull != PIN_CONFIG_BIAS_DISABLE) { - dev_err(info->dev, "only PIN_DEFAULT and DISABLE allowed\n"); - return -EINVAL; - } - - reg += bank->bank_num * ctrl->pull_bank_stride; - reg += (pin_num / 16) * 4; - bit = pin_num % 16; + ctrl->pull_calc_reg(bank, pin_num, ®, &bit); + switch (ctrl->type) { + case RK2928: spin_lock_irqsave(&bank->slock, flags); data = BIT(bit + 16); @@ -419,14 +484,38 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, writel(data, reg); spin_unlock_irqrestore(&bank->slock, flags); - } else { - if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) { - dev_err(info->dev, "pull direction (up/down) needs to be specified\n"); + break; + case RK3188: + 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; } - dev_err(info->dev, "pull support for rk31xx not implemented\n"); - return -EIO; + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); + break; + default: + dev_err(info->dev, "unsupported pinctrl type\n"); + return -EINVAL; } return 0; @@ -556,20 +645,17 @@ static const struct pinmux_ops rockchip_pmx_ops = { static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, enum pin_config_param pull) { - /* rk3066b does support any pulls */ - if (!ctrl->pull_offset) + switch (ctrl->type) { + case RK2928: + return (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT || + pull == PIN_CONFIG_BIAS_DISABLE); + case RK3066B: return pull ? false : true; - - if (ctrl->pull_auto) { - if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && - pull != PIN_CONFIG_BIAS_DISABLE) - return false; - } else { - if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) - return false; + case RK3188: + return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT); } - return true; + return false; } /* set the pin config settings for a specified pin */ @@ -597,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; @@ -635,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; @@ -656,7 +744,11 @@ static const struct pinconf_ops rockchip_pinconf_ops = { .pin_config_set = rockchip_pinconf_set, }; -static const char *gpio_compat = "rockchip,gpio-bank"; +static const struct of_device_id rockchip_bank_match[] = { + { .compatible = "rockchip,gpio-bank" }, + { .compatible = "rockchip,rk3188-gpio-bank0" }, + {}, +}; static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info, struct device_node *np) @@ -664,7 +756,7 @@ static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info, struct device_node *child; for_each_child_of_node(np, child) { - if (of_device_is_compatible(child, gpio_compat)) + if (of_match_node(rockchip_bank_match, child)) continue; info->nfunctions++; @@ -807,8 +899,9 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, i = 0; for_each_child_of_node(np, child) { - if (of_device_is_compatible(child, gpio_compat)) + if (of_match_node(rockchip_bank_match, child)) continue; + ret = rockchip_pinctrl_parse_functions(child, info, i++); if (ret) { dev_err(&pdev->dev, "failed to parse function\n"); @@ -985,7 +1078,9 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_get_chip(irq); struct rockchip_pin_bank *bank = irq_get_handler_data(irq); + u32 polarity = 0, data = 0; u32 pend; + bool edge_changed = false; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); @@ -993,6 +1088,12 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS); + if (bank->toggle_edge_mode) { + polarity = readl_relaxed(bank->reg_base + + GPIO_INT_POLARITY); + data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT); + } + while (pend) { unsigned int virq; @@ -1007,9 +1108,30 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq); + /* + * Triggering IRQ on both rising and falling edge + * needs manual intervention. + */ + if (bank->toggle_edge_mode & BIT(irq)) { + if (data & BIT(irq)) + polarity &= ~BIT(irq); + else + polarity |= BIT(irq); + + edge_changed = true; + } + generic_handle_irq(virq); } + if (bank->toggle_edge_mode && edge_changed) { + /* Interrupt params should only be set with ints disabled */ + data = readl_relaxed(bank->reg_base + GPIO_INTEN); + writel_relaxed(0, bank->reg_base + GPIO_INTEN); + writel(polarity, bank->reg_base + GPIO_INT_POLARITY); + writel(data, bank->reg_base + GPIO_INTEN); + } + chained_irq_exit(chip, desc); } @@ -1022,6 +1144,12 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) u32 level; u32 data; + /* make sure the pin is configured as gpio input */ + rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); + data &= ~mask; + writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + if (type & IRQ_TYPE_EDGE_BOTH) __irq_set_handler_locked(d->irq, handle_edge_irq); else @@ -1033,19 +1161,37 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) polarity = readl_relaxed(gc->reg_base + GPIO_INT_POLARITY); switch (type) { + case IRQ_TYPE_EDGE_BOTH: + bank->toggle_edge_mode |= mask; + level |= mask; + + /* + * Determine gpio state. If 1 next interrupt should be falling + * otherwise rising. + */ + data = readl(bank->reg_base + GPIO_EXT_PORT); + if (data & mask) + polarity &= ~mask; + else + polarity |= mask; + break; case IRQ_TYPE_EDGE_RISING: + bank->toggle_edge_mode &= ~mask; level |= mask; polarity |= mask; break; case IRQ_TYPE_EDGE_FALLING: + bank->toggle_edge_mode &= ~mask; level |= mask; polarity &= ~mask; break; case IRQ_TYPE_LEVEL_HIGH: + bank->toggle_edge_mode &= ~mask; level &= ~mask; polarity |= mask; break; case IRQ_TYPE_LEVEL_LOW: + bank->toggle_edge_mode &= ~mask; level &= ~mask; polarity &= ~mask; break; @@ -1059,12 +1205,6 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) irq_gc_unlock(gc); - /* make sure the pin is configured as gpio input */ - rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); - data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); - data &= ~mask; - writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); - return 0; } @@ -1205,6 +1345,26 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank, if (IS_ERR(bank->reg_base)) return PTR_ERR(bank->reg_base); + /* + * 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); bank->clk = of_clk_get(bank->of_node, 0); @@ -1289,6 +1449,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; @@ -1315,10 +1483,9 @@ static struct rockchip_pin_ctrl rk2928_pin_ctrl = { .pin_banks = rk2928_pin_banks, .nr_banks = ARRAY_SIZE(rk2928_pin_banks), .label = "RK2928-GPIO", + .type = RK2928, .mux_offset = 0xa8, - .pull_offset = 0x118, - .pull_auto = 1, - .pull_bank_stride = 8, + .pull_calc_reg = rk2928_calc_pull_reg_and_bit, }; static struct rockchip_pin_bank rk3066a_pin_banks[] = { @@ -1334,10 +1501,9 @@ static struct rockchip_pin_ctrl rk3066a_pin_ctrl = { .pin_banks = rk3066a_pin_banks, .nr_banks = ARRAY_SIZE(rk3066a_pin_banks), .label = "RK3066a-GPIO", + .type = RK2928, .mux_offset = 0xa8, - .pull_offset = 0x118, - .pull_auto = 1, - .pull_bank_stride = 8, + .pull_calc_reg = rk2928_calc_pull_reg_and_bit, }; static struct rockchip_pin_bank rk3066b_pin_banks[] = { @@ -1351,8 +1517,8 @@ static struct rockchip_pin_ctrl rk3066b_pin_ctrl = { .pin_banks = rk3066b_pin_banks, .nr_banks = ARRAY_SIZE(rk3066b_pin_banks), .label = "RK3066b-GPIO", + .type = RK3066B, .mux_offset = 0x60, - .pull_offset = -EINVAL, }; static struct rockchip_pin_bank rk3188_pin_banks[] = { @@ -1366,9 +1532,9 @@ static struct rockchip_pin_ctrl rk3188_pin_ctrl = { .pin_banks = rk3188_pin_banks, .nr_banks = ARRAY_SIZE(rk3188_pin_banks), .label = "RK3188-GPIO", + .type = RK3188, .mux_offset = 0x68, - .pull_offset = 0x164, - .pull_bank_stride = 16, + .pull_calc_reg = rk3188_calc_pull_reg_and_bit, }; static const struct of_device_id rockchip_pinctrl_dt_match[] = { |