pinctrl: renesas: Updates for v6.9 (take two)

- Add support for the R-Car V4M (R8A779H0) SoC,
   - Add support for suspend/resume on the RZ/G2L family,
   - Miscellaneous fixes and improvements.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQ9qaHoIs/1I4cXmEiKwlD9ZEnxcAUCZdh+5gAKCRCKwlD9ZEnx
 cKiIAP9/dNg+l+cgCuI24EKaIehYnjq54clsWycHBV8i41brPgEAutwuYNMG++Vd
 B/iDXOihVSvOhjpQluQMtoYaUBmOCQc=
 =N37y
 -----END PGP SIGNATURE-----

Merge tag 'renesas-pinctrl-for-v6.9-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into devel

pinctrl: renesas: Updates for v6.9 (take two)

  - Add support for the R-Car V4M (R8A779H0) SoC,
  - Add support for suspend/resume on the RZ/G2L family,
  - Miscellaneous fixes and improvements.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Linus Walleij 2024-02-26 15:28:42 +01:00
commit 4432d416ba
7 changed files with 4440 additions and 32 deletions

View File

@ -46,6 +46,7 @@ properties:
- renesas,pfc-r8a779a0 # R-Car V3U
- renesas,pfc-r8a779f0 # R-Car S4-8
- renesas,pfc-r8a779g0 # R-Car V4H
- renesas,pfc-r8a779h0 # R-Car V4M
- renesas,pfc-sh73a0 # SH-Mobile AG5
reg:

View File

@ -38,6 +38,7 @@ config PINCTRL_RENESAS
select PINCTRL_PFC_R8A779A0 if ARCH_R8A779A0
select PINCTRL_PFC_R8A779F0 if ARCH_R8A779F0
select PINCTRL_PFC_R8A779G0 if ARCH_R8A779G0
select PINCTRL_PFC_R8A779H0 if ARCH_R8A779H0
select PINCTRL_RZG2L if ARCH_RZG2L
select PINCTRL_RZV2M if ARCH_R9A09G011
select PINCTRL_PFC_SH7203 if CPU_SUBTYPE_SH7203
@ -154,6 +155,10 @@ config PINCTRL_PFC_R8A779G0
bool "pin control support for R-Car V4H" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A779H0
bool "pin control support for R-Car V4M" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A7740
bool "pin control support for R-Mobile A1" if COMPILE_TEST
select PINCTRL_SH_PFC_GPIO
@ -187,9 +192,11 @@ config PINCTRL_RZG2L
bool "pin control support for RZ/{G2L,G2UL,V2L}" if COMPILE_TEST
depends on OF
select GPIOLIB
select GPIOLIB_IRQCHIP
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
select GENERIC_PINCONF
select IRQ_DOMAIN_HIERARCHY
help
This selects GPIO and pinctrl driver for Renesas RZ/{G2L,G2UL,V2L}
platforms.

View File

@ -31,6 +31,7 @@ obj-$(CONFIG_PINCTRL_PFC_R8A77995) += pfc-r8a77995.o
obj-$(CONFIG_PINCTRL_PFC_R8A779A0) += pfc-r8a779a0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779F0) += pfc-r8a779f0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779G0) += pfc-r8a779g0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779H0) += pfc-r8a779h0.o
obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o
obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o
obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o

View File

@ -638,6 +638,12 @@ static const struct of_device_id sh_pfc_of_table[] = {
.data = &r8a779g0_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A779H0
{
.compatible = "renesas,pfc-r8a779h0",
.data = &r8a779h0_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_SH73A0
{
.compatible = "renesas,pfc-sh73a0",
@ -731,10 +737,12 @@ static int sh_pfc_resume_noirq(struct device *dev)
sh_pfc_walk_regs(pfc, sh_pfc_restore_reg);
return 0;
}
#define pm_psci_sleep_ptr(_ptr) pm_sleep_ptr(_ptr)
#else
static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; }
static int sh_pfc_suspend_noirq(struct device *dev) { return 0; }
static int sh_pfc_resume_noirq(struct device *dev) { return 0; }
#define pm_psci_sleep_ptr(_ptr) PTR_IF(false, (_ptr))
#endif /* CONFIG_ARM_PSCI_FW */
static DEFINE_NOIRQ_DEV_PM_OPS(sh_pfc_pm, sh_pfc_suspend_noirq, sh_pfc_resume_noirq);
@ -1417,7 +1425,7 @@ static struct platform_driver sh_pfc_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(sh_pfc_of_table),
.pm = pm_sleep_ptr(&sh_pfc_pm),
.pm = pm_psci_sleep_ptr(&sh_pfc_pm),
},
};

File diff suppressed because it is too large Load Diff

View File

@ -149,6 +149,33 @@
#define RZG2L_TINT_IRQ_START_INDEX 9
#define RZG2L_PACK_HWIRQ(t, i) (((t) << 16) | (i))
/* Read/write 8 bits register */
#define RZG2L_PCTRL_REG_ACCESS8(_read, _addr, _val) \
do { \
if (_read) \
_val = readb(_addr); \
else \
writeb(_val, _addr); \
} while (0)
/* Read/write 16 bits register */
#define RZG2L_PCTRL_REG_ACCESS16(_read, _addr, _val) \
do { \
if (_read) \
_val = readw(_addr); \
else \
writew(_val, _addr); \
} while (0)
/* Read/write 32 bits register */
#define RZG2L_PCTRL_REG_ACCESS32(_read, _addr, _val) \
do { \
if (_read) \
_val = readl(_addr); \
else \
writel(_val, _addr); \
} while (0)
/**
* struct rzg2l_register_offsets - specific register offsets
* @pwpr: PWPR register offset
@ -241,6 +268,32 @@ struct rzg2l_pinctrl_pin_settings {
u16 drive_strength_ua;
};
/**
* struct rzg2l_pinctrl_reg_cache - register cache structure (to be used in suspend/resume)
* @p: P registers cache
* @pm: PM registers cache
* @pmc: PMC registers cache
* @pfc: PFC registers cache
* @iolh: IOLH registers cache
* @ien: IEN registers cache
* @sd_ch: SD_CH registers cache
* @eth_poc: ET_POC registers cache
* @eth_mode: ETH_MODE register cache
* @qspi: QSPI registers cache
*/
struct rzg2l_pinctrl_reg_cache {
u8 *p;
u16 *pm;
u8 *pmc;
u32 *pfc;
u32 *iolh[2];
u32 *ien[2];
u8 sd_ch[2];
u8 eth_poc[2];
u8 eth_mode;
u8 qspi;
};
struct rzg2l_pinctrl {
struct pinctrl_dev *pctl;
struct pinctrl_desc desc;
@ -250,6 +303,8 @@ struct rzg2l_pinctrl {
void __iomem *base;
struct device *dev;
struct clk *clk;
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range;
DECLARE_BITMAP(tint_slot, RZG2L_TINT_MAX_INTERRUPT);
@ -260,6 +315,9 @@ struct rzg2l_pinctrl {
struct mutex mutex; /* serialize adding groups and functions */
struct rzg2l_pinctrl_pin_settings *settings;
struct rzg2l_pinctrl_reg_cache *cache;
struct rzg2l_pinctrl_reg_cache *dedicated_cache;
atomic_t wakeup_path;
};
static const u16 available_ps[] = { 1800, 2500, 3300 };
@ -1809,11 +1867,9 @@ static int rzg2l_gpio_get_gpioint(unsigned int virq, struct rzg2l_pinctrl *pctrl
return gpioint;
}
static void rzg2l_gpio_irq_disable(struct irq_data *d)
static void rzg2l_gpio_irq_endisable(struct rzg2l_pinctrl *pctrl,
unsigned int hwirq, bool enable)
{
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);
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);
@ -1821,8 +1877,6 @@ static void rzg2l_gpio_irq_disable(struct irq_data *d)
unsigned long flags;
void __iomem *addr;
irq_chip_disable_parent(d);
addr = pctrl->base + ISEL(off);
if (bit >= 4) {
bit -= 4;
@ -1830,36 +1884,28 @@ static void rzg2l_gpio_irq_disable(struct irq_data *d)
}
spin_lock_irqsave(&pctrl->lock, flags);
writel(readl(addr) & ~BIT(bit * 8), addr);
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_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
unsigned int hwirq = irqd_to_hwirq(d);
irq_chip_disable_parent(d);
gpiochip_disable_irq(gc, hwirq);
}
static void rzg2l_gpio_irq_enable(struct irq_data *d)
{
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);
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;
gpiochip_enable_irq(gc, hwirq);
addr = pctrl->base + ISEL(off);
if (bit >= 4) {
bit -= 4;
addr += 4;
}
spin_lock_irqsave(&pctrl->lock, flags);
writel(readl(addr) | BIT(bit * 8), addr);
spin_unlock_irqrestore(&pctrl->lock, flags);
irq_chip_enable_parent(d);
}
@ -1880,6 +1926,28 @@ static void rzg2l_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
seq_printf(p, dev_name(gc->parent));
}
static int rzg2l_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip);
int ret;
/* It should not happen. */
if (!data->parent_data)
return -EOPNOTSUPP;
ret = irq_chip_set_wake_parent(data, on);
if (ret)
return ret;
if (on)
atomic_inc(&pctrl->wakeup_path);
else
atomic_dec(&pctrl->wakeup_path);
return 0;
}
static const struct irq_chip rzg2l_gpio_irqchip = {
.name = "rzg2l-gpio",
.irq_disable = rzg2l_gpio_irq_disable,
@ -1890,10 +1958,31 @@ static const struct irq_chip rzg2l_gpio_irqchip = {
.irq_eoi = rzg2l_gpio_irqc_eoi,
.irq_print_chip = rzg2l_gpio_irq_print_chip,
.irq_set_affinity = irq_chip_set_affinity_parent,
.irq_set_wake = rzg2l_gpio_irq_set_wake,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int rzg2l_gpio_interrupt_input_mode(struct gpio_chip *chip, unsigned int offset)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
u64 *pin_data = pin_desc->drv_data;
u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
u8 reg8;
int ret;
reg8 = readb(pctrl->base + PMC(off));
if (reg8 & BIT(bit)) {
ret = rzg2l_gpio_request(chip, offset);
if (ret)
return ret;
}
return rzg2l_gpio_direction_input(chip, offset);
}
static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
unsigned int child,
unsigned int child_type,
@ -1903,16 +1992,25 @@ static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned long flags;
int gpioint, irq;
int ret;
gpioint = rzg2l_gpio_get_gpioint(child, pctrl);
if (gpioint < 0)
return gpioint;
ret = rzg2l_gpio_interrupt_input_mode(gc, child);
if (ret)
return ret;
spin_lock_irqsave(&pctrl->bitmap_lock, flags);
irq = bitmap_find_free_region(pctrl->tint_slot, RZG2L_TINT_MAX_INTERRUPT, get_order(1));
spin_unlock_irqrestore(&pctrl->bitmap_lock, flags);
if (irq < 0)
return -ENOSPC;
if (irq < 0) {
ret = -ENOSPC;
goto err;
}
rzg2l_gpio_irq_endisable(pctrl, child, true);
pctrl->hwirq[irq] = child;
irq += RZG2L_TINT_IRQ_START_INDEX;
@ -1920,6 +2018,10 @@ static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
*parent_type = IRQ_TYPE_LEVEL_HIGH;
*parent = RZG2L_PACK_HWIRQ(gpioint, irq);
return 0;
err:
rzg2l_gpio_free(gc, child);
return ret;
}
static int rzg2l_gpio_populate_parent_fwspec(struct gpio_chip *chip,
@ -1937,6 +2039,35 @@ static int rzg2l_gpio_populate_parent_fwspec(struct gpio_chip *chip,
return 0;
}
static void rzg2l_gpio_irq_restore(struct rzg2l_pinctrl *pctrl)
{
struct irq_domain *domain = pctrl->gpio_chip.irq.domain;
for (unsigned int i = 0; i < RZG2L_TINT_MAX_INTERRUPT; i++) {
struct irq_data *data;
unsigned int virq;
if (!pctrl->hwirq[i])
continue;
virq = irq_find_mapping(domain, pctrl->hwirq[i]);
if (!virq) {
dev_crit(pctrl->dev, "Failed to find IRQ mapping for hwirq %u\n",
pctrl->hwirq[i]);
continue;
}
data = irq_domain_get_irq_data(domain, virq);
if (!data) {
dev_crit(pctrl->dev, "Failed to get IRQ data for virq=%u\n", virq);
continue;
}
if (!irqd_irq_disabled(data))
rzg2l_gpio_irq_enable(data);
}
}
static void rzg2l_gpio_irq_domain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{
@ -1952,6 +2083,8 @@ static void rzg2l_gpio_irq_domain_free(struct irq_domain *domain, unsigned int v
for (i = 0; i < RZG2L_TINT_MAX_INTERRUPT; i++) {
if (pctrl->hwirq[i] == hwirq) {
rzg2l_gpio_irq_endisable(pctrl, hwirq, false);
rzg2l_gpio_free(gc, hwirq);
spin_lock_irqsave(&pctrl->bitmap_lock, flags);
bitmap_release_region(pctrl->tint_slot, i, get_order(1));
spin_unlock_irqrestore(&pctrl->bitmap_lock, flags);
@ -1985,6 +2118,68 @@ static void rzg2l_init_irq_valid_mask(struct gpio_chip *gc,
}
}
static int rzg2l_pinctrl_reg_cache_alloc(struct rzg2l_pinctrl *pctrl)
{
u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT;
struct rzg2l_pinctrl_reg_cache *cache, *dedicated_cache;
cache = devm_kzalloc(pctrl->dev, sizeof(*cache), GFP_KERNEL);
if (!cache)
return -ENOMEM;
dedicated_cache = devm_kzalloc(pctrl->dev, sizeof(*dedicated_cache), GFP_KERNEL);
if (!dedicated_cache)
return -ENOMEM;
cache->p = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->p), GFP_KERNEL);
if (!cache->p)
return -ENOMEM;
cache->pm = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->pm), GFP_KERNEL);
if (!cache->pm)
return -ENOMEM;
cache->pmc = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->pmc), GFP_KERNEL);
if (!cache->pmc)
return -ENOMEM;
cache->pfc = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->pfc), GFP_KERNEL);
if (!cache->pfc)
return -ENOMEM;
for (u8 i = 0; i < 2; i++) {
u32 n_dedicated_pins = pctrl->data->n_dedicated_pins;
cache->iolh[i] = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->iolh[i]),
GFP_KERNEL);
if (!cache->iolh[i])
return -ENOMEM;
cache->ien[i] = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->ien[i]),
GFP_KERNEL);
if (!cache->ien[i])
return -ENOMEM;
/* Allocate dedicated cache. */
dedicated_cache->iolh[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins,
sizeof(*dedicated_cache->iolh[i]),
GFP_KERNEL);
if (!dedicated_cache->iolh[i])
return -ENOMEM;
dedicated_cache->ien[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins,
sizeof(*dedicated_cache->ien[i]),
GFP_KERNEL);
if (!dedicated_cache->ien[i])
return -ENOMEM;
}
pctrl->cache = cache;
pctrl->dedicated_cache = dedicated_cache;
return 0;
}
static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl)
{
struct device_node *np = pctrl->dev->of_node;
@ -2125,6 +2320,10 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl)
}
}
ret = rzg2l_pinctrl_reg_cache_alloc(pctrl);
if (ret)
return ret;
ret = devm_pinctrl_register_and_init(pctrl->dev, &pctrl->desc, pctrl,
&pctrl->pctl);
if (ret) {
@ -2150,7 +2349,6 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl)
static int rzg2l_pinctrl_probe(struct platform_device *pdev)
{
struct rzg2l_pinctrl *pctrl;
struct clk *clk;
int ret;
BUILD_BUG_ON(ARRAY_SIZE(r9a07g044_gpio_configs) * RZG2L_PINS_PER_PORT >
@ -2176,14 +2374,16 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
if (IS_ERR(pctrl->base))
return PTR_ERR(pctrl->base);
clk = devm_clk_get_enabled(pctrl->dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(pctrl->dev, PTR_ERR(clk),
pctrl->clk = devm_clk_get_enabled(pctrl->dev, NULL);
if (IS_ERR(pctrl->clk)) {
return dev_err_probe(pctrl->dev, PTR_ERR(pctrl->clk),
"failed to enable GPIO clk\n");
}
spin_lock_init(&pctrl->lock);
spin_lock_init(&pctrl->bitmap_lock);
mutex_init(&pctrl->mutex);
atomic_set(&pctrl->wakeup_path, 0);
platform_set_drvdata(pdev, pctrl);
@ -2195,6 +2395,224 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
return 0;
}
static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspend)
{
u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT;
struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache;
for (u32 port = 0; port < nports; port++) {
bool has_iolh, has_ien;
u32 off, caps;
u8 pincnt;
u64 cfg;
cfg = pctrl->data->port_pin_configs[port];
off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
pincnt = hweight8(FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg));
caps = FIELD_GET(PIN_CFG_MASK, cfg);
has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C));
has_ien = !!(caps & PIN_CFG_IEN);
if (suspend)
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PFC(off), cache->pfc[port]);
/*
* 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 (has_iolh) {
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IOLH(off),
cache->iolh[0][port]);
if (pincnt >= 4) {
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IOLH(off) + 4,
cache->iolh[1][port]);
}
}
RZG2L_PCTRL_REG_ACCESS16(suspend, pctrl->base + PM(off), cache->pm[port]);
RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + P(off), cache->p[port]);
if (has_ien) {
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IEN(off),
cache->ien[0][port]);
if (pincnt >= 4) {
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IEN(off) + 4,
cache->ien[1][port]);
}
}
}
}
static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, bool suspend)
{
struct rzg2l_pinctrl_reg_cache *cache = pctrl->dedicated_cache;
/*
* Make sure entries in pctrl->data->n_dedicated_pins[] having the same
* port offset are close together.
*/
for (u32 i = 0, caps = 0; i < pctrl->data->n_dedicated_pins; i++) {
bool has_iolh, has_ien;
u32 off, next_off = 0;
u64 cfg, next_cfg;
u8 pincnt;
cfg = pctrl->data->dedicated_pins[i].config;
off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
if (i + 1 < pctrl->data->n_dedicated_pins) {
next_cfg = pctrl->data->dedicated_pins[i + 1].config;
next_off = RZG2L_PIN_CFG_TO_PORT_OFFSET(next_cfg);
}
if (off == next_off) {
/* Gather caps of all port pins. */
caps |= FIELD_GET(PIN_CFG_MASK, cfg);
continue;
}
/* And apply them in a single shot. */
has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C));
has_ien = !!(caps & PIN_CFG_IEN);
pincnt = hweight8(FIELD_GET(RZG2L_SINGLE_PIN_BITS_MASK, cfg));
if (has_iolh) {
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IOLH(off),
cache->iolh[0][i]);
}
if (has_ien) {
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IEN(off),
cache->ien[0][i]);
}
if (pincnt >= 4) {
if (has_iolh) {
RZG2L_PCTRL_REG_ACCESS32(suspend,
pctrl->base + IOLH(off) + 4,
cache->iolh[1][i]);
}
if (has_ien) {
RZG2L_PCTRL_REG_ACCESS32(suspend,
pctrl->base + IEN(off) + 4,
cache->ien[1][i]);
}
}
caps = 0;
}
}
static void rzg2l_pinctrl_pm_setup_pfc(struct rzg2l_pinctrl *pctrl)
{
u32 nports = pctrl->data->n_port_pins / RZG2L_PINS_PER_PORT;
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
/* Set the PWPR register to allow PFC register to write. */
writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */
writel(PWPR_PFCWE, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=1 */
/* Restore port registers. */
for (u32 port = 0; port < nports; port++) {
unsigned long pinmap;
u8 pmc = 0, max_pin;
u32 off, pfc = 0;
u64 cfg;
u16 pm;
u8 pin;
cfg = pctrl->data->port_pin_configs[port];
off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
pinmap = FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg);
max_pin = fls(pinmap);
pm = readw(pctrl->base + PM(off));
for_each_set_bit(pin, &pinmap, max_pin) {
struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache;
/* Nothing to do if PFC was not configured before. */
if (!(cache->pmc[port] & BIT(pin)))
continue;
/* Set pin to 'Non-use (Hi-Z input protection)' */
pm &= ~(PM_MASK << (pin * 2));
writew(pm, pctrl->base + PM(off));
/* Temporarily switch to GPIO mode with PMC register */
pmc &= ~BIT(pin);
writeb(pmc, pctrl->base + PMC(off));
/* Select Pin function mode. */
pfc &= ~(PFC_MASK << (pin * 4));
pfc |= (cache->pfc[port] & (PFC_MASK << (pin * 4)));
writel(pfc, pctrl->base + PFC(off));
/* Switch to Peripheral pin function. */
pmc |= BIT(pin);
writeb(pmc, pctrl->base + PMC(off));
}
}
/* Set the PWPR register to be write-protected. */
writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */
writel(PWPR_B0WI, pctrl->base + regs->pwpr); /* B0WI=1, PFCWE=0 */
}
static int rzg2l_pinctrl_suspend_noirq(struct device *dev)
{
struct rzg2l_pinctrl *pctrl = dev_get_drvdata(dev);
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache;
rzg2l_pinctrl_pm_setup_regs(pctrl, true);
rzg2l_pinctrl_pm_setup_dedicated_regs(pctrl, true);
for (u8 i = 0; i < 2; i++) {
cache->sd_ch[i] = readb(pctrl->base + SD_CH(regs->sd_ch, i));
cache->eth_poc[i] = readb(pctrl->base + ETH_POC(regs->eth_poc, i));
}
cache->qspi = readb(pctrl->base + QSPI);
cache->eth_mode = readb(pctrl->base + ETH_MODE);
if (!atomic_read(&pctrl->wakeup_path))
clk_disable_unprepare(pctrl->clk);
else
device_set_wakeup_path(dev);
return 0;
}
static int rzg2l_pinctrl_resume_noirq(struct device *dev)
{
struct rzg2l_pinctrl *pctrl = dev_get_drvdata(dev);
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache;
int ret;
if (!atomic_read(&pctrl->wakeup_path)) {
ret = clk_prepare_enable(pctrl->clk);
if (ret)
return ret;
}
writeb(cache->qspi, pctrl->base + QSPI);
writeb(cache->eth_mode, pctrl->base + ETH_MODE);
for (u8 i = 0; i < 2; i++) {
writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i));
writeb(cache->eth_poc[i], pctrl->base + ETH_POC(regs->eth_poc, i));
}
rzg2l_pinctrl_pm_setup_pfc(pctrl);
rzg2l_pinctrl_pm_setup_regs(pctrl, false);
rzg2l_pinctrl_pm_setup_dedicated_regs(pctrl, false);
rzg2l_gpio_irq_restore(pctrl);
return 0;
}
static const struct rzg2l_hwcfg rzg2l_hwcfg = {
.regs = {
.pwpr = 0x3014,
@ -2291,10 +2709,15 @@ static const struct of_device_id rzg2l_pinctrl_of_table[] = {
{ /* sentinel */ }
};
static const struct dev_pm_ops rzg2l_pinctrl_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(rzg2l_pinctrl_suspend_noirq, rzg2l_pinctrl_resume_noirq)
};
static struct platform_driver rzg2l_pinctrl_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(rzg2l_pinctrl_of_table),
.pm = pm_sleep_ptr(&rzg2l_pinctrl_pm_ops),
},
.probe = rzg2l_pinctrl_probe,
};

View File

@ -322,6 +322,7 @@ extern const struct sh_pfc_soc_info r8a77995_pinmux_info;
extern const struct sh_pfc_soc_info r8a779a0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779f0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779g0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779h0_pinmux_info;
extern const struct sh_pfc_soc_info sh7203_pinmux_info;
extern const struct sh_pfc_soc_info sh7264_pinmux_info;
extern const struct sh_pfc_soc_info sh7269_pinmux_info;