gpio: brcmstb: use new generic GPIO chip API

Convert the driver to using the new generic GPIO chip interfaces from
linux/gpio/generic.h.

Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
Acked-by: Doug Berger <opendmb@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20250910-gpio-mmio-gpio-conv-part4-v2-7-f3d1a4c57124@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
This commit is contained in:
Bartosz Golaszewski
2025-09-10 09:12:43 +02:00
parent 36f30f7ffc
commit e8bd2a6a50
+60 -52
View File
@@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/generic.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/irqdomain.h>
@@ -37,7 +38,7 @@ enum gio_reg_index {
struct brcmstb_gpio_bank {
struct list_head node;
int id;
struct gpio_chip gc;
struct gpio_generic_chip chip;
struct brcmstb_gpio_priv *parent_priv;
u32 width;
u32 wake_active;
@@ -72,19 +73,18 @@ __brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
{
void __iomem *reg_base = bank->parent_priv->reg_base;
return bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) &
bank->gc.read_reg(reg_base + GIO_MASK(bank->id));
return gpio_generic_read_reg(&bank->chip, reg_base + GIO_STAT(bank->id)) &
gpio_generic_read_reg(&bank->chip, reg_base + GIO_MASK(bank->id));
}
static unsigned long
brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
{
unsigned long status;
unsigned long flags;
raw_spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
guard(gpio_generic_lock_irqsave)(&bank->chip);
status = __brcmstb_gpio_get_active_irqs(bank);
raw_spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
return status;
}
@@ -92,26 +92,26 @@ brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq,
struct brcmstb_gpio_bank *bank)
{
return hwirq - bank->gc.offset;
return hwirq - bank->chip.gc.offset;
}
static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
unsigned int hwirq, bool enable)
{
struct gpio_chip *gc = &bank->gc;
struct brcmstb_gpio_priv *priv = bank->parent_priv;
u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(hwirq, bank));
u32 imask;
unsigned long flags;
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
guard(gpio_generic_lock_irqsave)(&bank->chip);
imask = gpio_generic_read_reg(&bank->chip,
priv->reg_base + GIO_MASK(bank->id));
if (enable)
imask |= mask;
else
imask &= ~mask;
gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_MASK(bank->id), imask);
}
static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -150,7 +150,8 @@ static void brcmstb_gpio_irq_ack(struct irq_data *d)
struct brcmstb_gpio_priv *priv = bank->parent_priv;
u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank));
gc->write_reg(priv->reg_base + GIO_STAT(bank->id), mask);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_STAT(bank->id), mask);
}
static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
@@ -162,7 +163,6 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
u32 edge_insensitive, iedge_insensitive;
u32 edge_config, iedge_config;
u32 level, ilevel;
unsigned long flags;
switch (type) {
case IRQ_TYPE_LEVEL_LOW:
@@ -194,23 +194,25 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
raw_spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
guard(gpio_generic_lock_irqsave)(&bank->chip);
iedge_config = bank->gc.read_reg(priv->reg_base +
GIO_EC(bank->id)) & ~mask;
iedge_insensitive = bank->gc.read_reg(priv->reg_base +
GIO_EI(bank->id)) & ~mask;
ilevel = bank->gc.read_reg(priv->reg_base +
GIO_LEVEL(bank->id)) & ~mask;
iedge_config = gpio_generic_read_reg(&bank->chip,
priv->reg_base + GIO_EC(bank->id)) & ~mask;
iedge_insensitive = gpio_generic_read_reg(&bank->chip,
priv->reg_base + GIO_EI(bank->id)) & ~mask;
ilevel = gpio_generic_read_reg(&bank->chip,
priv->reg_base + GIO_LEVEL(bank->id)) & ~mask;
bank->gc.write_reg(priv->reg_base + GIO_EC(bank->id),
iedge_config | edge_config);
bank->gc.write_reg(priv->reg_base + GIO_EI(bank->id),
iedge_insensitive | edge_insensitive);
bank->gc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
ilevel | level);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_EC(bank->id),
iedge_config | edge_config);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_EI(bank->id),
iedge_insensitive | edge_insensitive);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_LEVEL(bank->id),
ilevel | level);
raw_spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
return 0;
}
@@ -263,7 +265,7 @@ static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
{
struct brcmstb_gpio_priv *priv = bank->parent_priv;
struct irq_domain *domain = priv->irq_domain;
int hwbase = bank->gc.offset;
int hwbase = bank->chip.gc.offset;
unsigned long status;
while ((status = brcmstb_gpio_get_active_irqs(bank))) {
@@ -303,7 +305,7 @@ static struct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank(
/* banks are in descending order */
list_for_each_entry_reverse(bank, &priv->bank_list, node) {
i += bank->gc.ngpio;
i += bank->chip.gc.ngpio;
if (hwirq < i)
return bank;
}
@@ -332,7 +334,7 @@ static int brcmstb_gpio_irq_map(struct irq_domain *d, unsigned int irq,
dev_dbg(&pdev->dev, "Mapping irq %d for gpio line %d (bank %d)\n",
irq, (int)hwirq, bank->id);
ret = irq_set_chip_data(irq, &bank->gc);
ret = irq_set_chip_data(irq, &bank->chip.gc);
if (ret < 0)
return ret;
irq_set_lockdep_class(irq, &brcmstb_gpio_irq_lock_class,
@@ -394,7 +396,7 @@ static void brcmstb_gpio_remove(struct platform_device *pdev)
* more important to actually perform all of the steps.
*/
list_for_each_entry(bank, &priv->bank_list, node)
gpiochip_remove(&bank->gc);
gpiochip_remove(&bank->chip.gc);
}
static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
@@ -412,7 +414,7 @@ static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
return -EINVAL;
offset = gpiospec->args[0] - bank->gc.offset;
offset = gpiospec->args[0] - bank->chip.gc.offset;
if (offset >= gc->ngpio || offset < 0)
return -EINVAL;
@@ -493,19 +495,17 @@ out_free_domain:
static void brcmstb_gpio_bank_save(struct brcmstb_gpio_priv *priv,
struct brcmstb_gpio_bank *bank)
{
struct gpio_chip *gc = &bank->gc;
unsigned int i;
for (i = 0; i < GIO_REG_STAT; i++)
bank->saved_regs[i] = gc->read_reg(priv->reg_base +
GIO_BANK_OFF(bank->id, i));
bank->saved_regs[i] = gpio_generic_read_reg(&bank->chip,
priv->reg_base + GIO_BANK_OFF(bank->id, i));
}
static void brcmstb_gpio_quiesce(struct device *dev, bool save)
{
struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev);
struct brcmstb_gpio_bank *bank;
struct gpio_chip *gc;
u32 imask;
/* disable non-wake interrupt */
@@ -513,8 +513,6 @@ static void brcmstb_gpio_quiesce(struct device *dev, bool save)
disable_irq(priv->parent_irq);
list_for_each_entry(bank, &priv->bank_list, node) {
gc = &bank->gc;
if (save)
brcmstb_gpio_bank_save(priv, bank);
@@ -523,8 +521,9 @@ static void brcmstb_gpio_quiesce(struct device *dev, bool save)
imask = bank->wake_active;
else
imask = 0;
gc->write_reg(priv->reg_base + GIO_MASK(bank->id),
imask);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_MASK(bank->id),
imask);
}
}
@@ -538,12 +537,12 @@ static void brcmstb_gpio_shutdown(struct platform_device *pdev)
static void brcmstb_gpio_bank_restore(struct brcmstb_gpio_priv *priv,
struct brcmstb_gpio_bank *bank)
{
struct gpio_chip *gc = &bank->gc;
unsigned int i;
for (i = 0; i < GIO_REG_STAT; i++)
gc->write_reg(priv->reg_base + GIO_BANK_OFF(bank->id, i),
bank->saved_regs[i]);
gpio_generic_write_reg(&bank->chip,
priv->reg_base + GIO_BANK_OFF(bank->id, i),
bank->saved_regs[i]);
}
static int brcmstb_gpio_suspend(struct device *dev)
@@ -585,6 +584,7 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
static int brcmstb_gpio_probe(struct platform_device *pdev)
{
struct gpio_generic_chip_config config;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
void __iomem *reg_base;
@@ -665,17 +665,24 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
bank->width = bank_width;
}
gc = &bank->chip.gc;
/*
* Regs are 4 bytes wide, have data reg, no set/clear regs,
* and direction bits have 0 = output and 1 = input
*/
gc = &bank->gc;
err = bgpio_init(gc, dev, 4,
reg_base + GIO_DATA(bank->id),
NULL, NULL, NULL,
reg_base + GIO_IODIR(bank->id), flags);
config = (struct gpio_generic_chip_config) {
.dev = dev,
.sz = 4,
.dat = reg_base + GIO_DATA(bank->id),
.dirin = reg_base + GIO_IODIR(bank->id),
.flags = flags,
};
err = gpio_generic_chip_init(&bank->chip, &config);
if (err) {
dev_err(dev, "bgpio_init() failed\n");
dev_err(dev, "failed to initialize generic GPIO chip\n");
goto fail;
}
@@ -700,7 +707,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
* be retained from S5 cold boot
*/
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
gpio_generic_write_reg(&bank->chip,
reg_base + GIO_MASK(bank->id), 0);
err = gpiochip_add_data(gc, bank);
if (err) {