mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-10 15:19:51 +00:00
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: Herve Codina <herve.codina@bootlin.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Link: https://lore.kernel.org/r/20211202095255.165797-3-herve.codina@bootlin.com Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
d11db044a3
commit
7151cef59e
@ -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 {
|
|||||||
*/
|
*/
|
||||||
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 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
*/
|
*/
|
||||||
#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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user