Skip to content

Commit cc43eea

Browse files
committed
Merge tag 'samsung-pinctrl-6.17' of https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung into devel
Samsung pinctrl drivers changes for v6.17 Add support for programming wake up for Google GS101 SoC pin controllers, so the SoC can be properly woken up from low power states. Signed-off-by: Linus Walleij <[email protected]>
2 parents 2427d69 + 683d532 commit cc43eea

File tree

4 files changed

+98
-16
lines changed

4 files changed

+98
-16
lines changed

drivers/pinctrl/samsung/pinctrl-exynos-arm64.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,7 @@ static const struct samsung_pin_bank_data exynosautov920_pin_banks7[] = {
14051405
EXYNOSV920_PIN_BANK_EINTG(8, 0x8000, "gpg1", 0x18, 0x24, 0x28),
14061406
};
14071407

1408-
static const struct samsung_retention_data exynosautov920_retention_data __initconst = {
1408+
static const struct samsung_retention_data no_retention_data __initconst = {
14091409
.regs = NULL,
14101410
.nr_regs = 0,
14111411
.value = 0,
@@ -1421,7 +1421,7 @@ static const struct samsung_pin_ctrl exynosautov920_pin_ctrl[] = {
14211421
.eint_wkup_init = exynos_eint_wkup_init,
14221422
.suspend = exynosautov920_pinctrl_suspend,
14231423
.resume = exynosautov920_pinctrl_resume,
1424-
.retention_data = &exynosautov920_retention_data,
1424+
.retention_data = &no_retention_data,
14251425
}, {
14261426
/* pin-controller instance 1 AUD data */
14271427
.pin_banks = exynosautov920_pin_banks1,
@@ -1764,13 +1764,15 @@ static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
17641764
.eint_wkup_init = exynos_eint_wkup_init,
17651765
.suspend = gs101_pinctrl_suspend,
17661766
.resume = gs101_pinctrl_resume,
1767+
.retention_data = &no_retention_data,
17671768
}, {
17681769
/* pin banks of gs101 pin-controller (FAR_ALIVE) */
17691770
.pin_banks = gs101_pin_far_alive,
17701771
.nr_banks = ARRAY_SIZE(gs101_pin_far_alive),
17711772
.eint_wkup_init = exynos_eint_wkup_init,
17721773
.suspend = gs101_pinctrl_suspend,
17731774
.resume = gs101_pinctrl_resume,
1775+
.retention_data = &no_retention_data,
17741776
}, {
17751777
/* pin banks of gs101 pin-controller (GSACORE) */
17761778
.pin_banks = gs101_pin_gsacore,

drivers/pinctrl/samsung/pinctrl-exynos.c

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,24 @@
3232
#include "pinctrl-samsung.h"
3333
#include "pinctrl-exynos.h"
3434

35+
#define MAX_WAKEUP_REG 3
36+
3537
struct exynos_irq_chip {
3638
struct irq_chip chip;
3739

3840
u32 eint_con;
3941
u32 eint_mask;
4042
u32 eint_pend;
41-
u32 *eint_wake_mask_value;
43+
u32 eint_num_wakeup_reg;
4244
u32 eint_wake_mask_reg;
4345
void (*set_eint_wakeup_mask)(struct samsung_pinctrl_drv_data *drvdata,
4446
struct exynos_irq_chip *irq_chip);
4547
};
4648

49+
static u32 eint_wake_mask_values[MAX_WAKEUP_REG] = { EXYNOS_EINT_WAKEUP_MASK_DISABLED,
50+
EXYNOS_EINT_WAKEUP_MASK_DISABLED,
51+
EXYNOS_EINT_WAKEUP_MASK_DISABLED};
52+
4753
static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
4854
{
4955
return container_of(chip, struct exynos_irq_chip, chip);
@@ -307,7 +313,7 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
307313
.eint_con = EXYNOS_GPIO_ECON_OFFSET,
308314
.eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
309315
.eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
310-
/* eint_wake_mask_value not used */
316+
/* eint_wake_mask_values not used */
311317
};
312318

313319
static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
@@ -467,20 +473,65 @@ __init int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
467473
return ret;
468474
}
469475

476+
#define BITS_PER_U32 32
477+
static int gs101_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
478+
{
479+
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
480+
struct samsung_pinctrl_drv_data *d = bank->drvdata;
481+
u32 bit, wakeup_reg, shift;
482+
483+
bit = bank->eint_num + irqd->hwirq;
484+
wakeup_reg = bit / BITS_PER_U32;
485+
shift = bit - (wakeup_reg * BITS_PER_U32);
486+
487+
if (!on)
488+
eint_wake_mask_values[wakeup_reg] |= BIT_U32(shift);
489+
else
490+
eint_wake_mask_values[wakeup_reg] &= ~BIT_U32(shift);
491+
492+
dev_info(d->dev, "wake %s for irq %d\n", str_enabled_disabled(on),
493+
irqd->irq);
494+
495+
return 0;
496+
}
497+
498+
static void
499+
gs101_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
500+
struct exynos_irq_chip *irq_chip)
501+
{
502+
struct regmap *pmu_regs;
503+
504+
if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) {
505+
dev_warn(drvdata->dev,
506+
"No PMU syscon available. Wake-up mask will not be set.\n");
507+
return;
508+
}
509+
510+
pmu_regs = drvdata->retention_ctrl->priv;
511+
512+
dev_dbg(drvdata->dev, "Setting external wakeup interrupt mask:\n");
513+
514+
for (int i = 0; i < irq_chip->eint_num_wakeup_reg; i++) {
515+
dev_dbg(drvdata->dev, "\tWAKEUP_MASK%d[0x%X] value[0x%X]\n",
516+
i, irq_chip->eint_wake_mask_reg + i * 4,
517+
eint_wake_mask_values[i]);
518+
regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg + i * 4,
519+
eint_wake_mask_values[i]);
520+
}
521+
}
522+
470523
static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
471524
{
472-
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
473-
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
474525
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
475526
unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
476527

477528
pr_info("wake %s for irq %u (%s-%lu)\n", str_enabled_disabled(on),
478529
irqd->irq, bank->name, irqd->hwirq);
479530

480531
if (!on)
481-
*our_chip->eint_wake_mask_value |= bit;
532+
eint_wake_mask_values[0] |= bit;
482533
else
483-
*our_chip->eint_wake_mask_value &= ~bit;
534+
eint_wake_mask_values[0] &= ~bit;
484535

485536
return 0;
486537
}
@@ -500,10 +551,10 @@ exynos_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
500551
pmu_regs = drvdata->retention_ctrl->priv;
501552
dev_info(drvdata->dev,
502553
"Setting external wakeup interrupt mask: 0x%x\n",
503-
*irq_chip->eint_wake_mask_value);
554+
eint_wake_mask_values[0]);
504555

505556
regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg,
506-
*irq_chip->eint_wake_mask_value);
557+
eint_wake_mask_values[0]);
507558
}
508559

509560
static void
@@ -522,11 +573,10 @@ s5pv210_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
522573

523574
clk_base = (void __iomem *) drvdata->retention_ctrl->priv;
524575

525-
__raw_writel(*irq_chip->eint_wake_mask_value,
576+
__raw_writel(eint_wake_mask_values[0],
526577
clk_base + irq_chip->eint_wake_mask_reg);
527578
}
528579

529-
static u32 eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED;
530580
/*
531581
* irq_chip for wakeup interrupts
532582
*/
@@ -544,7 +594,7 @@ static const struct exynos_irq_chip s5pv210_wkup_irq_chip __initconst = {
544594
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
545595
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
546596
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
547-
.eint_wake_mask_value = &eint_wake_mask_value,
597+
.eint_num_wakeup_reg = 1,
548598
/* Only differences with exynos4210_wkup_irq_chip: */
549599
.eint_wake_mask_reg = S5PV210_EINT_WAKEUP_MASK,
550600
.set_eint_wakeup_mask = s5pv210_pinctrl_set_eint_wakeup_mask,
@@ -564,7 +614,7 @@ static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = {
564614
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
565615
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
566616
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
567-
.eint_wake_mask_value = &eint_wake_mask_value,
617+
.eint_num_wakeup_reg = 1,
568618
.eint_wake_mask_reg = EXYNOS_EINT_WAKEUP_MASK,
569619
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
570620
};
@@ -583,7 +633,7 @@ static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
583633
.eint_con = EXYNOS7_WKUP_ECON_OFFSET,
584634
.eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
585635
.eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
586-
.eint_wake_mask_value = &eint_wake_mask_value,
636+
.eint_num_wakeup_reg = 1,
587637
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
588638
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
589639
};
@@ -599,13 +649,34 @@ static const struct exynos_irq_chip exynosautov920_wkup_irq_chip __initconst = {
599649
.irq_request_resources = exynos_irq_request_resources,
600650
.irq_release_resources = exynos_irq_release_resources,
601651
},
602-
.eint_wake_mask_value = &eint_wake_mask_value,
652+
.eint_num_wakeup_reg = 1,
603653
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
604654
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
605655
};
606656

657+
static const struct exynos_irq_chip gs101_wkup_irq_chip __initconst = {
658+
.chip = {
659+
.name = "gs101_wkup_irq_chip",
660+
.irq_unmask = exynos_irq_unmask,
661+
.irq_mask = exynos_irq_mask,
662+
.irq_ack = exynos_irq_ack,
663+
.irq_set_type = exynos_irq_set_type,
664+
.irq_set_wake = gs101_wkup_irq_set_wake,
665+
.irq_request_resources = exynos_irq_request_resources,
666+
.irq_release_resources = exynos_irq_release_resources,
667+
},
668+
.eint_con = EXYNOS7_WKUP_ECON_OFFSET,
669+
.eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
670+
.eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
671+
.eint_num_wakeup_reg = 3,
672+
.eint_wake_mask_reg = GS101_EINT_WAKEUP_MASK,
673+
.set_eint_wakeup_mask = gs101_pinctrl_set_eint_wakeup_mask,
674+
};
675+
607676
/* list of external wakeup controllers supported */
608677
static const struct of_device_id exynos_wkup_irq_ids[] = {
678+
{ .compatible = "google,gs101-wakeup-eint",
679+
.data = &gs101_wkup_irq_chip },
609680
{ .compatible = "samsung,s5pv210-wakeup-eint",
610681
.data = &s5pv210_wkup_irq_chip },
611682
{ .compatible = "samsung,exynos4210-wakeup-eint",
@@ -688,6 +759,7 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
688759
chained_irq_exit(chip, desc);
689760
}
690761

762+
static int eint_num;
691763
/*
692764
* exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
693765
* @d: driver data of samsung pinctrl driver.
@@ -736,6 +808,9 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
736808
return -ENXIO;
737809
}
738810

811+
bank->eint_num = eint_num;
812+
eint_num = eint_num + bank->nr_pins;
813+
739814
if (!fwnode_property_present(bank->fwnode, "interrupts")) {
740815
bank->eint_type = EINT_TYPE_WKUP_MUX;
741816
++muxed_banks;

drivers/pinctrl/samsung/pinctrl-samsung.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ struct samsung_pin_bank_type {
141141
* @eint_type: type of the external interrupt supported by the bank.
142142
* @eint_mask: bit mask of pins which support EINT function.
143143
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
144+
* @eint_num: total number of eint pins.
144145
* @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank.
145146
* @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
146147
* @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
@@ -156,6 +157,7 @@ struct samsung_pin_bank_data {
156157
enum eint_type eint_type;
157158
u32 eint_mask;
158159
u32 eint_offset;
160+
u32 eint_num;
159161
u32 eint_con_offset;
160162
u32 eint_mask_offset;
161163
u32 eint_pend_offset;
@@ -174,6 +176,7 @@ struct samsung_pin_bank_data {
174176
* @eint_type: type of the external interrupt supported by the bank.
175177
* @eint_mask: bit mask of pins which support EINT function.
176178
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
179+
* @eint_num: total number of eint pins.
177180
* @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank.
178181
* @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
179182
* @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
@@ -201,6 +204,7 @@ struct samsung_pin_bank {
201204
enum eint_type eint_type;
202205
u32 eint_mask;
203206
u32 eint_offset;
207+
u32 eint_num;
204208
u32 eint_con_offset;
205209
u32 eint_mask_offset;
206210
u32 eint_pend_offset;

include/linux/soc/samsung/exynos-regs-pmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@
669669
#define GS101_CPU_INFORM(cpu) \
670670
(GS101_CPU0_INFORM + (cpu*4))
671671
#define GS101_SYSTEM_CONFIGURATION (0x3A00)
672+
#define GS101_EINT_WAKEUP_MASK (0x3A80)
672673
#define GS101_PHY_CTRL_USB20 (0x3EB0)
673674
#define GS101_PHY_CTRL_USBDP (0x3EB4)
674675

0 commit comments

Comments
 (0)