diff options
Diffstat (limited to 'drivers/pinctrl/renesas/pinctrl-rzg2l.c')
| -rw-r--r-- | drivers/pinctrl/renesas/pinctrl-rzg2l.c | 171 |
1 files changed, 104 insertions, 67 deletions
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index f524af6f586f..863e779dda02 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -359,7 +359,7 @@ struct rzg2l_pinctrl { spinlock_t bitmap_lock; /* protect tint_slot bitmap */ unsigned int hwirq[RZG2L_TINT_MAX_INTERRUPT]; - spinlock_t lock; /* lock read/write registers */ + raw_spinlock_t lock; /* lock read/write registers */ struct mutex mutex; /* serialize adding groups and functions */ struct rzg2l_pinctrl_pin_settings *settings; @@ -541,9 +541,16 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, u8 pin, u8 off, u8 func) { unsigned long flags; - u32 reg; + u32 reg, pfc; - spin_lock_irqsave(&pctrl->lock, flags); + /* Switching to GPIO is not required if reset value is same as func */ + raw_spin_lock_irqsave(&pctrl->lock, flags); + reg = readb(pctrl->base + PMC(off)); + pfc = readl(pctrl->base + PFC(off)); + if ((reg & BIT(pin)) && (((pfc >> (pin * 4)) & PFC_MASK) == func)) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return; + } /* Set pin to 'Non-use (Hi-Z input protection)' */ reg = readw(pctrl->base + PM(off)); @@ -557,9 +564,8 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, writeb(reg & ~BIT(pin), pctrl->base + PMC(off)); /* Select Pin function mode with PFC register */ - reg = readl(pctrl->base + PFC(off)); - reg &= ~(PFC_MASK << (pin * 4)); - writel(reg | (func << (pin * 4)), pctrl->base + PFC(off)); + pfc &= ~(PFC_MASK << (pin * 4)); + writel(pfc | (func << (pin * 4)), pctrl->base + PFC(off)); /* Switch to Peripheral pin function with PMC register */ reg = readb(pctrl->base + PMC(off)); @@ -567,8 +573,8 @@ static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl, pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); - spin_unlock_irqrestore(&pctrl->lock, flags); -}; + raw_spin_unlock_irqrestore(&pctrl->lock, flags); +} static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, @@ -608,7 +614,7 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzg2l_map_add_config(struct pinctrl_map *map, const char *group_or_pin, @@ -882,10 +888,10 @@ static void rzg2l_rmw_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset, addr += 4; } - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg = readl(addr) & ~(mask << (bit * 8)); writel(reg | (val << (bit * 8)), addr); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, u32 caps) @@ -1106,13 +1112,37 @@ static int rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) return !(readb(pctrl->base + pctrl->data->hwcfg->regs.oen) & BIT(bit)); } -static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) +/** + * rzg2l_oen_write_with_pwpr - Write to OEN register with PWPR protection + * @pctrl: pinctrl driver data + * @val: value to write to OEN register + * + * Writes to the OEN register, handling PWPR write protection if required + * by the hardware configuration. Must be called with pctrl->lock held. + */ +static void rzg2l_oen_write_with_pwpr(struct rzg2l_pinctrl *pctrl, u8 val) { const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; u16 oen_offset = pctrl->data->hwcfg->regs.oen; + u8 pwpr; + + if (pctrl->data->hwcfg->oen_pwpr_lock) { + pwpr = readb(pctrl->base + regs->pwpr); + writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); + } + + writeb(val, pctrl->base + oen_offset); + + if (pctrl->data->hwcfg->oen_pwpr_lock) + writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); +} + +static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) +{ + u16 oen_offset = pctrl->data->hwcfg->regs.oen; unsigned long flags; - u8 val, pwpr; int bit; + u8 val; if (!pctrl->data->pin_to_oen_bit) return -EOPNOTSUPP; @@ -1121,20 +1151,15 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe if (bit < 0) return -EINVAL; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); val = readb(pctrl->base + oen_offset); if (oen) val &= ~BIT(bit); else val |= BIT(bit); - if (pctrl->data->hwcfg->oen_pwpr_lock) { - pwpr = readb(pctrl->base + regs->pwpr); - writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); - } - writeb(val, pctrl->base + oen_offset); - if (pctrl->data->hwcfg->oen_pwpr_lock) - writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); + + rzg2l_oen_write_with_pwpr(pctrl, val); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1413,7 +1438,7 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, *config = pinconf_to_config_packed(param, arg); return 0; -}; +} static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, unsigned int _pin, @@ -1613,7 +1638,7 @@ static int rzg2l_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev, } return 0; -}; +} static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, unsigned int group, @@ -1640,7 +1665,7 @@ static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, } return 0; -}; +} static const struct pinctrl_ops rzg2l_pinctrl_pctlops = { .get_groups_count = pinctrl_generic_get_group_count, @@ -1687,14 +1712,14 @@ static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); /* Select GPIO mode in PMC Register */ reg8 = readb(pctrl->base + PMC(off)); reg8 &= ~BIT(bit); pctrl->data->pmc_writeb(pctrl, reg8, PMC(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1709,7 +1734,7 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset, unsigned long flags; u16 reg16; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg16 = readw(pctrl->base + PM(off)); reg16 &= ~(PM_MASK << (bit * 2)); @@ -1717,7 +1742,7 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset, reg16 |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2); writew(reg16, pctrl->base + PM(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) @@ -1761,7 +1786,7 @@ static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset, unsigned long flags; u8 reg8; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg8 = readb(pctrl->base + P(off)); @@ -1770,7 +1795,7 @@ static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset, else writeb(reg8 & ~BIT(bit), pctrl->base + P(off)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -2429,14 +2454,13 @@ static int rzg2l_gpio_get_gpioint(unsigned int virq, struct rzg2l_pinctrl *pctrl return gpioint; } -static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, - unsigned int hwirq, bool enable) +static void __rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, + unsigned int hwirq, bool enable) { const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[hwirq]; u64 *pin_data = pin_desc->drv_data; u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data); u8 bit = RZG2L_PIN_ID_TO_PIN(hwirq); - unsigned long flags; void __iomem *addr; addr = pctrl->base + ISEL(off); @@ -2445,12 +2469,20 @@ static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, addr += 4; } - spin_lock_irqsave(&pctrl->lock, flags); if (enable) writel(readl(addr) | BIT(bit * 8), addr); else writel(readl(addr) & ~BIT(bit * 8), addr); - spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl, + unsigned int hwirq, bool enable) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + __rzg2l_gpio_irq_endisable(pctrl, hwirq, enable); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void rzg2l_gpio_irq_disable(struct irq_data *d) @@ -2462,23 +2494,23 @@ static void rzg2l_gpio_irq_disable(struct irq_data *d) gpiochip_disable_irq(gc, hwirq); } -static void rzg2l_gpio_irq_enable(struct irq_data *d) +static void __rzg2l_gpio_irq_enable(struct irq_data *d, bool lock) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip); unsigned int hwirq = irqd_to_hwirq(d); gpiochip_enable_irq(gc, hwirq); + if (lock) + rzg2l_gpio_irq_endisable(pctrl, hwirq, true); + else + __rzg2l_gpio_irq_endisable(pctrl, hwirq, true); irq_chip_enable_parent(d); } -static int rzg2l_gpio_irq_set_type(struct irq_data *d, unsigned int type) -{ - return irq_chip_set_type_parent(d, type); -} - -static void rzg2l_gpio_irqc_eoi(struct irq_data *d) +static void rzg2l_gpio_irq_enable(struct irq_data *d) { - irq_chip_eoi_parent(d); + __rzg2l_gpio_irq_enable(d, true); } static void rzg2l_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p) @@ -2516,8 +2548,8 @@ static const struct irq_chip rzg2l_gpio_irqchip = { .irq_enable = rzg2l_gpio_irq_enable, .irq_mask = irq_chip_mask_parent, .irq_unmask = irq_chip_unmask_parent, - .irq_set_type = rzg2l_gpio_irq_set_type, - .irq_eoi = rzg2l_gpio_irqc_eoi, + .irq_set_type = irq_chip_set_type_parent, + .irq_eoi = irq_chip_eoi_parent, .irq_print_chip = rzg2l_gpio_irq_print_chip, .irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_wake = rzg2l_gpio_irq_set_wake, @@ -2616,11 +2648,11 @@ static void rzg2l_gpio_irq_restore(struct rzg2l_pinctrl *pctrl) * This has to be atomically executed to protect against a concurrent * interrupt. */ - spin_lock_irqsave(&pctrl->lock, flags); - ret = rzg2l_gpio_irq_set_type(data, irqd_get_trigger_type(data)); + raw_spin_lock_irqsave(&pctrl->lock, flags); + ret = irq_chip_set_type_parent(data, irqd_get_trigger_type(data)); if (!ret && !irqd_irq_disabled(data)) - rzg2l_gpio_irq_enable(data); - spin_unlock_irqrestore(&pctrl->lock, flags); + __rzg2l_gpio_irq_enable(data, false); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); if (ret) dev_crit(pctrl->dev, "Failed to set IRQ type for virq=%u\n", virq); @@ -2950,7 +2982,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev) "failed to enable GPIO clk\n"); } - spin_lock_init(&pctrl->lock); + raw_spin_lock_init(&pctrl->lock); spin_lock_init(&pctrl->bitmap_lock); mutex_init(&pctrl->mutex); atomic_set(&pctrl->wakeup_path, 0); @@ -2993,7 +3025,11 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen * Now cache the registers or set them in the order suggested by * HW manual (section "Operation for GPIO Function"). */ - RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + PMC(off), cache->pmc[port]); + if (suspend) + RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + PMC(off), cache->pmc[port]); + else + pctrl->data->pmc_writeb(pctrl, cache->pmc[port], PMC(off)); + if (has_iolh) { RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IOLH(off), cache->iolh[0][port]); @@ -3093,7 +3129,7 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT; unsigned long flags; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); pctrl->data->pwpr_pfc_lock_unlock(pctrl, false); /* Restore port registers. */ @@ -3113,11 +3149,18 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) pm = readw(pctrl->base + PM(off)); for_each_set_bit(pin, &pinmap, max_pin) { struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache; + u32 pfc_val, pfc_mask; /* Nothing to do if PFC was not configured before. */ if (!(cache->pmc[port] & BIT(pin))) continue; + pfc_val = readl(pctrl->base + PFC(off)); + pfc_mask = PFC_MASK << (pin * 4); + /* Nothing to do if reset value of the pin is same as cached value */ + if ((cache->pfc[port] & pfc_mask) == (pfc_val & pfc_mask)) + continue; + /* Set pin to 'Non-use (Hi-Z input protection)' */ pm &= ~(PM_MASK << (pin * 2)); writew(pm, pctrl->base + PM(off)); @@ -3127,8 +3170,8 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) writeb(pmc, pctrl->base + PMC(off)); /* Select Pin function mode. */ - pfc &= ~(PFC_MASK << (pin * 4)); - pfc |= (cache->pfc[port] & (PFC_MASK << (pin * 4))); + pfc &= ~pfc_mask; + pfc |= (cache->pfc[port] & pfc_mask); writel(pfc, pctrl->base + PFC(off)); /* Switch to Peripheral pin function. */ @@ -3138,7 +3181,7 @@ static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl) } pctrl->data->pwpr_pfc_lock_unlock(pctrl, true); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int rzg2l_pinctrl_suspend_noirq(struct device *dev) @@ -3176,7 +3219,6 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) const struct rzg2l_register_offsets *regs = &hwcfg->regs; struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache; unsigned long flags; - u8 pwpr; int ret; if (!atomic_read(&pctrl->wakeup_path)) { @@ -3186,16 +3228,11 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) } writeb(cache->qspi, pctrl->base + QSPI); - if (pctrl->data->hwcfg->oen_pwpr_lock) { - spin_lock_irqsave(&pctrl->lock, flags); - pwpr = readb(pctrl->base + regs->pwpr); - writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); - } - writeb(cache->oen, pctrl->base + pctrl->data->hwcfg->regs.oen); - if (pctrl->data->hwcfg->oen_pwpr_lock) { - writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); - } + + raw_spin_lock_irqsave(&pctrl->lock, flags); + rzg2l_oen_write_with_pwpr(pctrl, cache->oen); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + for (u8 i = 0; i < 2; i++) { if (regs->sd_ch) writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i)); |
