Skip to content

Commit 2642f55

Browse files
petegriffinkrzk
authored andcommitted
pinctrl: samsung: add support for gs101 wakeup mask programming
gs101 differs to other currently supported SoCs in that it has 3 wakeup mask registers for the 67 external wakeup interrupt pins in alive and far_alive. EINT_WAKEUP_MASK 0x3A80 EINT[31:0] EINT_WAKEUP_MASK2 0x3A84 EINT[63:32] EINT_WAKEUP_MASK3 0x3A88 EINT[66:64] Add gs101 specific callbacks and a dedicated gs101_wkup_irq_chip struct to handle these differences. The current wakeup mask with upstream is programmed as WAKEUP_MASK0[0x3A80] value[0xFFFFFFFF] WAKEUP_MASK1[0x3A84] value[0xF2FFEFFF] WAKEUP_MASK2[0x3A88] value[0xFFFFFFFF] Which corresponds to the following wakeup sources: gpa7-3 vol down gpa8-1 vol up gpa10-1 power gpa8-2 typec-int Signed-off-by: Peter Griffin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Krzysztof Kozlowski <[email protected]>
1 parent c8edb80 commit 2642f55

File tree

3 files changed

+91
-14
lines changed

3 files changed

+91
-14
lines changed

drivers/pinctrl/samsung/pinctrl-exynos.c

Lines changed: 86 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,31 @@ 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_num_wakeup_reg = 3,
669+
.eint_wake_mask_reg = GS101_EINT_WAKEUP_MASK,
670+
.set_eint_wakeup_mask = gs101_pinctrl_set_eint_wakeup_mask,
671+
};
672+
607673
/* list of external wakeup controllers supported */
608674
static const struct of_device_id exynos_wkup_irq_ids[] = {
675+
{ .compatible = "google,gs101-wakeup-eint",
676+
.data = &gs101_wkup_irq_chip },
609677
{ .compatible = "samsung,s5pv210-wakeup-eint",
610678
.data = &s5pv210_wkup_irq_chip },
611679
{ .compatible = "samsung,exynos4210-wakeup-eint",
@@ -688,6 +756,7 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
688756
chained_irq_exit(chip, desc);
689757
}
690758

759+
static int eint_num;
691760
/*
692761
* exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
693762
* @d: driver data of samsung pinctrl driver.
@@ -736,6 +805,9 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
736805
return -ENXIO;
737806
}
738807

808+
bank->eint_num = eint_num;
809+
eint_num = eint_num + bank->nr_pins;
810+
739811
if (!fwnode_property_present(bank->fwnode, "interrupts")) {
740812
bank->eint_type = EINT_TYPE_WKUP_MUX;
741813
++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)