Commit 0dc17d14 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v3.19-5' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull gpio fixes from Linus Walleij:
 "Yet more GPIO fixes for the v3.19 series.

  There is a high bug-spot activity in GPIO this merge window, much due
  to Johan Hovolds spearheading into actually exercising the removal
  path for GPIO chips, something that was never really exercised before.

  The other two fixes are augmenting erroneous behaviours in two
  specific drivers for minor systems.

  Summary from signed tag:

   - Two fixes stabilizing that which was never stable before: removal
     of GPIO chips, now let's stop leaking memory.
   - Make sure OMAP IRQs are usable when the irqchip API is used
     orthogonally to the gpiochip API.
   - Provide a default GPIO base for the mcp23s08 driver"

* tag 'gpio-v3.19-5' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpio: sysfs: fix memory leak in gpiod_sysfs_set_active_low
  gpio: sysfs: fix memory leak in gpiod_export_link
  gpio: mcp23s08: handle default gpio base
  gpio: omap: Fix bad device access with setup_irq()
parents e36f014e 49d2ca84
...@@ -801,9 +801,11 @@ static int mcp230xx_probe(struct i2c_client *client, ...@@ -801,9 +801,11 @@ static int mcp230xx_probe(struct i2c_client *client,
client->irq = irq_of_parse_and_map(client->dev.of_node, 0); client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
} else { } else {
pdata = dev_get_platdata(&client->dev); pdata = dev_get_platdata(&client->dev);
if (!pdata || !gpio_is_valid(pdata->base)) { if (!pdata) {
dev_dbg(&client->dev, "invalid platform data\n"); pdata = devm_kzalloc(&client->dev,
return -EINVAL; sizeof(struct mcp23s08_platform_data),
GFP_KERNEL);
pdata->base = -1;
} }
} }
...@@ -924,10 +926,11 @@ static int mcp23s08_probe(struct spi_device *spi) ...@@ -924,10 +926,11 @@ static int mcp23s08_probe(struct spi_device *spi)
} else { } else {
type = spi_get_device_id(spi)->driver_data; type = spi_get_device_id(spi)->driver_data;
pdata = dev_get_platdata(&spi->dev); pdata = dev_get_platdata(&spi->dev);
if (!pdata || !gpio_is_valid(pdata->base)) { if (!pdata) {
dev_dbg(&spi->dev, pdata = devm_kzalloc(&spi->dev,
"invalid or missing platform data\n"); sizeof(struct mcp23s08_platform_data),
return -EINVAL; GFP_KERNEL);
pdata->base = -1;
} }
for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
......
...@@ -88,6 +88,8 @@ struct gpio_bank { ...@@ -88,6 +88,8 @@ struct gpio_bank {
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) #define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
#define LINE_USED(line, offset) (line & (BIT(offset))) #define LINE_USED(line, offset) (line & (BIT(offset)))
static void omap_gpio_unmask_irq(struct irq_data *d);
static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
{ {
return bank->chip.base + gpio_irq; return bank->chip.base + gpio_irq;
...@@ -477,6 +479,16 @@ static int omap_gpio_is_input(struct gpio_bank *bank, int mask) ...@@ -477,6 +479,16 @@ static int omap_gpio_is_input(struct gpio_bank *bank, int mask)
return readl_relaxed(reg) & mask; return readl_relaxed(reg) & mask;
} }
static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned gpio,
unsigned offset)
{
if (!LINE_USED(bank->mod_usage, offset)) {
omap_enable_gpio_module(bank, offset);
omap_set_gpio_direction(bank, offset, 1);
}
bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
}
static int omap_gpio_irq_type(struct irq_data *d, unsigned type) static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
{ {
struct gpio_bank *bank = omap_irq_data_get_bank(d); struct gpio_bank *bank = omap_irq_data_get_bank(d);
...@@ -506,15 +518,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) ...@@ -506,15 +518,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
offset = GPIO_INDEX(bank, gpio); offset = GPIO_INDEX(bank, gpio);
retval = omap_set_gpio_triggering(bank, offset, type); retval = omap_set_gpio_triggering(bank, offset, type);
if (!LINE_USED(bank->mod_usage, offset)) { omap_gpio_init_irq(bank, gpio, offset);
omap_enable_gpio_module(bank, offset); if (!omap_gpio_is_input(bank, BIT(offset))) {
omap_set_gpio_direction(bank, offset, 1);
} else if (!omap_gpio_is_input(bank, BIT(offset))) {
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL; return -EINVAL;
} }
bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
...@@ -792,6 +800,24 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -792,6 +800,24 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
pm_runtime_put(bank->dev); pm_runtime_put(bank->dev);
} }
static unsigned int omap_gpio_irq_startup(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
unsigned long flags;
unsigned offset = GPIO_INDEX(bank, gpio);
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
omap_gpio_init_irq(bank, gpio, offset);
spin_unlock_irqrestore(&bank->lock, flags);
omap_gpio_unmask_irq(d);
return 0;
}
static void omap_gpio_irq_shutdown(struct irq_data *d) static void omap_gpio_irq_shutdown(struct irq_data *d)
{ {
struct gpio_bank *bank = omap_irq_data_get_bank(d); struct gpio_bank *bank = omap_irq_data_get_bank(d);
...@@ -1181,6 +1207,7 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1181,6 +1207,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
if (!irqc) if (!irqc)
return -ENOMEM; return -ENOMEM;
irqc->irq_startup = omap_gpio_irq_startup,
irqc->irq_shutdown = omap_gpio_irq_shutdown, irqc->irq_shutdown = omap_gpio_irq_shutdown,
irqc->irq_ack = omap_gpio_ack_irq, irqc->irq_ack = omap_gpio_ack_irq,
irqc->irq_mask = omap_gpio_mask_irq, irqc->irq_mask = omap_gpio_mask_irq,
......
...@@ -648,6 +648,7 @@ int gpiod_export_link(struct device *dev, const char *name, ...@@ -648,6 +648,7 @@ int gpiod_export_link(struct device *dev, const char *name,
if (tdev != NULL) { if (tdev != NULL) {
status = sysfs_create_link(&dev->kobj, &tdev->kobj, status = sysfs_create_link(&dev->kobj, &tdev->kobj,
name); name);
put_device(tdev);
} else { } else {
status = -ENODEV; status = -ENODEV;
} }
...@@ -695,7 +696,7 @@ int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) ...@@ -695,7 +696,7 @@ int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
} }
status = sysfs_set_active_low(desc, dev, value); status = sysfs_set_active_low(desc, dev, value);
put_device(dev);
unlock: unlock:
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
......
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