Skip to content

Commit

Permalink
Merge tag 'samsung-pinctrl-6.10' of https://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/pinctrl/samsung into devel

Samsung pinctrl drivers changes for v6.10

1. Add support for toggling bus clock (PCLK) for any pin controller
   register accesses.  This looks needed on newer Samsung chips, like
   Google GS101 and probably Exynos850.
2. Drop old, deprecated in v6.1 bindings header with register constants.
   The constants were moved to DTS headers.

Signed-off-by: Linus Walleij <[email protected]>
  • Loading branch information
linusw committed May 6, 2024
2 parents 8ff0598 + e5b3732 commit 8390625
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 100 deletions.
21 changes: 21 additions & 0 deletions Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ properties:
minItems: 1
maxItems: 2

clocks:
maxItems: 1

clock-names:
items:
- const: pclk

wakeup-interrupt-controller:
$ref: samsung,pinctrl-wakeup-interrupt.yaml

Expand Down Expand Up @@ -120,6 +127,20 @@ required:

allOf:
- $ref: pinctrl.yaml#
- if:
properties:
compatible:
contains:
const: google,gs101-pinctrl
then:
required:
- clocks
- clock-names
else:
properties:
clocks: false
clock-names: false

- if:
properties:
compatible:
Expand Down
1 change: 0 additions & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -17489,7 +17489,6 @@ C: irc://irc.libera.chat/linux-exynos
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
F: Documentation/devicetree/bindings/pinctrl/samsung,pinctrl*yaml
F: drivers/pinctrl/samsung/
F: include/dt-bindings/pinctrl/samsung.h

PIN CONTROLLER - SINGLE
M: Tony Lindgren <[email protected]>
Expand Down
112 changes: 112 additions & 0 deletions drivers/pinctrl/samsung/pinctrl-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// 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>
Expand Down Expand Up @@ -61,13 +62,21 @@ static void exynos_irq_mask(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 masking IRQ\n");
return;
}

raw_spin_lock_irqsave(&bank->slock, flags);

mask = readl(bank->eint_base + reg_mask);
mask |= 1 << irqd->hwirq;
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)
Expand All @@ -82,7 +91,15 @@ 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)
Expand Down Expand Up @@ -110,13 +127,21 @@ 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);
mask &= ~(1 << irqd->hwirq);
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)
Expand All @@ -127,6 +152,7 @@ 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:
Expand Down Expand Up @@ -159,11 +185,20 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
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;
}

Expand Down Expand Up @@ -200,6 +235,14 @@ static int exynos_irq_request_resources(struct irq_data *irqd)
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);
Expand All @@ -209,6 +252,8 @@ static int exynos_irq_request_resources(struct irq_data *irqd)

raw_spin_unlock_irqrestore(&bank->slock, flags);

clk_disable(bank->drvdata->pclk);

return 0;
}

Expand All @@ -223,6 +268,13 @@ static void exynos_irq_release_resources(struct irq_data *irqd)
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);
Expand All @@ -232,6 +284,8 @@ static void exynos_irq_release_resources(struct irq_data *irqd)

raw_spin_unlock_irqrestore(&bank->slock, flags);

clk_disable(bank->drvdata->pclk);

gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq);
}

Expand Down Expand Up @@ -281,10 +335,19 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
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;

Expand Down Expand Up @@ -563,6 +626,20 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)

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
Expand All @@ -572,6 +649,9 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
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);
}

Expand Down Expand Up @@ -695,6 +775,12 @@ static void exynos_pinctrl_suspend_bank(
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
Expand All @@ -704,6 +790,8 @@ static void exynos_pinctrl_suspend_bank(
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);
Expand All @@ -716,9 +804,17 @@ static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drv
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);
}
Expand Down Expand Up @@ -753,6 +849,12 @@ static void exynos_pinctrl_resume_bank(
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);
Expand All @@ -774,6 +876,8 @@ static void exynos_pinctrl_resume_bank(
+ 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,
Expand All @@ -782,13 +886,21 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd
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,
readl(regs + bank->pctl_offset + bank->eint_mask_offset), save->eint_mask);

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)
Expand Down
Loading

0 comments on commit 8390625

Please sign in to comment.