diff options
Diffstat (limited to 'drivers/gpio/gpio-mcp23s08.c')
| -rw-r--r-- | drivers/gpio/gpio-mcp23s08.c | 111 | 
1 files changed, 34 insertions, 77 deletions
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 47e486910aab..ac22efc1840e 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -77,7 +77,6 @@ struct mcp23s08 {  	/* lock protects the cached values */  	struct mutex		lock;  	struct mutex		irq_lock; -	struct irq_domain	*irq_domain;  	struct gpio_chip	chip; @@ -96,11 +95,6 @@ struct mcp23s08_driver_data {  	struct mcp23s08		chip[];  }; -/* This lock class tells lockdep that GPIO irqs are in a different - * category than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; -  /*----------------------------------------------------------------------*/  #if IS_ENABLED(CONFIG_I2C) @@ -368,8 +362,9 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)  	for (i = 0; i < mcp->chip.ngpio; i++) {  		if ((BIT(i) & mcp->cache[MCP_INTF]) &&  		    ((BIT(i) & intcap & mcp->irq_rise) || -		     (mcp->irq_fall & ~intcap & BIT(i)))) { -			child_irq = irq_find_mapping(mcp->irq_domain, i); +		     (mcp->irq_fall & ~intcap & BIT(i)) || +		     (BIT(i) & mcp->cache[MCP_INTCON]))) { +			child_irq = irq_find_mapping(mcp->chip.irqdomain, i);  			handle_nested_irq(child_irq);  		}  	} @@ -377,16 +372,10 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)  	return IRQ_HANDLED;  } -static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ -	struct mcp23s08 *mcp = gpiochip_get_data(chip); - -	return irq_find_mapping(mcp->irq_domain, offset); -} -  static void mcp23s08_irq_mask(struct irq_data *data)  { -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data); +	struct mcp23s08 *mcp = gpiochip_get_data(gc);  	unsigned int pos = data->hwirq;  	mcp->cache[MCP_GPINTEN] &= ~BIT(pos); @@ -394,7 +383,8 @@ static void mcp23s08_irq_mask(struct irq_data *data)  static void mcp23s08_irq_unmask(struct irq_data *data)  { -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data); +	struct mcp23s08 *mcp = gpiochip_get_data(gc);  	unsigned int pos = data->hwirq;  	mcp->cache[MCP_GPINTEN] |= BIT(pos); @@ -402,7 +392,8 @@ static void mcp23s08_irq_unmask(struct irq_data *data)  static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)  { -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data); +	struct mcp23s08 *mcp = gpiochip_get_data(gc);  	unsigned int pos = data->hwirq;  	int status = 0; @@ -418,6 +409,12 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)  		mcp->cache[MCP_INTCON] &= ~BIT(pos);  		mcp->irq_rise &= ~BIT(pos);  		mcp->irq_fall |= BIT(pos); +	} else if (type & IRQ_TYPE_LEVEL_HIGH) { +		mcp->cache[MCP_INTCON] |= BIT(pos); +		mcp->cache[MCP_DEFVAL] &= ~BIT(pos); +	} else if (type & IRQ_TYPE_LEVEL_LOW) { +		mcp->cache[MCP_INTCON] |= BIT(pos); +		mcp->cache[MCP_DEFVAL] |= BIT(pos);  	} else  		return -EINVAL; @@ -426,14 +423,16 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)  static void mcp23s08_irq_bus_lock(struct irq_data *data)  { -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data); +	struct mcp23s08 *mcp = gpiochip_get_data(gc);  	mutex_lock(&mcp->irq_lock);  }  static void mcp23s08_irq_bus_unlock(struct irq_data *data)  { -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data); +	struct mcp23s08 *mcp = gpiochip_get_data(gc);  	mutex_lock(&mcp->lock);  	mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); @@ -443,27 +442,6 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data)  	mutex_unlock(&mcp->irq_lock);  } -static int mcp23s08_irq_reqres(struct irq_data *data) -{ -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - -	if (gpiochip_lock_as_irq(&mcp->chip, data->hwirq)) { -		dev_err(mcp->chip.parent, -			"unable to lock HW IRQ %lu for IRQ usage\n", -			data->hwirq); -		return -EINVAL; -	} - -	return 0; -} - -static void mcp23s08_irq_relres(struct irq_data *data) -{ -	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - -	gpiochip_unlock_as_irq(&mcp->chip, data->hwirq); -} -  static struct irq_chip mcp23s08_irq_chip = {  	.name = "gpio-mcp23xxx",  	.irq_mask = mcp23s08_irq_mask, @@ -471,24 +449,16 @@ static struct irq_chip mcp23s08_irq_chip = {  	.irq_set_type = mcp23s08_irq_set_type,  	.irq_bus_lock = mcp23s08_irq_bus_lock,  	.irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, -	.irq_request_resources = mcp23s08_irq_reqres, -	.irq_release_resources = mcp23s08_irq_relres,  };  static int mcp23s08_irq_setup(struct mcp23s08 *mcp)  {  	struct gpio_chip *chip = &mcp->chip; -	int err, irq, j; +	int err;  	unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED;  	mutex_init(&mcp->irq_lock); -	mcp->irq_domain = irq_domain_add_linear(chip->parent->of_node, -						chip->ngpio, -						&irq_domain_simple_ops, mcp); -	if (!mcp->irq_domain) -		return -ENODEV; -  	if (mcp->irq_active_high)  		irqflags |= IRQF_TRIGGER_HIGH;  	else @@ -503,30 +473,23 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)  		return err;  	} -	chip->to_irq = mcp23s08_gpio_to_irq; - -	for (j = 0; j < mcp->chip.ngpio; j++) { -		irq = irq_create_mapping(mcp->irq_domain, j); -		irq_set_lockdep_class(irq, &gpio_lock_class); -		irq_set_chip_data(irq, mcp); -		irq_set_chip(irq, &mcp23s08_irq_chip); -		irq_set_nested_thread(irq, true); -		irq_set_noprobe(irq); +	err =  gpiochip_irqchip_add(chip, +				    &mcp23s08_irq_chip, +				    0, +				    handle_simple_irq, +				    IRQ_TYPE_NONE); +	if (err) { +		dev_err(chip->parent, +			"could not connect irqchip to gpiochip: %d\n", err); +		return err;  	} -	return 0; -} -static void mcp23s08_irq_teardown(struct mcp23s08 *mcp) -{ -	unsigned int irq, i; +	gpiochip_set_chained_irqchip(chip, +				     &mcp23s08_irq_chip, +				     mcp->irq, +				     NULL); -	for (i = 0; i < mcp->chip.ngpio; i++) { -		irq = irq_find_mapping(mcp->irq_domain, i); -		if (irq > 0) -			irq_dispose_mapping(irq); -	} - -	irq_domain_remove(mcp->irq_domain); +	return 0;  }  /*----------------------------------------------------------------------*/ @@ -721,7 +684,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,  	if (mcp->irq && mcp->irq_controller) {  		status = mcp23s08_irq_setup(mcp);  		if (status) { -			mcp23s08_irq_teardown(mcp);  			goto fail;  		}  	} @@ -847,9 +809,6 @@ static int mcp230xx_remove(struct i2c_client *client)  {  	struct mcp23s08 *mcp = i2c_get_clientdata(client); -	if (client->irq && mcp->irq_controller) -		mcp23s08_irq_teardown(mcp); -  	gpiochip_remove(&mcp->chip);  	kfree(mcp); @@ -1017,8 +976,6 @@ static int mcp23s08_remove(struct spi_device *spi)  		if (!data->mcp[addr])  			continue; -		if (spi->irq && data->mcp[addr]->irq_controller) -			mcp23s08_irq_teardown(data->mcp[addr]);  		gpiochip_remove(&data->mcp[addr]->chip);  	}  |