// the Samsung pinctrl/gpiolib driver. It also includes the implementation of
// external gpio and wakeup interrupt support.
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
else
reg_mask = our_chip->eint_mask + bank->eint_offset;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for masking IRQ\n");
+ return;
+ }
+
raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask);
writel(mask, bank->eint_base + reg_mask);
raw_spin_unlock_irqrestore(&bank->slock, flags);
+
+ clk_disable(bank->drvdata->pclk);
}
static void exynos_irq_ack(struct irq_data *irqd)
else
reg_pend = our_chip->eint_pend + bank->eint_offset;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock to ack IRQ\n");
+ return;
+ }
+
writel(1 << irqd->hwirq, bank->eint_base + reg_pend);
+
+ clk_disable(bank->drvdata->pclk);
}
static void exynos_irq_unmask(struct irq_data *irqd)
else
reg_mask = our_chip->eint_mask + bank->eint_offset;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for unmasking IRQ\n");
+ return;
+ }
+
raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask);
writel(mask, bank->eint_base + reg_mask);
raw_spin_unlock_irqrestore(&bank->slock, flags);
+
+ clk_disable(bank->drvdata->pclk);
}
static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
unsigned int con, trig_type;
unsigned long reg_con;
+ int ret;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
else
reg_con = our_chip->eint_con + bank->eint_offset;
+ ret = clk_enable(bank->drvdata->pclk);
+ if (ret) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for configuring IRQ type\n");
+ return ret;
+ }
+
con = readl(bank->eint_base + reg_con);
con &= ~(EXYNOS_EINT_CON_MASK << shift);
con |= trig_type << shift;
writel(con, bank->eint_base + reg_con);
+ clk_disable(bank->drvdata->pclk);
+
return 0;
}
shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+ ret = clk_enable(bank->drvdata->pclk);
+ if (ret) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for configuring pin %s-%lu\n",
+ bank->name, irqd->hwirq);
+ return ret;
+ }
+
raw_spin_lock_irqsave(&bank->slock, flags);
con = readl(bank->pctl_base + reg_con);
raw_spin_unlock_irqrestore(&bank->slock, flags);
+ clk_disable(bank->drvdata->pclk);
+
return 0;
}
shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for deconfiguring pin %s-%lu\n",
+ bank->name, irqd->hwirq);
+ return;
+ }
+
raw_spin_lock_irqsave(&bank->slock, flags);
con = readl(bank->pctl_base + reg_con);
raw_spin_unlock_irqrestore(&bank->slock, flags);
+ clk_disable(bank->drvdata->pclk);
+
gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq);
}
unsigned int svc, group, pin;
int ret;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for handling IRQ\n");
+ return IRQ_NONE;
+ }
+
if (bank->eint_con_offset)
svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
else
svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
+
+ clk_disable(bank->drvdata->pclk);
+
group = EXYNOS_SVC_GROUP(svc);
pin = svc & EXYNOS_SVC_NUM_MASK;
chained_irq_enter(chip, desc);
+ /*
+ * just enable the clock once here, to avoid an enable/disable dance for
+ * each bank.
+ */
+ if (eintd->nr_banks) {
+ struct samsung_pin_bank *b = eintd->banks[0];
+
+ if (clk_enable(b->drvdata->pclk)) {
+ dev_err(b->gpio_chip.parent,
+ "unable to enable clock for pending IRQs\n");
+ return;
+ }
+ }
+
for (i = 0; i < eintd->nr_banks; ++i) {
struct samsung_pin_bank *b = eintd->banks[i];
pend = readl(b->eint_base + b->irq_chip->eint_pend
exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
}
+ if (eintd->nr_banks)
+ clk_disable(eintd->banks[0]->drvdata->pclk);
+
chained_irq_exit(chip, desc);
}
struct exynos_eint_gpio_save *save = bank->soc_priv;
const void __iomem *regs = bank->eint_base;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for saving state\n");
+ return;
+ }
+
save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset);
save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
save->eint_mask = readl(regs + bank->irq_chip->eint_mask
+ bank->eint_offset);
+ clk_disable(bank->drvdata->pclk);
+
pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
struct exynos_eint_gpio_save *save = bank->soc_priv;
const void __iomem *regs = bank->eint_base;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for saving state\n");
+ return;
+ }
+
save->eint_con = readl(regs + bank->pctl_offset + bank->eint_con_offset);
save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_offset);
+ clk_disable(bank->drvdata->pclk);
+
pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
}
struct exynos_eint_gpio_save *save = bank->soc_priv;
void __iomem *regs = bank->eint_base;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for restoring state\n");
+ return;
+ }
+
pr_debug("%s: con %#010x => %#010x\n", bank->name,
readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset), save->eint_con);
+ 2 * bank->eint_offset + 4);
writel(save->eint_mask, regs + bank->irq_chip->eint_mask
+ bank->eint_offset);
+
+ clk_disable(bank->drvdata->pclk);
}
static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
struct exynos_eint_gpio_save *save = bank->soc_priv;
void __iomem *regs = bank->eint_base;
+ if (clk_enable(bank->drvdata->pclk)) {
+ dev_err(bank->gpio_chip.parent,
+ "unable to enable clock for restoring state\n");
+ return;
+ }
+
pr_debug("%s: con %#010x => %#010x\n", bank->name,
readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
pr_debug("%s: mask %#010x => %#010x\n", bank->name,
writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset);
writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_offset);
+
+ clk_disable(bank->drvdata->pclk);
}
void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)