mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins
The driver assumes that every one of the AIROHA_NUM_PINS GPIOs can raise an interrupt. That holds for the SoCs supported so far, but not for every member of the family: on EN7528 only GPIO0-GPIO15 are wired to the interrupt controller. Without this the driver hands out interrupts for GPIOs that can never fire, and the interrupt handler reads status registers that are not backed by any pin. Add a num_irq_pins field to the per-SoC match data and use it to bound the interrupt callbacks and to size the loop in the interrupt handler. Feed it to gpiolib through gpio_irq_chip::init_valid_mask as well, so that gpiod_to_irq() fails for a pin that cannot be an interrupt source instead of deferring the failure to request_irq(). Signed-off-by: Ahmed Naseef <naseefkm@gmail.com> Reviewed-by: Benjamin Larsson <benjamin.larsson@genexis.eu> Signed-off-by: Linus Walleij <linusw@kernel.org>
This commit is contained in:
parent
cee9395acd
commit
4499389681
|
|
@ -127,6 +127,7 @@ struct airoha_pinctrl {
|
|||
|
||||
struct gpio_chip gpiochip;
|
||||
struct airoha_gpiochip_regs *gpio_regs;
|
||||
unsigned int num_irq_pins;
|
||||
};
|
||||
|
||||
struct airoha_pinctrl_match_data {
|
||||
|
|
@ -140,6 +141,8 @@ struct airoha_pinctrl_match_data {
|
|||
const struct airoha_pinctrl_func *funcs;
|
||||
const unsigned int num_funcs;
|
||||
const struct airoha_pinctrl_confs_info confs_info[AIROHA_PINCTRL_CONFS_MAX];
|
||||
/* number of GPIOs wired to the interrupt controller */
|
||||
const unsigned int num_irq_pins;
|
||||
};
|
||||
|
||||
int airoha_pinctrl_probe(struct platform_device *pdev);
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ static void airoha_irq_unmask(struct irq_data *data)
|
|||
u32 mask = GENMASK(2 * offset + 1, 2 * offset);
|
||||
u32 val = BIT(2 * offset);
|
||||
|
||||
if (WARN_ON_ONCE(data->hwirq >= AIROHA_NUM_PINS))
|
||||
if (WARN_ON_ONCE(data->hwirq >= pinctrl->num_irq_pins))
|
||||
return;
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(data));
|
||||
|
|
@ -249,7 +249,7 @@ static void airoha_irq_mask(struct irq_data *data)
|
|||
u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_PIN;
|
||||
u32 mask = GENMASK(2 * offset + 1, 2 * offset);
|
||||
|
||||
if (data->hwirq >= AIROHA_NUM_PINS)
|
||||
if (data->hwirq >= pinctrl->num_irq_pins)
|
||||
return;
|
||||
|
||||
regmap_clear_bits(pinctrl->regmap, gpio_regs->level[index], mask);
|
||||
|
|
@ -265,7 +265,7 @@ static void airoha_irq_ack(struct irq_data *data)
|
|||
u8 offset = data->hwirq % AIROHA_PIN_BANK_SIZE;
|
||||
u8 index = data->hwirq / AIROHA_PIN_BANK_SIZE;
|
||||
|
||||
if (data->hwirq >= AIROHA_NUM_PINS)
|
||||
if (data->hwirq >= pinctrl->num_irq_pins)
|
||||
return;
|
||||
|
||||
regmap_write(pinctrl->regmap, gpio_regs->status[index], BIT(offset));
|
||||
|
|
@ -273,7 +273,10 @@ static void airoha_irq_ack(struct irq_data *data)
|
|||
|
||||
static int airoha_irq_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
if (data->hwirq >= AIROHA_NUM_PINS)
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
|
||||
|
||||
if (data->hwirq >= pinctrl->num_irq_pins)
|
||||
return -EINVAL;
|
||||
|
||||
if (type == IRQ_TYPE_NONE) {
|
||||
|
|
@ -304,9 +307,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *data)
|
|||
{
|
||||
struct airoha_pinctrl *pinctrl = data;
|
||||
bool handled = false;
|
||||
unsigned int nbanks;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) {
|
||||
nbanks = DIV_ROUND_UP(pinctrl->num_irq_pins, AIROHA_PIN_BANK_SIZE);
|
||||
for (i = 0; i < nbanks; i++) {
|
||||
struct gpio_irq_chip *girq = &pinctrl->gpiochip.irq;
|
||||
u32 regmap;
|
||||
unsigned long status;
|
||||
|
|
@ -340,6 +345,22 @@ static const struct irq_chip airoha_gpio_irq_chip = {
|
|||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Mark the GPIOs that are not wired to the interrupt controller as not
|
||||
* valid, so that gpiod_to_irq() fails for them with -ENXIO instead of
|
||||
* handing out an interrupt that can never fire.
|
||||
*/
|
||||
static void airoha_gpio_init_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
|
||||
unsigned int num_irq_pins = pinctrl->num_irq_pins;
|
||||
|
||||
if (num_irq_pins < ngpios)
|
||||
bitmap_clear(valid_mask, num_irq_pins, ngpios - num_irq_pins);
|
||||
}
|
||||
|
||||
static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -362,6 +383,7 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
|
|||
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->init_valid_mask = airoha_gpio_init_valid_mask;
|
||||
gpio_irq_chip_set_chip(girq, &airoha_gpio_irq_chip);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
|
@ -848,6 +870,7 @@ int airoha_pinctrl_probe(struct platform_device *pdev)
|
|||
pinctrl->grps = data->grps;
|
||||
pinctrl->funcs = data->funcs;
|
||||
pinctrl->confs_info = data->confs_info;
|
||||
pinctrl->num_irq_pins = data->num_irq_pins;
|
||||
|
||||
err = pinctrl_enable(pinctrl->ctrl);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -1069,6 +1069,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
|
|||
.num_grps = ARRAY_SIZE(pinctrl_groups),
|
||||
.funcs = pinctrl_funcs,
|
||||
.num_funcs = ARRAY_SIZE(pinctrl_funcs),
|
||||
.num_irq_pins = AIROHA_NUM_PINS,
|
||||
.confs_info = {
|
||||
[AIROHA_PINCTRL_CONFS_PULLUP] = {
|
||||
.confs = pinctrl_pullup_conf,
|
||||
|
|
|
|||
|
|
@ -1441,6 +1441,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
|
|||
.num_grps = ARRAY_SIZE(pinctrl_groups),
|
||||
.funcs = pinctrl_funcs,
|
||||
.num_funcs = ARRAY_SIZE(pinctrl_funcs),
|
||||
.num_irq_pins = AIROHA_NUM_PINS,
|
||||
.confs_info = {
|
||||
[AIROHA_PINCTRL_CONFS_PULLUP] = {
|
||||
.confs = pinctrl_pullup_conf,
|
||||
|
|
|
|||
|
|
@ -1471,6 +1471,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
|
|||
.num_grps = ARRAY_SIZE(pinctrl_groups),
|
||||
.funcs = pinctrl_funcs,
|
||||
.num_funcs = ARRAY_SIZE(pinctrl_funcs),
|
||||
.num_irq_pins = AIROHA_NUM_PINS,
|
||||
.confs_info = {
|
||||
[AIROHA_PINCTRL_CONFS_PULLUP] = {
|
||||
.confs = pinctrl_pullup_conf,
|
||||
|
|
|
|||
|
|
@ -1113,6 +1113,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
|
|||
.num_grps = ARRAY_SIZE(pinctrl_groups),
|
||||
.funcs = pinctrl_funcs,
|
||||
.num_funcs = ARRAY_SIZE(pinctrl_funcs),
|
||||
.num_irq_pins = AIROHA_NUM_PINS,
|
||||
.confs_info = {
|
||||
[AIROHA_PINCTRL_CONFS_PULLUP] = {
|
||||
.confs = pinctrl_pullup_conf,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user