Commit 83906257 authored by Linus Walleij's avatar Linus Walleij

Merge tag 'samsung-pinctrl-6.10' of...

Merge tag 'samsung-pinctrl-6.10' of https://git.kernel.org/pub/scm/linux/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: default avatarLinus Walleij <linus.walleij@linaro.org>
parents 8ff05989 e5b3732a
...@@ -73,6 +73,13 @@ properties: ...@@ -73,6 +73,13 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
clocks:
maxItems: 1
clock-names:
items:
- const: pclk
wakeup-interrupt-controller: wakeup-interrupt-controller:
$ref: samsung,pinctrl-wakeup-interrupt.yaml $ref: samsung,pinctrl-wakeup-interrupt.yaml
...@@ -120,6 +127,20 @@ required: ...@@ -120,6 +127,20 @@ required:
allOf: allOf:
- $ref: pinctrl.yaml# - $ref: pinctrl.yaml#
- if:
properties:
compatible:
contains:
const: google,gs101-pinctrl
then:
required:
- clocks
- clock-names
else:
properties:
clocks: false
clock-names: false
- if: - if:
properties: properties:
compatible: compatible:
......
...@@ -17489,7 +17489,6 @@ C: irc://irc.libera.chat/linux-exynos ...@@ -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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
F: Documentation/devicetree/bindings/pinctrl/samsung,pinctrl*yaml F: Documentation/devicetree/bindings/pinctrl/samsung,pinctrl*yaml
F: drivers/pinctrl/samsung/ F: drivers/pinctrl/samsung/
F: include/dt-bindings/pinctrl/samsung.h
PIN CONTROLLER - SINGLE PIN CONTROLLER - SINGLE
M: Tony Lindgren <tony@atomide.com> M: Tony Lindgren <tony@atomide.com>
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// the Samsung pinctrl/gpiolib driver. It also includes the implementation of // the Samsung pinctrl/gpiolib driver. It also includes the implementation of
// external gpio and wakeup interrupt support. // external gpio and wakeup interrupt support.
#include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
...@@ -61,6 +62,12 @@ static void exynos_irq_mask(struct irq_data *irqd) ...@@ -61,6 +62,12 @@ static void exynos_irq_mask(struct irq_data *irqd)
else else
reg_mask = our_chip->eint_mask + bank->eint_offset; 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); raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask); mask = readl(bank->eint_base + reg_mask);
...@@ -68,6 +75,8 @@ static void exynos_irq_mask(struct irq_data *irqd) ...@@ -68,6 +75,8 @@ static void exynos_irq_mask(struct irq_data *irqd)
writel(mask, bank->eint_base + reg_mask); writel(mask, bank->eint_base + reg_mask);
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->drvdata->pclk);
} }
static void exynos_irq_ack(struct irq_data *irqd) static void exynos_irq_ack(struct irq_data *irqd)
...@@ -82,7 +91,15 @@ static void exynos_irq_ack(struct irq_data *irqd) ...@@ -82,7 +91,15 @@ static void exynos_irq_ack(struct irq_data *irqd)
else else
reg_pend = our_chip->eint_pend + bank->eint_offset; 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); writel(1 << irqd->hwirq, bank->eint_base + reg_pend);
clk_disable(bank->drvdata->pclk);
} }
static void exynos_irq_unmask(struct irq_data *irqd) static void exynos_irq_unmask(struct irq_data *irqd)
...@@ -110,6 +127,12 @@ static void exynos_irq_unmask(struct irq_data *irqd) ...@@ -110,6 +127,12 @@ static void exynos_irq_unmask(struct irq_data *irqd)
else else
reg_mask = our_chip->eint_mask + bank->eint_offset; 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); raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask); mask = readl(bank->eint_base + reg_mask);
...@@ -117,6 +140,8 @@ static void exynos_irq_unmask(struct irq_data *irqd) ...@@ -117,6 +140,8 @@ static void exynos_irq_unmask(struct irq_data *irqd)
writel(mask, bank->eint_base + reg_mask); writel(mask, bank->eint_base + reg_mask);
raw_spin_unlock_irqrestore(&bank->slock, flags); 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) static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
...@@ -127,6 +152,7 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) ...@@ -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 shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
unsigned int con, trig_type; unsigned int con, trig_type;
unsigned long reg_con; unsigned long reg_con;
int ret;
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
...@@ -159,11 +185,20 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) ...@@ -159,11 +185,20 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
else else
reg_con = our_chip->eint_con + bank->eint_offset; 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 = readl(bank->eint_base + reg_con);
con &= ~(EXYNOS_EINT_CON_MASK << shift); con &= ~(EXYNOS_EINT_CON_MASK << shift);
con |= trig_type << shift; con |= trig_type << shift;
writel(con, bank->eint_base + reg_con); writel(con, bank->eint_base + reg_con);
clk_disable(bank->drvdata->pclk);
return 0; return 0;
} }
...@@ -200,6 +235,14 @@ static int exynos_irq_request_resources(struct irq_data *irqd) ...@@ -200,6 +235,14 @@ static int exynos_irq_request_resources(struct irq_data *irqd)
shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC]; shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; 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); raw_spin_lock_irqsave(&bank->slock, flags);
con = readl(bank->pctl_base + reg_con); con = readl(bank->pctl_base + reg_con);
...@@ -209,6 +252,8 @@ static int exynos_irq_request_resources(struct irq_data *irqd) ...@@ -209,6 +252,8 @@ static int exynos_irq_request_resources(struct irq_data *irqd)
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->drvdata->pclk);
return 0; return 0;
} }
...@@ -223,6 +268,13 @@ static void exynos_irq_release_resources(struct irq_data *irqd) ...@@ -223,6 +268,13 @@ static void exynos_irq_release_resources(struct irq_data *irqd)
shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC]; shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; 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); raw_spin_lock_irqsave(&bank->slock, flags);
con = readl(bank->pctl_base + reg_con); con = readl(bank->pctl_base + reg_con);
...@@ -232,6 +284,8 @@ static void exynos_irq_release_resources(struct irq_data *irqd) ...@@ -232,6 +284,8 @@ static void exynos_irq_release_resources(struct irq_data *irqd)
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->drvdata->pclk);
gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq); gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq);
} }
...@@ -281,10 +335,19 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) ...@@ -281,10 +335,19 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
unsigned int svc, group, pin; unsigned int svc, group, pin;
int ret; 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) if (bank->eint_con_offset)
svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET); svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
else else
svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET); svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
clk_disable(bank->drvdata->pclk);
group = EXYNOS_SVC_GROUP(svc); group = EXYNOS_SVC_GROUP(svc);
pin = svc & EXYNOS_SVC_NUM_MASK; pin = svc & EXYNOS_SVC_NUM_MASK;
...@@ -563,6 +626,20 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc) ...@@ -563,6 +626,20 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
chained_irq_enter(chip, 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) { for (i = 0; i < eintd->nr_banks; ++i) {
struct samsung_pin_bank *b = eintd->banks[i]; struct samsung_pin_bank *b = eintd->banks[i];
pend = readl(b->eint_base + b->irq_chip->eint_pend pend = readl(b->eint_base + b->irq_chip->eint_pend
...@@ -572,6 +649,9 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc) ...@@ -572,6 +649,9 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
exynos_irq_demux_eint(pend & ~mask, b->irq_domain); 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); chained_irq_exit(chip, desc);
} }
...@@ -695,6 +775,12 @@ static void exynos_pinctrl_suspend_bank( ...@@ -695,6 +775,12 @@ static void exynos_pinctrl_suspend_bank(
struct exynos_eint_gpio_save *save = bank->soc_priv; struct exynos_eint_gpio_save *save = bank->soc_priv;
const void __iomem *regs = bank->eint_base; 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 save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset); + bank->eint_offset);
save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
...@@ -704,6 +790,8 @@ static void exynos_pinctrl_suspend_bank( ...@@ -704,6 +790,8 @@ static void exynos_pinctrl_suspend_bank(
save->eint_mask = readl(regs + bank->irq_chip->eint_mask save->eint_mask = readl(regs + bank->irq_chip->eint_mask
+ bank->eint_offset); + bank->eint_offset);
clk_disable(bank->drvdata->pclk);
pr_debug("%s: save con %#010x\n", bank->name, save->eint_con); 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 fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1); pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
...@@ -716,9 +804,17 @@ static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drv ...@@ -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; struct exynos_eint_gpio_save *save = bank->soc_priv;
const void __iomem *regs = bank->eint_base; 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_con = readl(regs + bank->pctl_offset + bank->eint_con_offset);
save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_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 con %#010x\n", bank->name, save->eint_con);
pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask); pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
} }
...@@ -753,6 +849,12 @@ static void exynos_pinctrl_resume_bank( ...@@ -753,6 +849,12 @@ static void exynos_pinctrl_resume_bank(
struct exynos_eint_gpio_save *save = bank->soc_priv; struct exynos_eint_gpio_save *save = bank->soc_priv;
void __iomem *regs = bank->eint_base; 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, pr_debug("%s: con %#010x => %#010x\n", bank->name,
readl(regs + EXYNOS_GPIO_ECON_OFFSET readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset), save->eint_con); + bank->eint_offset), save->eint_con);
...@@ -774,6 +876,8 @@ static void exynos_pinctrl_resume_bank( ...@@ -774,6 +876,8 @@ static void exynos_pinctrl_resume_bank(
+ 2 * bank->eint_offset + 4); + 2 * bank->eint_offset + 4);
writel(save->eint_mask, regs + bank->irq_chip->eint_mask writel(save->eint_mask, regs + bank->irq_chip->eint_mask
+ bank->eint_offset); + bank->eint_offset);
clk_disable(bank->drvdata->pclk);
} }
static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata, static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
...@@ -782,6 +886,12 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd ...@@ -782,6 +886,12 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd
struct exynos_eint_gpio_save *save = bank->soc_priv; struct exynos_eint_gpio_save *save = bank->soc_priv;
void __iomem *regs = bank->eint_base; 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, pr_debug("%s: con %#010x => %#010x\n", bank->name,
readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con); readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
pr_debug("%s: mask %#010x => %#010x\n", bank->name, pr_debug("%s: mask %#010x => %#010x\n", bank->name,
...@@ -789,6 +899,8 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd ...@@ -789,6 +899,8 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd
writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset); writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset);
writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_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) void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
// but provides extensions to which platform specific implementation of the gpio // but provides extensions to which platform specific implementation of the gpio
// and wakeup interrupts can be hooked to. // and wakeup interrupts can be hooked to.
#include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -371,7 +372,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, ...@@ -371,7 +372,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
} }
/* enable or disable a pinmux function */ /* enable or disable a pinmux function */
static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, static int samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group) unsigned group)
{ {
struct samsung_pinctrl_drv_data *drvdata; struct samsung_pinctrl_drv_data *drvdata;
...@@ -382,6 +383,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, ...@@ -382,6 +383,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
unsigned long flags; unsigned long flags;
const struct samsung_pmx_func *func; const struct samsung_pmx_func *func;
const struct samsung_pin_group *grp; const struct samsung_pin_group *grp;
int ret;
drvdata = pinctrl_dev_get_drvdata(pctldev); drvdata = pinctrl_dev_get_drvdata(pctldev);
func = &drvdata->pmx_functions[selector]; func = &drvdata->pmx_functions[selector];
...@@ -397,6 +399,12 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, ...@@ -397,6 +399,12 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
reg += 4; reg += 4;
} }
ret = clk_enable(drvdata->pclk);
if (ret) {
dev_err(pctldev->dev, "failed to enable clock for setup\n");
return ret;
}
raw_spin_lock_irqsave(&bank->slock, flags); raw_spin_lock_irqsave(&bank->slock, flags);
data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
...@@ -405,6 +413,10 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, ...@@ -405,6 +413,10 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]); writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(drvdata->pclk);
return 0;
} }
/* enable a specified pinmux by writing to registers */ /* enable a specified pinmux by writing to registers */
...@@ -412,8 +424,7 @@ static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev, ...@@ -412,8 +424,7 @@ static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned selector, unsigned selector,
unsigned group) unsigned group)
{ {
samsung_pinmux_setup(pctldev, selector, group); return samsung_pinmux_setup(pctldev, selector, group);
return 0;
} }
/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ /* list of pinmux callbacks for the pinmux vertical in pinctrl core */
...@@ -436,6 +447,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -436,6 +447,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
u32 data, width, pin_offset, mask, shift; u32 data, width, pin_offset, mask, shift;
u32 cfg_value, cfg_reg; u32 cfg_value, cfg_reg;
unsigned long flags; unsigned long flags;
int ret;
drvdata = pinctrl_dev_get_drvdata(pctldev); drvdata = pinctrl_dev_get_drvdata(pctldev);
pin_to_reg_bank(drvdata, pin, &reg_base, &pin_offset, &bank); pin_to_reg_bank(drvdata, pin, &reg_base, &pin_offset, &bank);
...@@ -447,6 +459,12 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -447,6 +459,12 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
width = type->fld_width[cfg_type]; width = type->fld_width[cfg_type];
cfg_reg = type->reg_offset[cfg_type]; cfg_reg = type->reg_offset[cfg_type];
ret = clk_enable(drvdata->pclk);
if (ret) {
dev_err(drvdata->dev, "failed to enable clock\n");
return ret;
}
raw_spin_lock_irqsave(&bank->slock, flags); raw_spin_lock_irqsave(&bank->slock, flags);
mask = (1 << width) - 1; mask = (1 << width) - 1;
...@@ -466,6 +484,8 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -466,6 +484,8 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(drvdata->pclk);
return 0; return 0;
} }
...@@ -555,11 +575,19 @@ static void samsung_gpio_set_value(struct gpio_chip *gc, ...@@ -555,11 +575,19 @@ static void samsung_gpio_set_value(struct gpio_chip *gc,
static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{ {
struct samsung_pin_bank *bank = gpiochip_get_data(gc); struct samsung_pin_bank *bank = gpiochip_get_data(gc);
struct samsung_pinctrl_drv_data *drvdata = bank->drvdata;
unsigned long flags; unsigned long flags;
if (clk_enable(drvdata->pclk)) {
dev_err(drvdata->dev, "failed to enable clock\n");
return;
}
raw_spin_lock_irqsave(&bank->slock, flags); raw_spin_lock_irqsave(&bank->slock, flags);
samsung_gpio_set_value(gc, offset, value); samsung_gpio_set_value(gc, offset, value);
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(drvdata->pclk);
} }
/* gpiolib gpio_get callback function */ /* gpiolib gpio_get callback function */
...@@ -569,12 +597,23 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) ...@@ -569,12 +597,23 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
u32 data; u32 data;
struct samsung_pin_bank *bank = gpiochip_get_data(gc); struct samsung_pin_bank *bank = gpiochip_get_data(gc);
const struct samsung_pin_bank_type *type = bank->type; const struct samsung_pin_bank_type *type = bank->type;
struct samsung_pinctrl_drv_data *drvdata = bank->drvdata;
int ret;
reg = bank->pctl_base + bank->pctl_offset; reg = bank->pctl_base + bank->pctl_offset;
ret = clk_enable(drvdata->pclk);
if (ret) {
dev_err(drvdata->dev, "failed to enable clock\n");
return ret;
}
data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
data >>= offset; data >>= offset;
data &= 1; data &= 1;
clk_disable(drvdata->pclk);
return data; return data;
} }
...@@ -619,12 +658,22 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, ...@@ -619,12 +658,22 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{ {
struct samsung_pin_bank *bank = gpiochip_get_data(gc); struct samsung_pin_bank *bank = gpiochip_get_data(gc);
struct samsung_pinctrl_drv_data *drvdata = bank->drvdata;
unsigned long flags; unsigned long flags;
int ret; int ret;
ret = clk_enable(drvdata->pclk);
if (ret) {
dev_err(drvdata->dev, "failed to enable clock\n");
return ret;
}
raw_spin_lock_irqsave(&bank->slock, flags); raw_spin_lock_irqsave(&bank->slock, flags);
ret = samsung_gpio_set_direction(gc, offset, true); ret = samsung_gpio_set_direction(gc, offset, true);
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(drvdata->pclk);
return ret; return ret;
} }
...@@ -633,14 +682,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, ...@@ -633,14 +682,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
int value) int value)
{ {
struct samsung_pin_bank *bank = gpiochip_get_data(gc); struct samsung_pin_bank *bank = gpiochip_get_data(gc);
struct samsung_pinctrl_drv_data *drvdata = bank->drvdata;
unsigned long flags; unsigned long flags;
int ret; int ret;
ret = clk_enable(drvdata->pclk);
if (ret) {
dev_err(drvdata->dev, "failed to enable clock\n");
return ret;
}
raw_spin_lock_irqsave(&bank->slock, flags); raw_spin_lock_irqsave(&bank->slock, flags);
samsung_gpio_set_value(gc, offset, value); samsung_gpio_set_value(gc, offset, value);
ret = samsung_gpio_set_direction(gc, offset, false); ret = samsung_gpio_set_direction(gc, offset, false);
raw_spin_unlock_irqrestore(&bank->slock, flags); raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(drvdata->pclk);
return ret; return ret;
} }
...@@ -1164,6 +1222,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) ...@@ -1164,6 +1222,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
} }
} }
drvdata->pclk = devm_clk_get_optional_prepared(dev, "pclk");
if (IS_ERR(drvdata->pclk)) {
ret = PTR_ERR(drvdata->pclk);
goto err_put_banks;
}
ret = samsung_pinctrl_register(pdev, drvdata); ret = samsung_pinctrl_register(pdev, drvdata);
if (ret) if (ret)
goto err_put_banks; goto err_put_banks;
...@@ -1202,6 +1266,13 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) ...@@ -1202,6 +1266,13 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
int i; int i;
i = clk_enable(drvdata->pclk);
if (i) {
dev_err(drvdata->dev,
"failed to enable clock for saving state\n");
return i;
}
for (i = 0; i < drvdata->nr_banks; i++) { for (i = 0; i < drvdata->nr_banks; i++) {
struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
const void __iomem *reg = bank->pctl_base + bank->pctl_offset; const void __iomem *reg = bank->pctl_base + bank->pctl_offset;
...@@ -1231,6 +1302,8 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) ...@@ -1231,6 +1302,8 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
} }
} }
clk_disable(drvdata->pclk);
if (drvdata->suspend) if (drvdata->suspend)
drvdata->suspend(drvdata); drvdata->suspend(drvdata);
if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable) if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable)
...@@ -1250,8 +1323,20 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) ...@@ -1250,8 +1323,20 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
static int __maybe_unused samsung_pinctrl_resume(struct device *dev) static int __maybe_unused samsung_pinctrl_resume(struct device *dev)
{ {
struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
int ret;
int i; int i;
/*
* enable clock before the callback, as we don't want to have to deal
* with callback cleanup on clock failures.
*/
ret = clk_enable(drvdata->pclk);
if (ret) {
dev_err(drvdata->dev,
"failed to enable clock for restoring state\n");
return ret;
}
if (drvdata->resume) if (drvdata->resume)
drvdata->resume(drvdata); drvdata->resume(drvdata);
...@@ -1286,6 +1371,8 @@ static int __maybe_unused samsung_pinctrl_resume(struct device *dev) ...@@ -1286,6 +1371,8 @@ static int __maybe_unused samsung_pinctrl_resume(struct device *dev)
writel(bank->pm_save[type], reg + offs[type]); writel(bank->pm_save[type], reg + offs[type]);
} }
clk_disable(drvdata->pclk);
if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable) if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable)
drvdata->retention_ctrl->disable(drvdata); drvdata->retention_ctrl->disable(drvdata);
......
...@@ -274,6 +274,7 @@ struct samsung_pin_ctrl { ...@@ -274,6 +274,7 @@ struct samsung_pin_ctrl {
* through samsung_pinctrl_drv_data, not samsung_pin_bank). * through samsung_pinctrl_drv_data, not samsung_pin_bank).
* @dev: device instance representing the controller. * @dev: device instance representing the controller.
* @irq: interrpt number used by the controller to notify gpio interrupts. * @irq: interrpt number used by the controller to notify gpio interrupts.
* @pclk: optional bus clock if required for accessing registers
* @ctrl: pin controller instance managed by the driver. * @ctrl: pin controller instance managed by the driver.
* @pctl: pin controller descriptor registered with the pinctrl subsystem. * @pctl: pin controller descriptor registered with the pinctrl subsystem.
* @pctl_dev: cookie representing pinctrl device instance. * @pctl_dev: cookie representing pinctrl device instance.
...@@ -293,6 +294,7 @@ struct samsung_pinctrl_drv_data { ...@@ -293,6 +294,7 @@ struct samsung_pinctrl_drv_data {
void __iomem *virt_base; void __iomem *virt_base;
struct device *dev; struct device *dev;
int irq; int irq;
struct clk *pclk;
struct pinctrl_desc pctl; struct pinctrl_desc pctl;
struct pinctrl_dev *pctl_dev; struct pinctrl_dev *pctl_dev;
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Samsung's Exynos pinctrl bindings
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* http://www.samsung.com
* Author: Krzysztof Kozlowski <krzk@kernel.org>
*/
#ifndef __DT_BINDINGS_PINCTRL_SAMSUNG_H__
#define __DT_BINDINGS_PINCTRL_SAMSUNG_H__
/*
* These bindings are deprecated, because they do not match the actual
* concept of bindings but rather contain pure register values.
* Instead include the header in the DTS source directory.
*/
#warning "These bindings are deprecated. Instead use the header in the DTS source directory."
#define EXYNOS_PIN_PULL_NONE 0
#define EXYNOS_PIN_PULL_DOWN 1
#define EXYNOS_PIN_PULL_UP 3
#define S3C64XX_PIN_PULL_NONE 0
#define S3C64XX_PIN_PULL_DOWN 1
#define S3C64XX_PIN_PULL_UP 2
/* Pin function in power down mode */
#define EXYNOS_PIN_PDN_OUT0 0
#define EXYNOS_PIN_PDN_OUT1 1
#define EXYNOS_PIN_PDN_INPUT 2
#define EXYNOS_PIN_PDN_PREV 3
/* Drive strengths for Exynos3250, Exynos4 (all) and Exynos5250 */
#define EXYNOS4_PIN_DRV_LV1 0
#define EXYNOS4_PIN_DRV_LV2 2
#define EXYNOS4_PIN_DRV_LV3 1
#define EXYNOS4_PIN_DRV_LV4 3
/* Drive strengths for Exynos5260 */
#define EXYNOS5260_PIN_DRV_LV1 0
#define EXYNOS5260_PIN_DRV_LV2 1
#define EXYNOS5260_PIN_DRV_LV4 2
#define EXYNOS5260_PIN_DRV_LV6 3
/*
* Drive strengths for Exynos5410, Exynos542x, Exynos5800 and Exynos850 (except
* GPIO_HSI block)
*/
#define EXYNOS5420_PIN_DRV_LV1 0
#define EXYNOS5420_PIN_DRV_LV2 1
#define EXYNOS5420_PIN_DRV_LV3 2
#define EXYNOS5420_PIN_DRV_LV4 3
/* Drive strengths for Exynos5433 */
#define EXYNOS5433_PIN_DRV_FAST_SR1 0
#define EXYNOS5433_PIN_DRV_FAST_SR2 1
#define EXYNOS5433_PIN_DRV_FAST_SR3 2
#define EXYNOS5433_PIN_DRV_FAST_SR4 3
#define EXYNOS5433_PIN_DRV_FAST_SR5 4
#define EXYNOS5433_PIN_DRV_FAST_SR6 5
#define EXYNOS5433_PIN_DRV_SLOW_SR1 8
#define EXYNOS5433_PIN_DRV_SLOW_SR2 9
#define EXYNOS5433_PIN_DRV_SLOW_SR3 0xa
#define EXYNOS5433_PIN_DRV_SLOW_SR4 0xb
#define EXYNOS5433_PIN_DRV_SLOW_SR5 0xc
#define EXYNOS5433_PIN_DRV_SLOW_SR6 0xf
/* Drive strengths for Exynos850 GPIO_HSI block */
#define EXYNOS850_HSI_PIN_DRV_LV1 0 /* 1x */
#define EXYNOS850_HSI_PIN_DRV_LV1_5 1 /* 1.5x */
#define EXYNOS850_HSI_PIN_DRV_LV2 2 /* 2x */
#define EXYNOS850_HSI_PIN_DRV_LV2_5 3 /* 2.5x */
#define EXYNOS850_HSI_PIN_DRV_LV3 4 /* 3x */
#define EXYNOS850_HSI_PIN_DRV_LV4 5 /* 4x */
#define EXYNOS_PIN_FUNC_INPUT 0
#define EXYNOS_PIN_FUNC_OUTPUT 1
#define EXYNOS_PIN_FUNC_2 2
#define EXYNOS_PIN_FUNC_3 3
#define EXYNOS_PIN_FUNC_4 4
#define EXYNOS_PIN_FUNC_5 5
#define EXYNOS_PIN_FUNC_6 6
#define EXYNOS_PIN_FUNC_EINT 0xf
#define EXYNOS_PIN_FUNC_F EXYNOS_PIN_FUNC_EINT
/* Drive strengths for Exynos7 FSYS1 block */
#define EXYNOS7_FSYS1_PIN_DRV_LV1 0
#define EXYNOS7_FSYS1_PIN_DRV_LV2 4
#define EXYNOS7_FSYS1_PIN_DRV_LV3 2
#define EXYNOS7_FSYS1_PIN_DRV_LV4 6
#define EXYNOS7_FSYS1_PIN_DRV_LV5 1
#define EXYNOS7_FSYS1_PIN_DRV_LV6 5
#endif /* __DT_BINDINGS_PINCTRL_SAMSUNG_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment