|
|
|
@@ -32,18 +32,24 @@
|
|
|
|
|
#include "pinctrl-samsung.h"
|
|
|
|
|
#include "pinctrl-exynos.h"
|
|
|
|
|
|
|
|
|
|
#define MAX_WAKEUP_REG 3
|
|
|
|
|
|
|
|
|
|
struct exynos_irq_chip {
|
|
|
|
|
struct irq_chip chip;
|
|
|
|
|
|
|
|
|
|
u32 eint_con;
|
|
|
|
|
u32 eint_mask;
|
|
|
|
|
u32 eint_pend;
|
|
|
|
|
u32 *eint_wake_mask_value;
|
|
|
|
|
u32 eint_num_wakeup_reg;
|
|
|
|
|
u32 eint_wake_mask_reg;
|
|
|
|
|
void (*set_eint_wakeup_mask)(struct samsung_pinctrl_drv_data *drvdata,
|
|
|
|
|
struct exynos_irq_chip *irq_chip);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static u32 eint_wake_mask_values[MAX_WAKEUP_REG] = { EXYNOS_EINT_WAKEUP_MASK_DISABLED,
|
|
|
|
|
EXYNOS_EINT_WAKEUP_MASK_DISABLED,
|
|
|
|
|
EXYNOS_EINT_WAKEUP_MASK_DISABLED};
|
|
|
|
|
|
|
|
|
|
static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
|
|
|
|
|
{
|
|
|
|
|
return container_of(chip, struct exynos_irq_chip, chip);
|
|
|
|
@@ -307,7 +313,7 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
|
|
|
|
|
.eint_con = EXYNOS_GPIO_ECON_OFFSET,
|
|
|
|
|
.eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
|
|
|
|
|
.eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
|
|
|
|
|
/* eint_wake_mask_value not used */
|
|
|
|
|
/* eint_wake_mask_values not used */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
|
|
|
|
@@ -467,10 +473,55 @@ err_domains:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define BITS_PER_U32 32
|
|
|
|
|
static int gs101_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
|
|
|
|
|
{
|
|
|
|
|
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
|
|
|
|
|
struct samsung_pinctrl_drv_data *d = bank->drvdata;
|
|
|
|
|
u32 bit, wakeup_reg, shift;
|
|
|
|
|
|
|
|
|
|
bit = bank->eint_num + irqd->hwirq;
|
|
|
|
|
wakeup_reg = bit / BITS_PER_U32;
|
|
|
|
|
shift = bit - (wakeup_reg * BITS_PER_U32);
|
|
|
|
|
|
|
|
|
|
if (!on)
|
|
|
|
|
eint_wake_mask_values[wakeup_reg] |= BIT_U32(shift);
|
|
|
|
|
else
|
|
|
|
|
eint_wake_mask_values[wakeup_reg] &= ~BIT_U32(shift);
|
|
|
|
|
|
|
|
|
|
dev_info(d->dev, "wake %s for irq %d\n", str_enabled_disabled(on),
|
|
|
|
|
irqd->irq);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gs101_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
|
|
|
|
|
struct exynos_irq_chip *irq_chip)
|
|
|
|
|
{
|
|
|
|
|
struct regmap *pmu_regs;
|
|
|
|
|
|
|
|
|
|
if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) {
|
|
|
|
|
dev_warn(drvdata->dev,
|
|
|
|
|
"No PMU syscon available. Wake-up mask will not be set.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pmu_regs = drvdata->retention_ctrl->priv;
|
|
|
|
|
|
|
|
|
|
dev_dbg(drvdata->dev, "Setting external wakeup interrupt mask:\n");
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < irq_chip->eint_num_wakeup_reg; i++) {
|
|
|
|
|
dev_dbg(drvdata->dev, "\tWAKEUP_MASK%d[0x%X] value[0x%X]\n",
|
|
|
|
|
i, irq_chip->eint_wake_mask_reg + i * 4,
|
|
|
|
|
eint_wake_mask_values[i]);
|
|
|
|
|
regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg + i * 4,
|
|
|
|
|
eint_wake_mask_values[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
|
|
|
|
|
{
|
|
|
|
|
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
|
|
|
|
|
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
|
|
|
|
|
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
|
|
|
|
|
unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
|
|
|
|
|
|
|
|
|
@@ -478,9 +529,9 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
|
|
|
|
|
irqd->irq, bank->name, irqd->hwirq);
|
|
|
|
|
|
|
|
|
|
if (!on)
|
|
|
|
|
*our_chip->eint_wake_mask_value |= bit;
|
|
|
|
|
eint_wake_mask_values[0] |= bit;
|
|
|
|
|
else
|
|
|
|
|
*our_chip->eint_wake_mask_value &= ~bit;
|
|
|
|
|
eint_wake_mask_values[0] &= ~bit;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@@ -500,10 +551,10 @@ exynos_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
|
|
|
|
|
pmu_regs = drvdata->retention_ctrl->priv;
|
|
|
|
|
dev_info(drvdata->dev,
|
|
|
|
|
"Setting external wakeup interrupt mask: 0x%x\n",
|
|
|
|
|
*irq_chip->eint_wake_mask_value);
|
|
|
|
|
eint_wake_mask_values[0]);
|
|
|
|
|
|
|
|
|
|
regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg,
|
|
|
|
|
*irq_chip->eint_wake_mask_value);
|
|
|
|
|
eint_wake_mask_values[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
@@ -522,11 +573,10 @@ s5pv210_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
|
|
|
|
|
|
|
|
|
|
clk_base = (void __iomem *) drvdata->retention_ctrl->priv;
|
|
|
|
|
|
|
|
|
|
__raw_writel(*irq_chip->eint_wake_mask_value,
|
|
|
|
|
__raw_writel(eint_wake_mask_values[0],
|
|
|
|
|
clk_base + irq_chip->eint_wake_mask_reg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED;
|
|
|
|
|
/*
|
|
|
|
|
* irq_chip for wakeup interrupts
|
|
|
|
|
*/
|
|
|
|
@@ -544,7 +594,7 @@ static const struct exynos_irq_chip s5pv210_wkup_irq_chip __initconst = {
|
|
|
|
|
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
|
|
|
|
|
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
|
|
|
|
|
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
|
|
|
|
|
.eint_wake_mask_value = &eint_wake_mask_value,
|
|
|
|
|
.eint_num_wakeup_reg = 1,
|
|
|
|
|
/* Only differences with exynos4210_wkup_irq_chip: */
|
|
|
|
|
.eint_wake_mask_reg = S5PV210_EINT_WAKEUP_MASK,
|
|
|
|
|
.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 = {
|
|
|
|
|
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
|
|
|
|
|
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
|
|
|
|
|
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
|
|
|
|
|
.eint_wake_mask_value = &eint_wake_mask_value,
|
|
|
|
|
.eint_num_wakeup_reg = 1,
|
|
|
|
|
.eint_wake_mask_reg = EXYNOS_EINT_WAKEUP_MASK,
|
|
|
|
|
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
|
|
|
|
|
};
|
|
|
|
@@ -583,7 +633,7 @@ static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
|
|
|
|
|
.eint_con = EXYNOS7_WKUP_ECON_OFFSET,
|
|
|
|
|
.eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
|
|
|
|
|
.eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
|
|
|
|
|
.eint_wake_mask_value = &eint_wake_mask_value,
|
|
|
|
|
.eint_num_wakeup_reg = 1,
|
|
|
|
|
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
|
|
|
|
|
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
|
|
|
|
|
};
|
|
|
|
@@ -599,13 +649,34 @@ static const struct exynos_irq_chip exynosautov920_wkup_irq_chip __initconst = {
|
|
|
|
|
.irq_request_resources = exynos_irq_request_resources,
|
|
|
|
|
.irq_release_resources = exynos_irq_release_resources,
|
|
|
|
|
},
|
|
|
|
|
.eint_wake_mask_value = &eint_wake_mask_value,
|
|
|
|
|
.eint_num_wakeup_reg = 1,
|
|
|
|
|
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
|
|
|
|
|
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct exynos_irq_chip gs101_wkup_irq_chip __initconst = {
|
|
|
|
|
.chip = {
|
|
|
|
|
.name = "gs101_wkup_irq_chip",
|
|
|
|
|
.irq_unmask = exynos_irq_unmask,
|
|
|
|
|
.irq_mask = exynos_irq_mask,
|
|
|
|
|
.irq_ack = exynos_irq_ack,
|
|
|
|
|
.irq_set_type = exynos_irq_set_type,
|
|
|
|
|
.irq_set_wake = gs101_wkup_irq_set_wake,
|
|
|
|
|
.irq_request_resources = exynos_irq_request_resources,
|
|
|
|
|
.irq_release_resources = exynos_irq_release_resources,
|
|
|
|
|
},
|
|
|
|
|
.eint_con = EXYNOS7_WKUP_ECON_OFFSET,
|
|
|
|
|
.eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
|
|
|
|
|
.eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
|
|
|
|
|
.eint_num_wakeup_reg = 3,
|
|
|
|
|
.eint_wake_mask_reg = GS101_EINT_WAKEUP_MASK,
|
|
|
|
|
.set_eint_wakeup_mask = gs101_pinctrl_set_eint_wakeup_mask,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* list of external wakeup controllers supported */
|
|
|
|
|
static const struct of_device_id exynos_wkup_irq_ids[] = {
|
|
|
|
|
{ .compatible = "google,gs101-wakeup-eint",
|
|
|
|
|
.data = &gs101_wkup_irq_chip },
|
|
|
|
|
{ .compatible = "samsung,s5pv210-wakeup-eint",
|
|
|
|
|
.data = &s5pv210_wkup_irq_chip },
|
|
|
|
|
{ .compatible = "samsung,exynos4210-wakeup-eint",
|
|
|
|
@@ -688,6 +759,7 @@ out:
|
|
|
|
|
chained_irq_exit(chip, desc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int eint_num;
|
|
|
|
|
/*
|
|
|
|
|
* exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
|
|
|
|
|
* @d: driver data of samsung pinctrl driver.
|
|
|
|
@@ -736,6 +808,9 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bank->eint_num = eint_num;
|
|
|
|
|
eint_num = eint_num + bank->nr_pins;
|
|
|
|
|
|
|
|
|
|
if (!fwnode_property_present(bank->fwnode, "interrupts")) {
|
|
|
|
|
bank->eint_type = EINT_TYPE_WKUP_MUX;
|
|
|
|
|
++muxed_banks;
|
|
|
|
|