Skip to content

Commit

Permalink
Merge tag 'gpio-v3.19-5' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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()
  • Loading branch information
Linus Torvalds committed Feb 3, 2015
2 parents e36f014 + 49d2ca8 commit 0dc17d1
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 14 deletions.
17 changes: 10 additions & 7 deletions drivers/gpio/gpio-mcp23s08.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,9 +801,11 @@ static int mcp230xx_probe(struct i2c_client *client,
client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
} else {
pdata = dev_get_platdata(&client->dev);
if (!pdata || !gpio_is_valid(pdata->base)) {
dev_dbg(&client->dev, "invalid platform data\n");
return -EINVAL;
if (!pdata) {
pdata = devm_kzalloc(&client->dev,
sizeof(struct mcp23s08_platform_data),
GFP_KERNEL);
pdata->base = -1;
}
}

Expand Down Expand Up @@ -924,10 +926,11 @@ static int mcp23s08_probe(struct spi_device *spi)
} else {
type = spi_get_device_id(spi)->driver_data;
pdata = dev_get_platdata(&spi->dev);
if (!pdata || !gpio_is_valid(pdata->base)) {
dev_dbg(&spi->dev,
"invalid or missing platform data\n");
return -EINVAL;
if (!pdata) {
pdata = devm_kzalloc(&spi->dev,
sizeof(struct mcp23s08_platform_data),
GFP_KERNEL);
pdata->base = -1;
}

for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
Expand Down
39 changes: 33 additions & 6 deletions drivers/gpio/gpio-omap.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ struct gpio_bank {
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
#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)
{
return bank->chip.base + gpio_irq;
Expand Down Expand Up @@ -477,6 +479,16 @@ static int omap_gpio_is_input(struct gpio_bank *bank, int 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)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
Expand Down Expand Up @@ -506,15 +518,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
spin_lock_irqsave(&bank->lock, flags);
offset = GPIO_INDEX(bank, gpio);
retval = omap_set_gpio_triggering(bank, offset, type);
if (!LINE_USED(bank->mod_usage, offset)) {
omap_enable_gpio_module(bank, offset);
omap_set_gpio_direction(bank, offset, 1);
} else if (!omap_gpio_is_input(bank, BIT(offset))) {
omap_gpio_init_irq(bank, gpio, offset);
if (!omap_gpio_is_input(bank, BIT(offset))) {
spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL;
}

bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
spin_unlock_irqrestore(&bank->lock, flags);

if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
Expand Down Expand Up @@ -792,6 +800,24 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
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)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
Expand Down Expand Up @@ -1181,6 +1207,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
if (!irqc)
return -ENOMEM;

irqc->irq_startup = omap_gpio_irq_startup,
irqc->irq_shutdown = omap_gpio_irq_shutdown,
irqc->irq_ack = omap_gpio_ack_irq,
irqc->irq_mask = omap_gpio_mask_irq,
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpio/gpiolib-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ int gpiod_export_link(struct device *dev, const char *name,
if (tdev != NULL) {
status = sysfs_create_link(&dev->kobj, &tdev->kobj,
name);
put_device(tdev);
} else {
status = -ENODEV;
}
Expand Down Expand Up @@ -695,7 +696,7 @@ int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
}

status = sysfs_set_active_low(desc, dev, value);

put_device(dev);
unlock:
mutex_unlock(&sysfs_lock);

Expand Down

0 comments on commit 0dc17d1

Please sign in to comment.