summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/renesas/pinctrl-rzg2l.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/renesas/pinctrl-rzg2l.c')
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzg2l.c171
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));