summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-04-09 13:28:50 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2016-04-09 13:28:50 -0700
commit289b7bfd483c8ca3dfde92d7e19a8b70e0b81248 (patch)
tree364c942c06a31305da5b3932fb064a63166ddad0
parent183c948a3cb3efbf45eabed41fa7ee04c19378fc (diff)
parent9b8e3ec34318663affced3c14d960e78d760dd9a (diff)
downloadop-kernel-dev-289b7bfd483c8ca3dfde92d7e19a8b70e0b81248.zip
op-kernel-dev-289b7bfd483c8ca3dfde92d7e19a8b70e0b81248.tar.gz
Merge tag 'gpio-v4.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO fixes from Linus Walleij: "Here is a set of four GPIO fixes. The two fixes to the core are serious as they are regressing minor architectures. Core fixes: - Defer GPIO device setup until after gpiolib is initialized. It turns out that a few very tightly integrated GPIO platform drivers initialize so early (befor core_initcall()) so that the gpiolib isn't even initialized itself. That limits what the library can do, and we cannot reference uninitialized fields until later. Defer some of the initialization until right after the gpiolib is initialized in these (rare) cases. - As a consequence: do not use devm_* resources when allocating the states in the initial set-up of the gpiochip. Driver fixes: - In ACPI retrieveal: ignore GpioInt when looking for output GPIOs. - Fix legacy builds on the PXA without a backing pin controller. - Use correct datatype on pca953x register writes" * tag 'gpio-v4.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: gpio: pca953x: Use correct u16 value for register word write gpiolib: Defer gpio device setup until after gpiolib initialization gpiolib: Do not use devm functions when registering gpio chip gpio: pxa: fix legacy non pinctrl aware builds gpio / ACPI: ignore GpioInt() GPIOs when requesting GPIO_OUT_*
-rw-r--r--drivers/gpio/gpio-pca953x.c3
-rw-r--r--drivers/gpio/gpio-pxa.c4
-rw-r--r--drivers/gpio/gpiolib.c133
3 files changed, 95 insertions, 45 deletions
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index d0d3065..e66084c 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/platform_data/pca953x.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
#include <linux/of_platform.h>
#include <linux/acpi.h>
@@ -159,7 +160,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
switch (chip->chip_type) {
case PCA953X_TYPE:
ret = i2c_smbus_write_word_data(chip->client,
- reg << 1, (u16) *val);
+ reg << 1, cpu_to_le16(get_unaligned((u16 *)val)));
break;
case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index b2b7b78..76ac906 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -283,8 +283,8 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
ret = pinctrl_gpio_direction_output(chip->base + offset);
- if (!ret)
- return 0;
+ if (ret)
+ return ret;
spin_lock_irqsave(&gpio_lock, flags);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 7206553..b747c76 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -68,6 +68,7 @@ LIST_HEAD(gpio_devices);
static void gpiochip_free_hogs(struct gpio_chip *chip);
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+static bool gpiolib_initialized;
static inline void desc_set_label(struct gpio_desc *d, const char *label)
{
@@ -440,9 +441,63 @@ static void gpiodevice_release(struct device *dev)
cdev_del(&gdev->chrdev);
list_del(&gdev->list);
ida_simple_remove(&gpio_ida, gdev->id);
+ kfree(gdev->label);
+ kfree(gdev->descs);
kfree(gdev);
}
+static int gpiochip_setup_dev(struct gpio_device *gdev)
+{
+ int status;
+
+ cdev_init(&gdev->chrdev, &gpio_fileops);
+ gdev->chrdev.owner = THIS_MODULE;
+ gdev->chrdev.kobj.parent = &gdev->dev.kobj;
+ gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
+ status = cdev_add(&gdev->chrdev, gdev->dev.devt, 1);
+ if (status < 0)
+ chip_warn(gdev->chip, "failed to add char device %d:%d\n",
+ MAJOR(gpio_devt), gdev->id);
+ else
+ chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n",
+ MAJOR(gpio_devt), gdev->id);
+ status = device_add(&gdev->dev);
+ if (status)
+ goto err_remove_chardev;
+
+ status = gpiochip_sysfs_register(gdev);
+ if (status)
+ goto err_remove_device;
+
+ /* From this point, the .release() function cleans up gpio_device */
+ gdev->dev.release = gpiodevice_release;
+ get_device(&gdev->dev);
+ pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n",
+ __func__, gdev->base, gdev->base + gdev->ngpio - 1,
+ dev_name(&gdev->dev), gdev->chip->label ? : "generic");
+
+ return 0;
+
+err_remove_device:
+ device_del(&gdev->dev);
+err_remove_chardev:
+ cdev_del(&gdev->chrdev);
+ return status;
+}
+
+static void gpiochip_setup_devs(void)
+{
+ struct gpio_device *gdev;
+ int err;
+
+ list_for_each_entry(gdev, &gpio_devices, list) {
+ err = gpiochip_setup_dev(gdev);
+ if (err)
+ pr_err("%s: Failed to initialize gpio device (%d)\n",
+ dev_name(&gdev->dev), err);
+ }
+}
+
/**
* gpiochip_add_data() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
@@ -457,6 +512,9 @@ static void gpiodevice_release(struct device *dev)
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
* for GPIOs will fail rudely.
*
+ * gpiochip_add_data() must only be called after gpiolib initialization,
+ * ie after core_initcall().
+ *
* If chip->base is negative, this requests dynamic assignment of
* a range of valid GPIOs.
*/
@@ -504,8 +562,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
else
gdev->owner = THIS_MODULE;
- gdev->descs = devm_kcalloc(&gdev->dev, chip->ngpio,
- sizeof(gdev->descs[0]), GFP_KERNEL);
+ gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
if (!gdev->descs) {
status = -ENOMEM;
goto err_free_gdev;
@@ -514,16 +571,16 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
if (chip->ngpio == 0) {
chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
status = -EINVAL;
- goto err_free_gdev;
+ goto err_free_descs;
}
if (chip->label)
- gdev->label = devm_kstrdup(&gdev->dev, chip->label, GFP_KERNEL);
+ gdev->label = kstrdup(chip->label, GFP_KERNEL);
else
- gdev->label = devm_kstrdup(&gdev->dev, "unknown", GFP_KERNEL);
+ gdev->label = kstrdup("unknown", GFP_KERNEL);
if (!gdev->label) {
status = -ENOMEM;
- goto err_free_gdev;
+ goto err_free_descs;
}
gdev->ngpio = chip->ngpio;
@@ -543,7 +600,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
if (base < 0) {
status = base;
spin_unlock_irqrestore(&gpio_lock, flags);
- goto err_free_gdev;
+ goto err_free_label;
}
/*
* TODO: it should not be necessary to reflect the assigned
@@ -558,7 +615,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
status = gpiodev_add_to_list(gdev);
if (status) {
spin_unlock_irqrestore(&gpio_lock, flags);
- goto err_free_gdev;
+ goto err_free_label;
}
for (i = 0; i < chip->ngpio; i++) {
@@ -596,39 +653,16 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
* we get a device node entry in sysfs under
* /sys/bus/gpio/devices/gpiochipN/dev that can be used for
* coldplug of device nodes and other udev business.
+ * We can do this only if gpiolib has been initialized.
+ * Otherwise, defer until later.
*/
- cdev_init(&gdev->chrdev, &gpio_fileops);
- gdev->chrdev.owner = THIS_MODULE;
- gdev->chrdev.kobj.parent = &gdev->dev.kobj;
- gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
- status = cdev_add(&gdev->chrdev, gdev->dev.devt, 1);
- if (status < 0)
- chip_warn(chip, "failed to add char device %d:%d\n",
- MAJOR(gpio_devt), gdev->id);
- else
- chip_dbg(chip, "added GPIO chardev (%d:%d)\n",
- MAJOR(gpio_devt), gdev->id);
- status = device_add(&gdev->dev);
- if (status)
- goto err_remove_chardev;
-
- status = gpiochip_sysfs_register(gdev);
- if (status)
- goto err_remove_device;
-
- /* From this point, the .release() function cleans up gpio_device */
- gdev->dev.release = gpiodevice_release;
- get_device(&gdev->dev);
- pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n",
- __func__, gdev->base, gdev->base + gdev->ngpio - 1,
- dev_name(&gdev->dev), chip->label ? : "generic");
-
+ if (gpiolib_initialized) {
+ status = gpiochip_setup_dev(gdev);
+ if (status)
+ goto err_remove_chip;
+ }
return 0;
-err_remove_device:
- device_del(&gdev->dev);
-err_remove_chardev:
- cdev_del(&gdev->chrdev);
err_remove_chip:
acpi_gpiochip_remove(chip);
gpiochip_free_hogs(chip);
@@ -637,6 +671,10 @@ err_remove_from_list:
spin_lock_irqsave(&gpio_lock, flags);
list_del(&gdev->list);
spin_unlock_irqrestore(&gpio_lock, flags);
+err_free_label:
+ kfree(gdev->label);
+err_free_descs:
+ kfree(gdev->descs);
err_free_gdev:
ida_simple_remove(&gpio_ida, gdev->id);
/* failures here can mean systems won't boot... */
@@ -2231,9 +2269,11 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
return desc;
}
-static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
+static struct gpio_desc *acpi_find_gpio(struct device *dev,
+ const char *con_id,
unsigned int idx,
- enum gpio_lookup_flags *flags)
+ enum gpiod_flags flags,
+ enum gpio_lookup_flags *lookupflags)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
@@ -2264,10 +2304,16 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
+
+ if ((flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH) &&
+ info.gpioint) {
+ dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n");
+ return ERR_PTR(-ENOENT);
+ }
}
if (info.polarity == GPIO_ACTIVE_LOW)
- *flags |= GPIO_ACTIVE_LOW;
+ *lookupflags |= GPIO_ACTIVE_LOW;
return desc;
}
@@ -2530,7 +2576,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
desc = of_find_gpio(dev, con_id, idx, &lookupflags);
} else if (ACPI_COMPANION(dev)) {
dev_dbg(dev, "using ACPI for GPIO lookup\n");
- desc = acpi_find_gpio(dev, con_id, idx, &lookupflags);
+ desc = acpi_find_gpio(dev, con_id, idx, flags, &lookupflags);
}
}
@@ -2829,6 +2875,9 @@ static int __init gpiolib_dev_init(void)
if (ret < 0) {
pr_err("gpiolib: failed to allocate char dev region\n");
bus_unregister(&gpio_bus_type);
+ } else {
+ gpiolib_initialized = true;
+ gpiochip_setup_devs();
}
return ret;
}
OpenPOWER on IntegriCloud