提交 41c64bb1 编写于 作者: L Linus Torvalds

Merge tag 'gpio-v4.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO fixes from Linus Walleij:
 "Here is a bunch of GPIO fixes that I collected since -rc1, nothing
  controversial, nothing special:

   - fix a memory leak for GPIO hotplug.

   - fix a signedness bug in the ACPI GPIO pin validation.

   - driver fixes: Qualcomm SPMI and OMAP MPUIO IRQ issues"

* tag 'gpio-v4.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpio: omap: Fix regression for MPUIO interrupts
  gpio: sysfs: fix memory leaks and device hotplug
  pinctrl: qcom-spmi-gpio: Fix input value report
  pinctrl: qcom-spmi-gpio: Fix output type configuration
  gpiolib: change gpio pin from unsigned to signed in acpi callback
...@@ -1054,38 +1054,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) ...@@ -1054,38 +1054,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
dev_err(bank->dev, "Could not get gpio dbck\n"); dev_err(bank->dev, "Could not get gpio dbck\n");
} }
static void
omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
unsigned int num)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
gc = irq_alloc_generic_chip("MPUIO", 1, irq_start, bank->base,
handle_simple_irq);
if (!gc) {
dev_err(bank->dev, "Memory alloc failed for gc\n");
return;
}
ct = gc->chip_types;
/* NOTE: No ack required, reading IRQ status clears it. */
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->chip.irq_set_type = omap_gpio_irq_type;
if (bank->regs->wkup_en)
ct->chip.irq_set_wake = omap_gpio_wake_enable;
ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
{ {
int j;
static int gpio; static int gpio;
int irq_base = 0; int irq_base = 0;
int ret; int ret;
...@@ -1132,6 +1102,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) ...@@ -1132,6 +1102,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
} }
#endif #endif
/* MPUIO is a bit different, reading IRQ status clears it */
if (bank->is_mpuio) {
irqc->irq_ack = dummy_irq_chip.irq_ack;
irqc->irq_mask = irq_gc_mask_set_bit;
irqc->irq_unmask = irq_gc_mask_clr_bit;
if (!bank->regs->wkup_en)
irqc->irq_set_wake = NULL;
}
ret = gpiochip_irqchip_add(&bank->chip, irqc, ret = gpiochip_irqchip_add(&bank->chip, irqc,
irq_base, omap_gpio_irq_handler, irq_base, omap_gpio_irq_handler,
IRQ_TYPE_NONE); IRQ_TYPE_NONE);
...@@ -1145,15 +1124,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) ...@@ -1145,15 +1124,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
gpiochip_set_chained_irqchip(&bank->chip, irqc, gpiochip_set_chained_irqchip(&bank->chip, irqc,
bank->irq, omap_gpio_irq_handler); bank->irq, omap_gpio_irq_handler);
for (j = 0; j < bank->width; j++) {
int irq = irq_find_mapping(bank->chip.irqdomain, j);
if (bank->is_mpuio) {
omap_mpuio_alloc_gc(bank, irq, bank->width);
irq_set_chip_and_handler(irq, NULL, NULL);
set_irq_flags(irq, 0);
}
}
return 0; return 0;
} }
......
...@@ -550,7 +550,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, ...@@ -550,7 +550,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
length = min(agpio->pin_table_length, (u16)(pin_index + bits)); length = min(agpio->pin_table_length, (u16)(pin_index + bits));
for (i = pin_index; i < length; ++i) { for (i = pin_index; i < length; ++i) {
unsigned pin = agpio->pin_table[i]; int pin = agpio->pin_table[i];
struct acpi_gpio_connection *conn; struct acpi_gpio_connection *conn;
struct gpio_desc *desc; struct gpio_desc *desc;
bool found; bool found;
......
...@@ -551,6 +551,7 @@ static struct class gpio_class = { ...@@ -551,6 +551,7 @@ static struct class gpio_class = {
*/ */
int gpiod_export(struct gpio_desc *desc, bool direction_may_change) int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{ {
struct gpio_chip *chip;
unsigned long flags; unsigned long flags;
int status; int status;
const char *ioname = NULL; const char *ioname = NULL;
...@@ -568,8 +569,16 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ...@@ -568,8 +569,16 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
return -EINVAL; return -EINVAL;
} }
chip = desc->chip;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
/* check if chip is being removed */
if (!chip || !chip->exported) {
status = -ENODEV;
goto fail_unlock;
}
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!test_bit(FLAG_REQUESTED, &desc->flags) || if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) { test_bit(FLAG_EXPORT, &desc->flags)) {
...@@ -783,12 +792,15 @@ void gpiochip_unexport(struct gpio_chip *chip) ...@@ -783,12 +792,15 @@ void gpiochip_unexport(struct gpio_chip *chip)
{ {
int status; int status;
struct device *dev; struct device *dev;
struct gpio_desc *desc;
unsigned int i;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
dev = class_find_device(&gpio_class, NULL, chip, match_export); dev = class_find_device(&gpio_class, NULL, chip, match_export);
if (dev) { if (dev) {
put_device(dev); put_device(dev);
device_unregister(dev); device_unregister(dev);
/* prevent further gpiod exports */
chip->exported = false; chip->exported = false;
status = 0; status = 0;
} else } else
...@@ -797,6 +809,13 @@ void gpiochip_unexport(struct gpio_chip *chip) ...@@ -797,6 +809,13 @@ void gpiochip_unexport(struct gpio_chip *chip)
if (status) if (status)
chip_dbg(chip, "%s: status %d\n", __func__, status); chip_dbg(chip, "%s: status %d\n", __func__, status);
/* unregister gpiod class devices owned by sysfs */
for (i = 0; i < chip->ngpio; i++) {
desc = &chip->desc[i];
if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
gpiod_free(desc);
}
} }
static int __init gpiolib_sysfs_init(void) static int __init gpiolib_sysfs_init(void)
......
...@@ -418,7 +418,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -418,7 +418,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
return ret; return ret;
val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT; val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT;
val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; val |= pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val); ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val);
if (ret < 0) if (ret < 0)
...@@ -467,13 +467,14 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, ...@@ -467,13 +467,14 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
seq_puts(s, " ---"); seq_puts(s, " ---");
} else { } else {
if (!pad->input_enabled) { if (pad->input_enabled) {
ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
if (!ret) { if (ret < 0)
return;
ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
pad->out_value = ret; pad->out_value = ret;
} }
}
seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]); seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册