Commit 7151cef5 authored by Herve Codina's avatar Herve Codina Committed by Linus Walleij

pinctrl: spear: plgpio: Convert to regmap

Resources need to be shared between pinmux and plgpio.

Use regmap (syscon) to access resources to allow an
easy way to share resources.
Signed-off-by: default avatarHerve Codina <herve.codina@bootlin.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Link: https://lore.kernel.org/r/20211202095255.165797-3-herve.codina@bootlin.comSigned-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent d11db044
...@@ -14,11 +14,13 @@ ...@@ -14,11 +14,13 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#define MAX_GPIO_PER_REG 32 #define MAX_GPIO_PER_REG 32
...@@ -64,7 +66,7 @@ struct plgpio_regs { ...@@ -64,7 +66,7 @@ struct plgpio_regs {
*/ */
struct plgpio { struct plgpio {
spinlock_t lock; spinlock_t lock;
void __iomem *base; struct regmap *regmap;
struct clk *clk; struct clk *clk;
struct gpio_chip chip; struct gpio_chip chip;
int (*p2o)(int pin); /* pin_to_offset */ int (*p2o)(int pin); /* pin_to_offset */
...@@ -77,33 +79,38 @@ struct plgpio { ...@@ -77,33 +79,38 @@ struct plgpio {
}; };
/* register manipulation inline functions */ /* register manipulation inline functions */
static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg) static inline u32 is_plgpio_set(struct regmap *regmap, u32 pin, u32 reg)
{ {
u32 offset = PIN_OFFSET(pin); u32 offset = PIN_OFFSET(pin);
void __iomem *reg_off = REG_OFFSET(base, reg, pin); u32 reg_off = REG_OFFSET(0, reg, pin);
u32 val = readl_relaxed(reg_off); u32 val;
regmap_read(regmap, reg_off, &val);
return !!(val & (1 << offset)); return !!(val & (1 << offset));
} }
static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg) static inline void plgpio_reg_set(struct regmap *regmap, u32 pin, u32 reg)
{ {
u32 offset = PIN_OFFSET(pin); u32 offset = PIN_OFFSET(pin);
void __iomem *reg_off = REG_OFFSET(base, reg, pin); u32 reg_off = REG_OFFSET(0, reg, pin);
u32 val = readl_relaxed(reg_off); u32 mask;
writel_relaxed(val | (1 << offset), reg_off); mask = 1 << offset;
regmap_update_bits(regmap, reg_off, mask, mask);
} }
static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg) static inline void plgpio_reg_reset(struct regmap *regmap, u32 pin, u32 reg)
{ {
u32 offset = PIN_OFFSET(pin); u32 offset = PIN_OFFSET(pin);
void __iomem *reg_off = REG_OFFSET(base, reg, pin); u32 reg_off = REG_OFFSET(0, reg, pin);
u32 val = readl_relaxed(reg_off); u32 mask;
writel_relaxed(val & ~(1 << offset), reg_off); mask = 1 << offset;
regmap_update_bits(regmap, reg_off, mask, 0);
} }
/* gpio framework specific routines */ /* gpio framework specific routines */
static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset) static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
{ {
...@@ -118,7 +125,7 @@ static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset) ...@@ -118,7 +125,7 @@ static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
} }
spin_lock_irqsave(&plgpio->lock, flags); spin_lock_irqsave(&plgpio->lock, flags);
plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir); plgpio_reg_set(plgpio->regmap, offset, plgpio->regs.dir);
spin_unlock_irqrestore(&plgpio->lock, flags); spin_unlock_irqrestore(&plgpio->lock, flags);
return 0; return 0;
...@@ -145,13 +152,13 @@ static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset, ...@@ -145,13 +152,13 @@ static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
spin_lock_irqsave(&plgpio->lock, flags); spin_lock_irqsave(&plgpio->lock, flags);
if (value) if (value)
plgpio_reg_set(plgpio->base, wdata_offset, plgpio_reg_set(plgpio->regmap, wdata_offset,
plgpio->regs.wdata); plgpio->regs.wdata);
else else
plgpio_reg_reset(plgpio->base, wdata_offset, plgpio_reg_reset(plgpio->regmap, wdata_offset,
plgpio->regs.wdata); plgpio->regs.wdata);
plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir); plgpio_reg_reset(plgpio->regmap, dir_offset, plgpio->regs.dir);
spin_unlock_irqrestore(&plgpio->lock, flags); spin_unlock_irqrestore(&plgpio->lock, flags);
return 0; return 0;
...@@ -171,7 +178,7 @@ static int plgpio_get_value(struct gpio_chip *chip, unsigned offset) ...@@ -171,7 +178,7 @@ static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
return -EINVAL; return -EINVAL;
} }
return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata); return is_plgpio_set(plgpio->regmap, offset, plgpio->regs.rdata);
} }
static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
...@@ -189,9 +196,9 @@ static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) ...@@ -189,9 +196,9 @@ static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
} }
if (value) if (value)
plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata); plgpio_reg_set(plgpio->regmap, offset, plgpio->regs.wdata);
else else
plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata); plgpio_reg_reset(plgpio->regmap, offset, plgpio->regs.wdata);
} }
static int plgpio_request(struct gpio_chip *chip, unsigned offset) static int plgpio_request(struct gpio_chip *chip, unsigned offset)
...@@ -234,7 +241,7 @@ static int plgpio_request(struct gpio_chip *chip, unsigned offset) ...@@ -234,7 +241,7 @@ static int plgpio_request(struct gpio_chip *chip, unsigned offset)
} }
spin_lock_irqsave(&plgpio->lock, flags); spin_lock_irqsave(&plgpio->lock, flags);
plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb); plgpio_reg_set(plgpio->regmap, offset, plgpio->regs.enb);
spin_unlock_irqrestore(&plgpio->lock, flags); spin_unlock_irqrestore(&plgpio->lock, flags);
return 0; return 0;
...@@ -266,7 +273,7 @@ static void plgpio_free(struct gpio_chip *chip, unsigned offset) ...@@ -266,7 +273,7 @@ static void plgpio_free(struct gpio_chip *chip, unsigned offset)
} }
spin_lock_irqsave(&plgpio->lock, flags); spin_lock_irqsave(&plgpio->lock, flags);
plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb); plgpio_reg_reset(plgpio->regmap, offset, plgpio->regs.enb);
spin_unlock_irqrestore(&plgpio->lock, flags); spin_unlock_irqrestore(&plgpio->lock, flags);
disable_clk: disable_clk:
...@@ -292,7 +299,7 @@ static void plgpio_irq_disable(struct irq_data *d) ...@@ -292,7 +299,7 @@ static void plgpio_irq_disable(struct irq_data *d)
} }
spin_lock_irqsave(&plgpio->lock, flags); spin_lock_irqsave(&plgpio->lock, flags);
plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie); plgpio_reg_set(plgpio->regmap, offset, plgpio->regs.ie);
spin_unlock_irqrestore(&plgpio->lock, flags); spin_unlock_irqrestore(&plgpio->lock, flags);
} }
...@@ -311,7 +318,7 @@ static void plgpio_irq_enable(struct irq_data *d) ...@@ -311,7 +318,7 @@ static void plgpio_irq_enable(struct irq_data *d)
} }
spin_lock_irqsave(&plgpio->lock, flags); spin_lock_irqsave(&plgpio->lock, flags);
plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie); plgpio_reg_reset(plgpio->regmap, offset, plgpio->regs.ie);
spin_unlock_irqrestore(&plgpio->lock, flags); spin_unlock_irqrestore(&plgpio->lock, flags);
} }
...@@ -320,7 +327,7 @@ static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) ...@@ -320,7 +327,7 @@ static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct plgpio *plgpio = gpiochip_get_data(gc); struct plgpio *plgpio = gpiochip_get_data(gc);
int offset = d->hwirq; int offset = d->hwirq;
void __iomem *reg_off; u32 reg_off;
unsigned int supported_type = 0, val; unsigned int supported_type = 0, val;
if (offset >= plgpio->chip.ngpio) if (offset >= plgpio->chip.ngpio)
...@@ -337,14 +344,14 @@ static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) ...@@ -337,14 +344,14 @@ static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
if (plgpio->regs.eit == -1) if (plgpio->regs.eit == -1)
return 0; return 0;
reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset); reg_off = REG_OFFSET(0, plgpio->regs.eit, offset);
val = readl_relaxed(reg_off); regmap_read(plgpio->regmap, reg_off, &val);
offset = PIN_OFFSET(offset); offset = PIN_OFFSET(offset);
if (trigger & IRQ_TYPE_EDGE_RISING) if (trigger & IRQ_TYPE_EDGE_RISING)
writel_relaxed(val | (1 << offset), reg_off); regmap_write(plgpio->regmap, reg_off, val | (1 << offset));
else else
writel_relaxed(val & ~(1 << offset), reg_off); regmap_write(plgpio->regmap, reg_off, val & ~(1 << offset));
return 0; return 0;
} }
...@@ -362,7 +369,8 @@ static void plgpio_irq_handler(struct irq_desc *desc) ...@@ -362,7 +369,8 @@ static void plgpio_irq_handler(struct irq_desc *desc)
struct plgpio *plgpio = gpiochip_get_data(gc); struct plgpio *plgpio = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc); struct irq_chip *irqchip = irq_desc_get_chip(desc);
int regs_count, count, pin, offset, i = 0; int regs_count, count, pin, offset, i = 0;
unsigned long pending; u32 pending;
unsigned long pendingl;
count = plgpio->chip.ngpio; count = plgpio->chip.ngpio;
regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG); regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG);
...@@ -370,14 +378,14 @@ static void plgpio_irq_handler(struct irq_desc *desc) ...@@ -370,14 +378,14 @@ static void plgpio_irq_handler(struct irq_desc *desc)
chained_irq_enter(irqchip, desc); chained_irq_enter(irqchip, desc);
/* check all plgpio MIS registers for a possible interrupt */ /* check all plgpio MIS registers for a possible interrupt */
for (; i < regs_count; i++) { for (; i < regs_count; i++) {
pending = readl_relaxed(plgpio->base + plgpio->regs.mis + regmap_read(plgpio->regmap, plgpio->regs.mis +
i * sizeof(int *)); i * sizeof(int *), &pending);
if (!pending) if (!pending)
continue; continue;
/* clear interrupts */ /* clear interrupts */
writel_relaxed(~pending, plgpio->base + plgpio->regs.mis + regmap_write(plgpio->regmap, plgpio->regs.mis +
i * sizeof(int *)); i * sizeof(int *), ~pending);
/* /*
* clear extra bits in last register having gpios < MAX/REG * clear extra bits in last register having gpios < MAX/REG
* ex: Suppose there are max 102 plgpios. then last register * ex: Suppose there are max 102 plgpios. then last register
...@@ -389,7 +397,8 @@ static void plgpio_irq_handler(struct irq_desc *desc) ...@@ -389,7 +397,8 @@ static void plgpio_irq_handler(struct irq_desc *desc)
if (count < MAX_GPIO_PER_REG) if (count < MAX_GPIO_PER_REG)
pending &= (1 << count) - 1; pending &= (1 << count) - 1;
for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) { pendingl = pending;
for_each_set_bit(offset, &pendingl, MAX_GPIO_PER_REG) {
/* get correct pin for "offset" */ /* get correct pin for "offset" */
if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) { if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) {
pin = plgpio->o2p(offset); pin = plgpio->o2p(offset);
...@@ -511,6 +520,7 @@ static int plgpio_probe_dt(struct platform_device *pdev, struct plgpio *plgpio) ...@@ -511,6 +520,7 @@ static int plgpio_probe_dt(struct platform_device *pdev, struct plgpio *plgpio)
end: end:
return ret; return ret;
} }
static int plgpio_probe(struct platform_device *pdev) static int plgpio_probe(struct platform_device *pdev)
{ {
struct plgpio *plgpio; struct plgpio *plgpio;
...@@ -520,9 +530,12 @@ static int plgpio_probe(struct platform_device *pdev) ...@@ -520,9 +530,12 @@ static int plgpio_probe(struct platform_device *pdev)
if (!plgpio) if (!plgpio)
return -ENOMEM; return -ENOMEM;
plgpio->base = devm_platform_ioremap_resource(pdev, 0); plgpio->regmap = device_node_to_regmap(pdev->dev.of_node);
if (IS_ERR(plgpio->base)) if (IS_ERR(plgpio->regmap)) {
return PTR_ERR(plgpio->base); dev_err(&pdev->dev, "Init regmap failed (%pe)\n",
plgpio->regmap);
return PTR_ERR(plgpio->regmap);
}
ret = plgpio_probe_dt(pdev, plgpio); ret = plgpio_probe_dt(pdev, plgpio);
if (ret) { if (ret) {
...@@ -607,22 +620,23 @@ static int plgpio_suspend(struct device *dev) ...@@ -607,22 +620,23 @@ static int plgpio_suspend(struct device *dev)
{ {
struct plgpio *plgpio = dev_get_drvdata(dev); struct plgpio *plgpio = dev_get_drvdata(dev);
int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
void __iomem *off; u32 off;
for (i = 0; i < reg_count; i++) { for (i = 0; i < reg_count; i++) {
off = plgpio->base + i * sizeof(int *); off = i * sizeof(int *);
if (plgpio->regs.enb != -1) if (plgpio->regs.enb != -1)
plgpio->csave_regs[i].enb = regmap_read(plgpio->regmap, plgpio->regs.enb + off,
readl_relaxed(plgpio->regs.enb + off); &plgpio->csave_regs[i].enb);
if (plgpio->regs.eit != -1) if (plgpio->regs.eit != -1)
plgpio->csave_regs[i].eit = regmap_read(plgpio->regmap, plgpio->regs.eit + off,
readl_relaxed(plgpio->regs.eit + off); &plgpio->csave_regs[i].eit);
plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata + regmap_read(plgpio->regmap, plgpio->regs.wdata + off,
off); &plgpio->csave_regs[i].wdata);
plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir + regmap_read(plgpio->regmap, plgpio->regs.dir + off,
off); &plgpio->csave_regs[i].dir);
plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off); regmap_read(plgpio->regmap, plgpio->regs.ie + off,
&plgpio->csave_regs[i].ie);
} }
return 0; return 0;
...@@ -636,7 +650,7 @@ static int plgpio_suspend(struct device *dev) ...@@ -636,7 +650,7 @@ static int plgpio_suspend(struct device *dev)
*/ */
#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \ #define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \
{ \ { \
_tmp = readl_relaxed(plgpio->regs.__reg + _off); \ regmap_read(plgpio->regmap, plgpio->regs.__reg + _off, &_tmp); \
_tmp &= ~_mask; \ _tmp &= ~_mask; \
plgpio->csave_regs[i].__reg = \ plgpio->csave_regs[i].__reg = \
_tmp | (plgpio->csave_regs[i].__reg & _mask); \ _tmp | (plgpio->csave_regs[i].__reg & _mask); \
...@@ -646,11 +660,11 @@ static int plgpio_resume(struct device *dev) ...@@ -646,11 +660,11 @@ static int plgpio_resume(struct device *dev)
{ {
struct plgpio *plgpio = dev_get_drvdata(dev); struct plgpio *plgpio = dev_get_drvdata(dev);
int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
void __iomem *off; u32 off;
u32 mask, tmp; u32 mask, tmp;
for (i = 0; i < reg_count; i++) { for (i = 0; i < reg_count; i++) {
off = plgpio->base + i * sizeof(int *); off = i * sizeof(int *);
if (i == reg_count - 1) { if (i == reg_count - 1) {
mask = (1 << (plgpio->chip.ngpio - i * mask = (1 << (plgpio->chip.ngpio - i *
...@@ -667,20 +681,22 @@ static int plgpio_resume(struct device *dev) ...@@ -667,20 +681,22 @@ static int plgpio_resume(struct device *dev)
plgpio_prepare_reg(ie, off, mask, tmp); plgpio_prepare_reg(ie, off, mask, tmp);
} }
writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata + regmap_write(plgpio->regmap, plgpio->regs.wdata + off,
off); plgpio->csave_regs[i].wdata);
writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir +
off); regmap_write(plgpio->regmap, plgpio->regs.dir + off,
plgpio->csave_regs[i].dir);
if (plgpio->regs.eit != -1) if (plgpio->regs.eit != -1)
writel_relaxed(plgpio->csave_regs[i].eit, regmap_write(plgpio->regmap, plgpio->regs.eit + off,
plgpio->regs.eit + off); plgpio->csave_regs[i].eit);
writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off); regmap_write(plgpio->regmap, plgpio->regs.ie + off,
plgpio->csave_regs[i].ie);
if (plgpio->regs.enb != -1) if (plgpio->regs.enb != -1)
writel_relaxed(plgpio->csave_regs[i].enb, regmap_write(plgpio->regmap, plgpio->regs.enb + off,
plgpio->regs.enb + off); plgpio->csave_regs[i].enb);
} }
return 0; return 0;
......
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