From 9e80f9064e73f9f82679884ddf8b03ac3606cf4a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 21 Oct 2016 11:09:58 +0200 Subject: pinctrl: Add SX150X GPIO Extender Pinctrl Driver Since the I2C sx150x GPIO expander driver uses platform_data to manage the pins configurations, rewrite the driver as a pinctrl driver using pinconf to get/set pin configurations from DT or debugfs. The pinctrl driver is functionnally equivalent as the gpio-only driver and can use DT for pinconf. The platform_data confirmation is dropped. This patchset removed the gpio-only driver and selects the Pinctrl driver config instead. This patchset also migrates the gpio dt-bindings to pinctrl and add the pinctrl optional properties. The driver was tested with a SX1509 device on a BeagleBone black with interrupt support and on an X86_64 machine over an I2C to USB converter. This is a fixed version that builds and runs on non-OF platforms and on arm based OF. The GPIO version is removed and the bindings are also moved to the pinctrl bindings. Changes since v2 - rebased on v4.9-rc1 - removed MODULE_DEVICE_TABLE as in upstream bb411e771b0e ("gpio: sx150x: fix implicit assumption module.h is present") Changes since v1 - Fix Kconfig descriptions on pinctrl and gpio - Fix Kconfig dependency - Remove oscio support for non-789 devices - correct typo in dt bindings - remove probe reset for non-789 devices Changes since RFC - Put #ifdef CONFIG_OF/CONFIG_OF_GPIO to remove OF code for non-of platforms - No more rely on OF_GPIO config - Moved and enhanced bindings to pinctrl bindings - Removed gpio-sx150x.c - Temporary select PINCTRL_SX150X when GPIO_SX150X - Temporary mark GPIO_SX150X as deprecated Signed-off-by: Neil Armstrong Tested-by: Peter Rosin Acked-by: Rob Herring ested-by: Andrey Smirnov Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 13 +- drivers/gpio/Makefile | 1 - drivers/gpio/gpio-sx150x.c | 792 --------------------------------------------- 3 files changed, 5 insertions(+), 801 deletions(-) delete mode 100644 drivers/gpio/gpio-sx150x.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 26ee00f6bd58..db3f7aab4160 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -781,16 +781,13 @@ config GPIO_PCF857X platform-neutral GPIO calls. config GPIO_SX150X - bool "Semtech SX150x I2C GPIO expander" - depends on I2C=y - select GPIOLIB_IRQCHIP + bool "Semtech SX150x I2C GPIO expander (deprecated)" + depends on PINCTRL && I2C=y + select PINCTRL_SX150X default n help - Say yes here to provide support for Semtech SX150-series I2C - GPIO expanders. Compatible models include: - - 8 bits: sx1508q - 16 bits: sx1509q + Say yes here to provide support for Semtech SX150x-series I2C + GPIO expanders. The GPIO driver was replaced by a Pinctrl version. config GPIO_TPIC2810 tristate "TPIC2810 8-Bit I2C GPO expander" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ab28a2daeacc..76c7af6c5839 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -102,7 +102,6 @@ obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o -obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c deleted file mode 100644 index af95de89db01..000000000000 --- a/drivers/gpio/gpio-sx150x.c +++ /dev/null @@ -1,792 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * Driver for Semtech SX150X I2C GPIO Expanders - * - * Author: Gregory Bean - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NO_UPDATE_PENDING -1 - -/* The chip models of sx150x */ -#define SX150X_123 0 -#define SX150X_456 1 -#define SX150X_789 2 - -struct sx150x_123_pri { - u8 reg_pld_mode; - u8 reg_pld_table0; - u8 reg_pld_table1; - u8 reg_pld_table2; - u8 reg_pld_table3; - u8 reg_pld_table4; - u8 reg_advance; -}; - -struct sx150x_456_pri { - u8 reg_pld_mode; - u8 reg_pld_table0; - u8 reg_pld_table1; - u8 reg_pld_table2; - u8 reg_pld_table3; - u8 reg_pld_table4; - u8 reg_advance; -}; - -struct sx150x_789_pri { - u8 reg_drain; - u8 reg_polarity; - u8 reg_clock; - u8 reg_misc; - u8 reg_reset; - u8 ngpios; -}; - -struct sx150x_device_data { - u8 model; - u8 reg_pullup; - u8 reg_pulldn; - u8 reg_dir; - u8 reg_data; - u8 reg_irq_mask; - u8 reg_irq_src; - u8 reg_sense; - u8 ngpios; - union { - struct sx150x_123_pri x123; - struct sx150x_456_pri x456; - struct sx150x_789_pri x789; - } pri; -}; - -/** - * struct sx150x_platform_data - config data for SX150x driver - * @gpio_base: The index number of the first GPIO assigned to this - * GPIO expander. The expander will create a block of - * consecutively numbered gpios beginning at the given base, - * with the size of the block depending on the model of the - * expander chip. - * @oscio_is_gpo: If set to true, the driver will configure OSCIO as a GPO - * instead of as an oscillator, increasing the size of the - * GP(I)O pool created by this expander by one. The - * output-only GPO pin will be added at the end of the block. - * @io_pullup_ena: A bit-mask which enables or disables the pull-up resistor - * for each IO line in the expander. Setting the bit at - * position n will enable the pull-up for the IO at - * the corresponding offset. For chips with fewer than - * 16 IO pins, high-end bits are ignored. - * @io_pulldn_ena: A bit-mask which enables-or disables the pull-down - * resistor for each IO line in the expander. Setting the - * bit at position n will enable the pull-down for the IO at - * the corresponding offset. For chips with fewer than - * 16 IO pins, high-end bits are ignored. - * @io_polarity: A bit-mask which enables polarity inversion for each IO line - * in the expander. Setting the bit at position n inverts - * the polarity of that IO line, while clearing it results - * in normal polarity. For chips with fewer than 16 IO pins, - * high-end bits are ignored. - * @irq_summary: The 'summary IRQ' line to which the GPIO expander's INT line - * is connected, via which it reports interrupt events - * across all GPIO lines. This must be a real, - * pre-existing IRQ line. - * Setting this value < 0 disables the irq_chip functionality - * of the driver. - * @irq_base: The first 'virtual IRQ' line at which our block of GPIO-based - * IRQ lines will appear. Similarly to gpio_base, the expander - * will create a block of irqs beginning at this number. - * This value is ignored if irq_summary is < 0. - * @reset_during_probe: If set to true, the driver will trigger a full - * reset of the chip at the beginning of the probe - * in order to place it in a known state. - */ -struct sx150x_platform_data { - unsigned gpio_base; - bool oscio_is_gpo; - u16 io_pullup_ena; - u16 io_pulldn_ena; - u16 io_polarity; - int irq_summary; - unsigned irq_base; - bool reset_during_probe; -}; - -struct sx150x_chip { - struct gpio_chip gpio_chip; - struct i2c_client *client; - const struct sx150x_device_data *dev_cfg; - int irq_summary; - int irq_base; - int irq_update; - u32 irq_sense; - u32 irq_masked; - u32 dev_sense; - u32 dev_masked; - struct irq_chip irq_chip; - struct mutex lock; -}; - -static const struct sx150x_device_data sx150x_devices[] = { - [0] = { /* sx1508q */ - .model = SX150X_789, - .reg_pullup = 0x03, - .reg_pulldn = 0x04, - .reg_dir = 0x07, - .reg_data = 0x08, - .reg_irq_mask = 0x09, - .reg_irq_src = 0x0c, - .reg_sense = 0x0b, - .pri.x789 = { - .reg_drain = 0x05, - .reg_polarity = 0x06, - .reg_clock = 0x0f, - .reg_misc = 0x10, - .reg_reset = 0x7d, - }, - .ngpios = 8, - }, - [1] = { /* sx1509q */ - .model = SX150X_789, - .reg_pullup = 0x07, - .reg_pulldn = 0x09, - .reg_dir = 0x0f, - .reg_data = 0x11, - .reg_irq_mask = 0x13, - .reg_irq_src = 0x19, - .reg_sense = 0x17, - .pri.x789 = { - .reg_drain = 0x0b, - .reg_polarity = 0x0d, - .reg_clock = 0x1e, - .reg_misc = 0x1f, - .reg_reset = 0x7d, - }, - .ngpios = 16 - }, - [2] = { /* sx1506q */ - .model = SX150X_456, - .reg_pullup = 0x05, - .reg_pulldn = 0x07, - .reg_dir = 0x03, - .reg_data = 0x01, - .reg_irq_mask = 0x09, - .reg_irq_src = 0x0f, - .reg_sense = 0x0d, - .pri.x456 = { - .reg_pld_mode = 0x21, - .reg_pld_table0 = 0x23, - .reg_pld_table1 = 0x25, - .reg_pld_table2 = 0x27, - .reg_pld_table3 = 0x29, - .reg_pld_table4 = 0x2b, - .reg_advance = 0xad, - }, - .ngpios = 16 - }, - [3] = { /* sx1502q */ - .model = SX150X_123, - .reg_pullup = 0x02, - .reg_pulldn = 0x03, - .reg_dir = 0x01, - .reg_data = 0x00, - .reg_irq_mask = 0x05, - .reg_irq_src = 0x08, - .reg_sense = 0x07, - .pri.x123 = { - .reg_pld_mode = 0x10, - .reg_pld_table0 = 0x11, - .reg_pld_table1 = 0x12, - .reg_pld_table2 = 0x13, - .reg_pld_table3 = 0x14, - .reg_pld_table4 = 0x15, - .reg_advance = 0xad, - }, - .ngpios = 8, - }, -}; - -static const struct i2c_device_id sx150x_id[] = { - {"sx1508q", 0}, - {"sx1509q", 1}, - {"sx1506q", 2}, - {"sx1502q", 3}, - {} -}; - -static const struct of_device_id sx150x_of_match[] = { - { .compatible = "semtech,sx1508q" }, - { .compatible = "semtech,sx1509q" }, - { .compatible = "semtech,sx1506q" }, - { .compatible = "semtech,sx1502q" }, - {}, -}; - -static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) -{ - s32 err = i2c_smbus_write_byte_data(client, reg, val); - - if (err < 0) - dev_warn(&client->dev, - "i2c write fail: can't write %02x to %02x: %d\n", - val, reg, err); - return err; -} - -static s32 sx150x_i2c_read(struct i2c_client *client, u8 reg, u8 *val) -{ - s32 err = i2c_smbus_read_byte_data(client, reg); - - if (err >= 0) - *val = err; - else - dev_warn(&client->dev, - "i2c read fail: can't read from %02x: %d\n", - reg, err); - return err; -} - -static inline bool offset_is_oscio(struct sx150x_chip *chip, unsigned offset) -{ - return (chip->dev_cfg->ngpios == offset); -} - -/* - * These utility functions solve the common problem of locating and setting - * configuration bits. Configuration bits are grouped into registers - * whose indexes increase downwards. For example, with eight-bit registers, - * sixteen gpios would have their config bits grouped in the following order: - * REGISTER N-1 [ f e d c b a 9 8 ] - * N [ 7 6 5 4 3 2 1 0 ] - * - * For multi-bit configurations, the pattern gets wider: - * REGISTER N-3 [ f f e e d d c c ] - * N-2 [ b b a a 9 9 8 8 ] - * N-1 [ 7 7 6 6 5 5 4 4 ] - * N [ 3 3 2 2 1 1 0 0 ] - * - * Given the address of the starting register 'N', the index of the gpio - * whose configuration we seek to change, and the width in bits of that - * configuration, these functions allow us to locate the correct - * register and mask the correct bits. - */ -static inline void sx150x_find_cfg(u8 offset, u8 width, - u8 *reg, u8 *mask, u8 *shift) -{ - *reg -= offset * width / 8; - *mask = (1 << width) - 1; - *shift = (offset * width) % 8; - *mask <<= *shift; -} - -static s32 sx150x_write_cfg(struct sx150x_chip *chip, - u8 offset, u8 width, u8 reg, u8 val) -{ - u8 mask; - u8 data; - u8 shift; - s32 err; - - sx150x_find_cfg(offset, width, ®, &mask, &shift); - err = sx150x_i2c_read(chip->client, reg, &data); - if (err < 0) - return err; - - data &= ~mask; - data |= (val << shift) & mask; - return sx150x_i2c_write(chip->client, reg, data); -} - -static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset) -{ - u8 reg = chip->dev_cfg->reg_data; - u8 mask; - u8 data; - u8 shift; - s32 err; - - sx150x_find_cfg(offset, 1, ®, &mask, &shift); - err = sx150x_i2c_read(chip->client, reg, &data); - if (err >= 0) - err = (data & mask) != 0 ? 1 : 0; - - return err; -} - -static void sx150x_set_oscio(struct sx150x_chip *chip, int val) -{ - sx150x_i2c_write(chip->client, - chip->dev_cfg->pri.x789.reg_clock, - (val ? 0x1f : 0x10)); -} - -static void sx150x_set_io(struct sx150x_chip *chip, unsigned offset, int val) -{ - sx150x_write_cfg(chip, - offset, - 1, - chip->dev_cfg->reg_data, - (val ? 1 : 0)); -} - -static int sx150x_io_input(struct sx150x_chip *chip, unsigned offset) -{ - return sx150x_write_cfg(chip, - offset, - 1, - chip->dev_cfg->reg_dir, - 1); -} - -static int sx150x_io_output(struct sx150x_chip *chip, unsigned offset, int val) -{ - int err; - - err = sx150x_write_cfg(chip, - offset, - 1, - chip->dev_cfg->reg_data, - (val ? 1 : 0)); - if (err >= 0) - err = sx150x_write_cfg(chip, - offset, - 1, - chip->dev_cfg->reg_dir, - 0); - return err; -} - -static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset) -{ - struct sx150x_chip *chip = gpiochip_get_data(gc); - int status = -EINVAL; - - if (!offset_is_oscio(chip, offset)) { - mutex_lock(&chip->lock); - status = sx150x_get_io(chip, offset); - mutex_unlock(&chip->lock); - } - - return (status < 0) ? status : !!status; -} - -static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val) -{ - struct sx150x_chip *chip = gpiochip_get_data(gc); - - mutex_lock(&chip->lock); - if (offset_is_oscio(chip, offset)) - sx150x_set_oscio(chip, val); - else - sx150x_set_io(chip, offset, val); - mutex_unlock(&chip->lock); -} - -static int sx150x_gpio_set_single_ended(struct gpio_chip *gc, - unsigned offset, - enum single_ended_mode mode) -{ - struct sx150x_chip *chip = gpiochip_get_data(gc); - - /* On the SX160X 789 we can set open drain */ - if (chip->dev_cfg->model != SX150X_789) - return -ENOTSUPP; - - if (mode == LINE_MODE_PUSH_PULL) - return sx150x_write_cfg(chip, - offset, - 1, - chip->dev_cfg->pri.x789.reg_drain, - 0); - - if (mode == LINE_MODE_OPEN_DRAIN) - return sx150x_write_cfg(chip, - offset, - 1, - chip->dev_cfg->pri.x789.reg_drain, - 1); - return -ENOTSUPP; -} - -static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset) -{ - struct sx150x_chip *chip = gpiochip_get_data(gc); - int status = -EINVAL; - - if (!offset_is_oscio(chip, offset)) { - mutex_lock(&chip->lock); - status = sx150x_io_input(chip, offset); - mutex_unlock(&chip->lock); - } - return status; -} - -static int sx150x_gpio_direction_output(struct gpio_chip *gc, - unsigned offset, - int val) -{ - struct sx150x_chip *chip = gpiochip_get_data(gc); - int status = 0; - - if (!offset_is_oscio(chip, offset)) { - mutex_lock(&chip->lock); - status = sx150x_io_output(chip, offset, val); - mutex_unlock(&chip->lock); - } - return status; -} - -static void sx150x_irq_mask(struct irq_data *d) -{ - struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned n = d->hwirq; - - chip->irq_masked |= (1 << n); - chip->irq_update = n; -} - -static void sx150x_irq_unmask(struct irq_data *d) -{ - struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned n = d->hwirq; - - chip->irq_masked &= ~(1 << n); - chip->irq_update = n; -} - -static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) -{ - struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned n, val = 0; - - if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) - return -EINVAL; - - n = d->hwirq; - - if (flow_type & IRQ_TYPE_EDGE_RISING) - val |= 0x1; - if (flow_type & IRQ_TYPE_EDGE_FALLING) - val |= 0x2; - - chip->irq_sense &= ~(3UL << (n * 2)); - chip->irq_sense |= val << (n * 2); - chip->irq_update = n; - return 0; -} - -static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) -{ - struct sx150x_chip *chip = (struct sx150x_chip *)dev_id; - unsigned nhandled = 0; - unsigned sub_irq; - unsigned n; - s32 err; - u8 val; - int i; - - for (i = (chip->dev_cfg->ngpios / 8) - 1; i >= 0; --i) { - err = sx150x_i2c_read(chip->client, - chip->dev_cfg->reg_irq_src - i, - &val); - if (err < 0) - continue; - - sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_irq_src - i, - val); - for (n = 0; n < 8; ++n) { - if (val & (1 << n)) { - sub_irq = irq_find_mapping( - chip->gpio_chip.irqdomain, - (i * 8) + n); - handle_nested_irq(sub_irq); - ++nhandled; - } - } - } - - return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); -} - -static void sx150x_irq_bus_lock(struct irq_data *d) -{ - struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - - mutex_lock(&chip->lock); -} - -static void sx150x_irq_bus_sync_unlock(struct irq_data *d) -{ - struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned n; - - if (chip->irq_update == NO_UPDATE_PENDING) - goto out; - - n = chip->irq_update; - chip->irq_update = NO_UPDATE_PENDING; - - /* Avoid updates if nothing changed */ - if (chip->dev_sense == chip->irq_sense && - chip->dev_masked == chip->irq_masked) - goto out; - - chip->dev_sense = chip->irq_sense; - chip->dev_masked = chip->irq_masked; - - if (chip->irq_masked & (1 << n)) { - sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); - sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); - } else { - sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); - sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, - chip->irq_sense >> (n * 2)); - } -out: - mutex_unlock(&chip->lock); -} - -static void sx150x_init_chip(struct sx150x_chip *chip, - struct i2c_client *client, - kernel_ulong_t driver_data, - struct sx150x_platform_data *pdata) -{ - mutex_init(&chip->lock); - - chip->client = client; - chip->dev_cfg = &sx150x_devices[driver_data]; - chip->gpio_chip.parent = &client->dev; - chip->gpio_chip.label = client->name; - chip->gpio_chip.direction_input = sx150x_gpio_direction_input; - chip->gpio_chip.direction_output = sx150x_gpio_direction_output; - chip->gpio_chip.get = sx150x_gpio_get; - chip->gpio_chip.set = sx150x_gpio_set; - chip->gpio_chip.set_single_ended = sx150x_gpio_set_single_ended; - chip->gpio_chip.base = pdata->gpio_base; - chip->gpio_chip.can_sleep = true; - chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; -#ifdef CONFIG_OF_GPIO - chip->gpio_chip.of_node = client->dev.of_node; - chip->gpio_chip.of_gpio_n_cells = 2; -#endif - if (pdata->oscio_is_gpo) - ++chip->gpio_chip.ngpio; - - chip->irq_chip.name = client->name; - chip->irq_chip.irq_mask = sx150x_irq_mask; - chip->irq_chip.irq_unmask = sx150x_irq_unmask; - chip->irq_chip.irq_set_type = sx150x_irq_set_type; - chip->irq_chip.irq_bus_lock = sx150x_irq_bus_lock; - chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; - chip->irq_summary = -1; - chip->irq_base = -1; - chip->irq_masked = ~0; - chip->irq_sense = 0; - chip->dev_masked = ~0; - chip->dev_sense = 0; - chip->irq_update = NO_UPDATE_PENDING; -} - -static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) -{ - int err = 0; - unsigned n; - - for (n = 0; err >= 0 && n < (chip->dev_cfg->ngpios / 8); ++n) - err = sx150x_i2c_write(chip->client, base - n, cfg >> (n * 8)); - return err; -} - -static int sx150x_reset(struct sx150x_chip *chip) -{ - int err; - - err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->pri.x789.reg_reset, - 0x12); - if (err < 0) - return err; - - err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->pri.x789.reg_reset, - 0x34); - return err; -} - -static int sx150x_init_hw(struct sx150x_chip *chip, - struct sx150x_platform_data *pdata) -{ - int err = 0; - - if (pdata->reset_during_probe) { - err = sx150x_reset(chip); - if (err < 0) - return err; - } - - if (chip->dev_cfg->model == SX150X_789) - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->pri.x789.reg_misc, - 0x01); - else if (chip->dev_cfg->model == SX150X_456) - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->pri.x456.reg_advance, - 0x04); - else - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->pri.x123.reg_advance, - 0x00); - if (err < 0) - return err; - - err = sx150x_init_io(chip, chip->dev_cfg->reg_pullup, - pdata->io_pullup_ena); - if (err < 0) - return err; - - err = sx150x_init_io(chip, chip->dev_cfg->reg_pulldn, - pdata->io_pulldn_ena); - if (err < 0) - return err; - - if (chip->dev_cfg->model == SX150X_789) { - err = sx150x_init_io(chip, - chip->dev_cfg->pri.x789.reg_polarity, - pdata->io_polarity); - if (err < 0) - return err; - } else if (chip->dev_cfg->model == SX150X_456) { - /* Set all pins to work in normal mode */ - err = sx150x_init_io(chip, - chip->dev_cfg->pri.x456.reg_pld_mode, - 0); - if (err < 0) - return err; - } else { - /* Set all pins to work in normal mode */ - err = sx150x_init_io(chip, - chip->dev_cfg->pri.x123.reg_pld_mode, - 0); - if (err < 0) - return err; - } - - - if (pdata->oscio_is_gpo) - sx150x_set_oscio(chip, 0); - - return err; -} - -static int sx150x_install_irq_chip(struct sx150x_chip *chip, - int irq_summary, - int irq_base) -{ - int err; - - chip->irq_summary = irq_summary; - chip->irq_base = irq_base; - - /* Add gpio chip to irq subsystem */ - err = gpiochip_irqchip_add(&chip->gpio_chip, - &chip->irq_chip, chip->irq_base, - handle_edge_irq, IRQ_TYPE_EDGE_BOTH); - if (err) { - dev_err(&chip->client->dev, - "could not connect irqchip to gpiochip\n"); - return err; - } - - err = devm_request_threaded_irq(&chip->client->dev, - irq_summary, NULL, sx150x_irq_thread_fn, - IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, - chip->irq_chip.name, chip); - if (err < 0) { - chip->irq_summary = -1; - chip->irq_base = -1; - } - - return err; -} - -static int sx150x_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_WORD_DATA; - struct sx150x_platform_data *pdata; - struct sx150x_chip *chip; - int rc; - - pdata = dev_get_platdata(&client->dev); - if (!pdata) - return -EINVAL; - - if (!i2c_check_functionality(client->adapter, i2c_funcs)) - return -ENOSYS; - - chip = devm_kzalloc(&client->dev, - sizeof(struct sx150x_chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - sx150x_init_chip(chip, client, id->driver_data, pdata); - rc = sx150x_init_hw(chip, pdata); - if (rc < 0) - return rc; - - rc = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); - if (rc) - return rc; - - if (pdata->irq_summary >= 0) { - rc = sx150x_install_irq_chip(chip, - pdata->irq_summary, - pdata->irq_base); - if (rc < 0) - return rc; - } - - i2c_set_clientdata(client, chip); - - return 0; -} - -static struct i2c_driver sx150x_driver = { - .driver = { - .name = "sx150x", - .of_match_table = of_match_ptr(sx150x_of_match), - }, - .probe = sx150x_probe, - .id_table = sx150x_id, -}; - -static int __init sx150x_init(void) -{ - return i2c_add_driver(&sx150x_driver); -} -subsys_initcall(sx150x_init); -- cgit v1.2.3 From fdf4332fdef28b401c36c229174469c3cf3e8241 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 25 Sep 2016 20:44:04 +0800 Subject: gpio: max77620: Remove unused fields from struct max77620_gpio Current code does not use gpio_irq/irq_base/gpio_base fields from struct max77620_gpio, so remove them. Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max77620.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index b46b436cb97f..df035866d7a2 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -21,9 +21,6 @@ struct max77620_gpio { struct gpio_chip gpio_chip; struct regmap *rmap; struct device *dev; - int gpio_irq; - int irq_base; - int gpio_base; }; static const struct regmap_irq max77620_gpio_irqs[] = { @@ -254,7 +251,6 @@ static int max77620_gpio_probe(struct platform_device *pdev) mgpio->rmap = chip->rmap; mgpio->dev = &pdev->dev; - mgpio->gpio_irq = gpio_irq; mgpio->gpio_chip.label = pdev->name; mgpio->gpio_chip.parent = &pdev->dev; @@ -268,7 +264,6 @@ static int max77620_gpio_probe(struct platform_device *pdev) mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; mgpio->gpio_chip.can_sleep = 1; mgpio->gpio_chip.base = -1; - mgpio->irq_base = -1; #ifdef CONFIG_OF_GPIO mgpio->gpio_chip.of_node = pdev->dev.parent->of_node; #endif @@ -281,9 +276,8 @@ static int max77620_gpio_probe(struct platform_device *pdev) return ret; } - mgpio->gpio_base = mgpio->gpio_chip.base; - ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, mgpio->gpio_irq, - IRQF_ONESHOT, mgpio->irq_base, + ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq, + IRQF_ONESHOT, -1, &max77620_gpio_irq_chip, &chip->gpio_irq_data); if (ret < 0) { -- cgit v1.2.3 From e78ade0a2f50fd1a5254d8c801dbb37f46a85e12 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Oct 2016 12:07:53 +0300 Subject: gpio: merrifield: set default handler to be handle_bad_irq() We switch the default handler to be handle_bad_irq() instead of handle_simple_irq() (which was not correct anyway). Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 45b51278b8ee..82cdcdc779bb 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -411,7 +411,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id } retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, - handle_simple_irq, IRQ_TYPE_NONE); + handle_bad_irq, IRQ_TYPE_NONE); if (retval) { dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); return retval; -- cgit v1.2.3 From 26a48c4cc2f15d516513e4a980a8a63a21aff018 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 2 Jun 2016 12:52:24 -0500 Subject: gpio: altera-a10sr: Add A10 System Resource Chip GPIO support. Add the GPIO functionality for the Altera Arria10 MAX5 System Resource Chip. The A10 MAX5 has 12 bits of GPIO assigned to switches, buttons, and LEDs as a GPIO extender on the SPI bus. Signed-off-by: Thor Thayer Acked-by: Linus Walleij i Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 8 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-altera-a10sr.c | 140 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 drivers/gpio/gpio-altera-a10sr.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 26ee00f6bd58..41e2a8f84289 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -818,6 +818,14 @@ config GPIO_ADP5520 This option enables support for on-chip GPIO found on Analog Devices ADP5520 PMICs. +config GPIO_ALTERA_A10SR + tristate "Altera Arria10 System Resource GPIO" + depends on MFD_ALTERA_A10SR + help + Driver for Arria10 Development Kit GPIO expansion which + includes reads of pushbuttons and DIP switches as well + as writes to LEDs. + config GPIO_ARIZONA tristate "Wolfson Microelectronics Arizona class devices" depends on MFD_ARIZONA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ab28a2daeacc..145847a4d1d5 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o +obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c new file mode 100644 index 000000000000..8274f98e3bee --- /dev/null +++ b/drivers/gpio/gpio-altera-a10sr.c @@ -0,0 +1,140 @@ +/* + * Copyright Intel Corporation (C) 2014-2016. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * GPIO driver for Altera Arria10 MAX5 System Resource Chip + * + * Adapted from gpio-tps65910.c + */ + +#include +#include +#include + +/** + * struct altr_a10sr_gpio - Altera Max5 GPIO device private data structure + * @gp: : instance of the gpio_chip + * @regmap: the regmap from the parent device. + */ +struct altr_a10sr_gpio { + struct gpio_chip gp; + struct regmap *regmap; +}; + +static int altr_a10sr_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); + int ret, val; + + ret = regmap_read(gpio->regmap, ALTR_A10SR_PBDSW_REG, &val); + if (ret < 0) + return ret; + + return !!(val & BIT(offset - ALTR_A10SR_LED_VALID_SHIFT)); +} + +static void altr_a10sr_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); + + regmap_update_bits(gpio->regmap, ALTR_A10SR_LED_REG, + BIT(ALTR_A10SR_LED_VALID_SHIFT + offset), + value ? BIT(ALTR_A10SR_LED_VALID_SHIFT + offset) + : 0); +} + +static int altr_a10sr_gpio_direction_input(struct gpio_chip *gc, + unsigned int nr) +{ + if (nr >= (ALTR_A10SR_IN_VALID_RANGE_LO - ALTR_A10SR_LED_VALID_SHIFT)) + return 0; + return -EINVAL; +} + +static int altr_a10sr_gpio_direction_output(struct gpio_chip *gc, + unsigned int nr, int value) +{ + if (nr <= (ALTR_A10SR_OUT_VALID_RANGE_HI - ALTR_A10SR_LED_VALID_SHIFT)) + return 0; + return -EINVAL; +} + +static struct gpio_chip altr_a10sr_gc = { + .label = "altr_a10sr_gpio", + .owner = THIS_MODULE, + .get = altr_a10sr_gpio_get, + .set = altr_a10sr_gpio_set, + .direction_input = altr_a10sr_gpio_direction_input, + .direction_output = altr_a10sr_gpio_direction_output, + .can_sleep = true, + .ngpio = 12, + .base = -1, +}; + +static int altr_a10sr_gpio_probe(struct platform_device *pdev) +{ + struct altr_a10sr_gpio *gpio; + int ret; + struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent); + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->regmap = a10sr->regmap; + + gpio->gp = altr_a10sr_gc; + + gpio->gp.of_node = pdev->dev.of_node; + + ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, gpio); + + return 0; +} + +static int altr_a10sr_gpio_remove(struct platform_device *pdev) +{ + struct altr_a10sr_gpio *gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&gpio->gp); + + return 0; +} + +static const struct of_device_id altr_a10sr_gpio_of_match[] = { + { .compatible = "altr,a10sr-gpio" }, + { }, +}; +MODULE_DEVICE_TABLE(of, altr_a10sr_gpio_of_match); + +static struct platform_driver altr_a10sr_gpio_driver = { + .probe = altr_a10sr_gpio_probe, + .remove = altr_a10sr_gpio_remove, + .driver = { + .name = "altr_a10sr_gpio", + .of_match_table = of_match_ptr(altr_a10sr_gpio_of_match), + }, +}; +module_platform_driver(altr_a10sr_gpio_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Thor Thayer "); +MODULE_DESCRIPTION("Altera Arria10 System Resource Chip GPIO"); -- cgit v1.2.3 From 4c5f15b71b22ea51fcb70e538056bcb4958edd9f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 14 Oct 2016 14:24:09 +0200 Subject: gpio: ts4900: Add hardware dependencies All the boards supported by the gpio-ts4900 driver are i.MX6 boards, so only offer the driver for building on this platform, unless build-testing. Signed-off-by: Jean Delvare Cc: Lucile Quirion Cc: Linus Walleij Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 41e2a8f84289..8eea33269433 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -802,6 +802,7 @@ config GPIO_TPIC2810 config GPIO_TS4900 tristate "Technologic Systems FPGA I2C GPIO" + depends on SOC_IMX6 || COMPILE_TEST select REGMAP_I2C help Say yes here to enabled the GPIO driver for Technologic's FPGA core. -- cgit v1.2.3 From 1208c93525f9385354588f74c3db5413bd7781dc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 17 Oct 2016 18:36:49 +0200 Subject: gpio: pca953x: Add MAX7318 compatible Add compatible string for the MAX7318 part. This is a two bank, 16 lines, I2C GPIO expander with interrupt line. Signed-off-by: Marek Vasut Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index e422568e14ad..601c4550ee27 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -74,6 +74,7 @@ static const struct i2c_device_id pca953x_id[] = { { "max7312", 16 | PCA953X_TYPE | PCA_INT, }, { "max7313", 16 | PCA953X_TYPE | PCA_INT, }, { "max7315", 8 | PCA953X_TYPE | PCA_INT, }, + { "max7318", 16 | PCA953X_TYPE | PCA_INT, }, { "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, @@ -907,6 +908,7 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), }, { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), }, { .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "maxim,max7318", .data = OF_953X(16, PCA_INT), }, { .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), }, { .compatible = "ti,pca9536", .data = OF_953X( 4, 0), }, -- cgit v1.2.3 From 6f7194a10bdba1588357342c6daaaeef98e0004f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 21 Oct 2016 17:21:29 +0300 Subject: ACPI / gpio: Allow holes in list of GPIOs for a device Make it possible to have an empty GPIOs in a GPIO list for device. For example a SPI master may use both GPIOs and native pins as chip selects and we need to be able to distinguish between the two. This makes it mandatory to have exactly 3 arguments for GPIOs and then converts gpiolib to use of __acpi_node_get_property_reference() instead. In addition we make acpi_gpio_package_count() to handle holes as well (this matches the DT version). Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 58ece201b8e6..700ea6ad609b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -468,7 +468,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, int ret; memset(&args, 0, sizeof(args)); - ret = acpi_node_get_property_reference(fwnode, propname, index, &args); + ret = __acpi_node_get_property_reference(fwnode, propname, index, 3, + &args); if (ret) { struct acpi_device *adev = to_acpi_device_node(fwnode); @@ -483,13 +484,13 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, * on returned args. */ lookup->adev = args.adev; - if (args.nargs >= 2) { - lookup->index = args.args[0]; - lookup->pin_index = args.args[1]; - /* 3rd argument, if present is used to specify active_low. */ - if (args.nargs >= 3) - lookup->active_low = !!args.args[2]; - } + if (args.nargs != 3) + return -EPROTO; + + lookup->index = args.args[0]; + lookup->pin_index = args.args[1]; + lookup->active_low = !!args.args[2]; + return 0; } @@ -915,18 +916,27 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) kfree(acpi_gpio); } -static unsigned int acpi_gpio_package_count(const union acpi_object *obj) +static int acpi_gpio_package_count(const union acpi_object *obj) { const union acpi_object *element = obj->package.elements; const union acpi_object *end = element + obj->package.count; unsigned int count = 0; while (element < end) { - if (element->type == ACPI_TYPE_LOCAL_REFERENCE) + switch (element->type) { + case ACPI_TYPE_LOCAL_REFERENCE: + element += 3; + /* Fallthrough */ + case ACPI_TYPE_INTEGER: + element++; count++; + break; - element++; + default: + return -EPROTO; + } } + return count; } -- cgit v1.2.3 From c80f1ba75df25837fb76044e06686b6587d33f6a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 21 Oct 2016 17:21:30 +0300 Subject: ACPI / gpio: Add hogging support GPIO hogging means that the GPIO controller can "hog" and configure certain GPIOs without need for a driver or userspace to do that. This is useful in open-connected boards where BIOS cannot possibly know beforehand which devices will be connected to the board. This adds GPIO hogging mechanism to ACPI analogous to Device Tree. Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 700ea6ad609b..4f46982ce982 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -857,6 +857,76 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) } } +struct gpio_desc *acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip, + struct fwnode_handle *fwnode, const char **name, unsigned int *lflags, + unsigned int *dflags) +{ + struct gpio_chip *chip = achip->chip; + struct gpio_desc *desc; + u32 gpios[2]; + int ret; + + ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios, + ARRAY_SIZE(gpios)); + if (ret < 0) + return ERR_PTR(ret); + + ret = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, gpios[0]); + if (ret < 0) + return ERR_PTR(ret); + + desc = gpiochip_get_desc(chip, ret); + if (IS_ERR(desc)) + return desc; + + *lflags = 0; + *dflags = 0; + *name = NULL; + + if (gpios[1]) + *lflags |= GPIO_ACTIVE_LOW; + + if (fwnode_property_present(fwnode, "input")) + *dflags |= GPIOD_IN; + else if (fwnode_property_present(fwnode, "output-low")) + *dflags |= GPIOD_OUT_LOW; + else if (fwnode_property_present(fwnode, "output-high")) + *dflags |= GPIOD_OUT_HIGH; + else + return ERR_PTR(-EINVAL); + + fwnode_property_read_string(fwnode, "line-name", name); + + return desc; +} + +static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + struct fwnode_handle *fwnode; + + device_for_each_child_node(chip->parent, fwnode) { + unsigned int lflags, dflags; + struct gpio_desc *desc; + const char *name; + int ret; + + if (!fwnode_property_present(fwnode, "gpio-hog")) + continue; + + desc = acpi_gpiochip_parse_own_gpio(achip, fwnode, &name, + &lflags, &dflags); + if (IS_ERR(desc)) + continue; + + ret = gpiod_hog(desc, name, lflags, dflags); + if (ret) { + dev_err(chip->parent, "Failed to hog GPIO\n"); + return; + } + } +} + void acpi_gpiochip_add(struct gpio_chip *chip) { struct acpi_gpio_chip *acpi_gpio; @@ -888,6 +958,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) } acpi_gpiochip_request_regions(acpi_gpio); + acpi_gpiochip_scan_gpios(acpi_gpio); acpi_walk_dep_device_list(handle); } -- cgit v1.2.3 From 9427ecbed46cc8425338084ae42ce8749566586f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 21 Oct 2016 17:21:31 +0300 Subject: gpio: Rework of_gpiochip_set_names() to use device property accessors In order to use "gpio-line-names" property in systems not having DT as their boot firmware, rework of_gpiochip_set_names() to use device property accessors. This reworked function is placed in a separate file making it clear it deals with universal device properties. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/Makefile | 1 + drivers/gpio/gpiolib-devprop.c | 62 ++++++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib-of.c | 47 +------------------------------- drivers/gpio/gpiolib.h | 2 ++ 4 files changed, 66 insertions(+), 46 deletions(-) create mode 100644 drivers/gpio/gpiolib-devprop.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 145847a4d1d5..bd51ad8b4841 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_GPIO_DEVRES) += devres.o obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o +obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o diff --git a/drivers/gpio/gpiolib-devprop.c b/drivers/gpio/gpiolib-devprop.c new file mode 100644 index 000000000000..17bfc41692ef --- /dev/null +++ b/drivers/gpio/gpiolib-devprop.c @@ -0,0 +1,62 @@ +/* + * Device property helpers for GPIO chips. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "gpiolib.h" + +/** + * devprop_gpiochip_set_names - Set GPIO line names using device properties + * @chip: GPIO chip whose lines should be named, if possible + * + * Looks for device property "gpio-line-names" and if it exists assigns + * GPIO line names for the chip. The memory allocated for the assigned + * names belong to the underlying firmware node and should not be released + * by the caller. + */ +void devprop_gpiochip_set_names(struct gpio_chip *chip) +{ + struct gpio_device *gdev = chip->gpiodev; + const char **names; + int ret, i; + + ret = device_property_read_string_array(chip->parent, "gpio-line-names", + NULL, 0); + if (ret < 0) + return; + + if (ret != gdev->ngpio) { + dev_warn(chip->parent, + "names %d do not match number of GPIOs %d\n", ret, + gdev->ngpio); + return; + } + + names = kcalloc(gdev->ngpio, sizeof(*names), GFP_KERNEL); + if (!names) + return; + + ret = device_property_read_string_array(chip->parent, "gpio-line-names", + names, gdev->ngpio); + if (ret < 0) { + dev_warn(chip->parent, "failed to read GPIO line names\n"); + kfree(names); + return; + } + + for (i = 0; i < gdev->ngpio; i++) + gdev->descs[i].name = names[i]; + + kfree(names); +} diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index ecad3f0e3b77..3fa4e84b4327 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -221,51 +221,6 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, return desc; } -/** - * of_gpiochip_set_names() - set up the names of the lines - * @chip: GPIO chip whose lines should be named, if possible - */ -static void of_gpiochip_set_names(struct gpio_chip *gc) -{ - struct gpio_device *gdev = gc->gpiodev; - struct device_node *np = gc->of_node; - int i; - int nstrings; - - nstrings = of_property_count_strings(np, "gpio-line-names"); - if (nstrings <= 0) - /* Lines names not present */ - return; - - /* This is normally not what you want */ - if (gdev->ngpio != nstrings) - dev_info(&gdev->dev, "gpio-line-names specifies %d line " - "names but there are %d lines on the chip\n", - nstrings, gdev->ngpio); - - /* - * Make sure to not index beyond the end of the number of descriptors - * of the GPIO device. - */ - for (i = 0; i < gdev->ngpio; i++) { - const char *name; - int ret; - - ret = of_property_read_string_index(np, - "gpio-line-names", - i, - &name); - if (ret) { - if (ret != -ENODATA) - dev_err(&gdev->dev, - "unable to name line %d: %d\n", - i, ret); - break; - } - gdev->descs[i].name = name; - } -} - /** * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions * @chip: gpio chip to act on @@ -522,7 +477,7 @@ int of_gpiochip_add(struct gpio_chip *chip) /* If the chip defines names itself, these take precedence */ if (!chip->names) - of_gpiochip_set_names(chip); + devprop_gpiochip_set_names(chip); of_node_get(chip->of_node); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 346fbda39220..d10eaf520860 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -209,6 +209,8 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) return desc - &desc->gdev->descs[0]; } +void devprop_gpiochip_set_names(struct gpio_chip *chip); + /* With descriptor prefix */ #define gpiod_emerg(desc, fmt, ...) \ -- cgit v1.2.3 From 4035cc15b99f4f4a4e29081b82aca010137e33da Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 21 Oct 2016 17:21:32 +0300 Subject: ACPI / gpio: Add support for naming GPIOs Now that we have the new helper function that sets nice names for GPIO lines based on "gpio-line-names" device property, we can take advantage of this in acpi_gpiochip_add(). Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 4f46982ce982..53266ef12008 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -957,6 +957,9 @@ void acpi_gpiochip_add(struct gpio_chip *chip) return; } + if (!chip->names) + devprop_gpiochip_set_names(chip); + acpi_gpiochip_request_regions(acpi_gpio); acpi_gpiochip_scan_gpios(acpi_gpio); acpi_walk_dep_device_list(handle); -- cgit v1.2.3 From 66a37c3bbf7348758a154fe99f8035df2874ebeb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 21 Oct 2016 15:11:37 +0200 Subject: gpio: mxs: use enable/disable regs to (un)mask irqs The mxs gpio controller does not only have a mask register to mask interrupts, but also enable/disable registers. Use the enable/disable registers rather than the mask register. This does not have any advantage for now, but makes the next patch simpler. Signed-off-by: Sascha Hauer Reviewed-by: Marek Vasut Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index b9daa0bf32a4..1cf579f670ec 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -211,12 +211,13 @@ static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct = gc->chip_types; ct->chip.irq_ack = irq_gc_ack_set_bit; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_mask = irq_gc_mask_disable_reg; + ct->chip.irq_unmask = irq_gc_unmask_enable_reg; ct->chip.irq_set_type = mxs_gpio_set_irq_type; ct->chip.irq_set_wake = mxs_gpio_set_wake_irq; ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; - ct->regs.mask = PINCTRL_IRQEN(port); + ct->regs.enable = PINCTRL_IRQEN(port) + MXS_SET; + ct->regs.disable = PINCTRL_IRQEN(port) + MXS_CLR; irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); -- cgit v1.2.3 From f08ea3cc94eeaf938ad9da86014e8fee79299458 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 21 Oct 2016 15:11:38 +0200 Subject: gpio: mxs: fix duplicate level interrupts According to the reference manual level interrupts can't be acked using the IRQSTAT registers. The effect is that when a level interrupt triggers the following ack is a no-op and the same interrupt triggers again right after it has been unmasked after running the interrupt handler. The reference manual says: Status bits for pins configured as level sensitive interrupts cannot be cleared unless either the actual pin is in the non-interrupting state, or the pin has been disabled as an interrupt source by clearing its bit in HW_PINCTRL_PIN2IRQ. To work around the duplicated interrupts we can use the PIN2IRQ rather than the IRQEN registers to mask the interrupts. This probably does not work for the edge interrupts, so we have to split up the irq chip into two chip types, one for the level interrupts and one for the edge interrupts. We now make use of two different enable registers, so we have to take care to always enable the right one, especially during switching of the interrupt type. An easy way to accomplish this is to use the IRQCHIP_SET_TYPE_MASKED which makes sure that set_irq_type is called with masked interrupts. With this the flow to change the irq type is like: - core masks interrupt (using the current chip type) - mxs_gpio_set_irq_type() changes chip type if necessary - mxs_gpio_set_irq_type() unconditionally sets the enable bit in the now unused enable register - core eventually unmasks the interrupt (using the new chip type) Signed-off-by: Sascha Hauer Reviewed-by: Marek Vasut Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 1cf579f670ec..62061f740ccf 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -87,10 +87,15 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) u32 val; u32 pin_mask = 1 << d->hwirq; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); struct mxs_gpio_port *port = gc->private; void __iomem *pin_addr; int edge; + if (!(ct->type & type)) + if (irq_setup_alt_chip(d, type)) + return -EINVAL; + port->both_edges &= ~pin_mask; switch (type) { case IRQ_TYPE_EDGE_BOTH: @@ -119,10 +124,13 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) /* set level or edge */ pin_addr = port->base + PINCTRL_IRQLEV(port); - if (edge & GPIO_INT_LEV_MASK) + if (edge & GPIO_INT_LEV_MASK) { writel(pin_mask, pin_addr + MXS_SET); - else + writel(pin_mask, port->base + PINCTRL_IRQEN(port) + MXS_SET); + } else { writel(pin_mask, pin_addr + MXS_CLR); + writel(pin_mask, port->base + PINCTRL_PIN2IRQ(port) + MXS_SET); + } /* set polarity */ pin_addr = port->base + PINCTRL_IRQPOL(port); @@ -202,22 +210,37 @@ static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) struct irq_chip_generic *gc; struct irq_chip_type *ct; - gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base, + gc = irq_alloc_generic_chip("gpio-mxs", 2, irq_base, port->base, handle_level_irq); if (!gc) return -ENOMEM; gc->private = port; - ct = gc->chip_types; + ct = &gc->chip_types[0]; + ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_disable_reg; + ct->chip.irq_unmask = irq_gc_unmask_enable_reg; + ct->chip.irq_set_type = mxs_gpio_set_irq_type; + ct->chip.irq_set_wake = mxs_gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED; + ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; + ct->regs.enable = PINCTRL_PIN2IRQ(port) + MXS_SET; + ct->regs.disable = PINCTRL_PIN2IRQ(port) + MXS_CLR; + + ct = &gc->chip_types[1]; + ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_disable_reg; ct->chip.irq_unmask = irq_gc_unmask_enable_reg; ct->chip.irq_set_type = mxs_gpio_set_irq_type; ct->chip.irq_set_wake = mxs_gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED; ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.enable = PINCTRL_IRQEN(port) + MXS_SET; ct->regs.disable = PINCTRL_IRQEN(port) + MXS_CLR; + ct->handler = handle_level_irq; irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); @@ -298,11 +321,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) } port->base = base; - /* - * select the pin interrupt functionality but initially - * disable the interrupts - */ - writel(~0U, port->base + PINCTRL_PIN2IRQ(port)); + /* initially disable the interrupts */ + writel(0, port->base + PINCTRL_PIN2IRQ(port)); writel(0, port->base + PINCTRL_IRQEN(port)); /* clear address has to be used to clear IRQSTAT bits */ -- cgit v1.2.3 From f85522c207ce395fc9c1f6b80a47f211d00914b0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 24 Oct 2016 14:49:13 +0000 Subject: gpio: altera-a10sr: Drop unnecessary gpiochip_remove It's not necessary to unregister gpio_chip which registered with devm_gpiochip_add_data(). Also get rid of useless altr_a10sr_gpio_remove(). Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij --- drivers/gpio/gpio-altera-a10sr.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c index 8274f98e3bee..9e1a138fed53 100644 --- a/drivers/gpio/gpio-altera-a10sr.c +++ b/drivers/gpio/gpio-altera-a10sr.c @@ -110,15 +110,6 @@ static int altr_a10sr_gpio_probe(struct platform_device *pdev) return 0; } -static int altr_a10sr_gpio_remove(struct platform_device *pdev) -{ - struct altr_a10sr_gpio *gpio = platform_get_drvdata(pdev); - - gpiochip_remove(&gpio->gp); - - return 0; -} - static const struct of_device_id altr_a10sr_gpio_of_match[] = { { .compatible = "altr,a10sr-gpio" }, { }, @@ -127,7 +118,6 @@ MODULE_DEVICE_TABLE(of, altr_a10sr_gpio_of_match); static struct platform_driver altr_a10sr_gpio_driver = { .probe = altr_a10sr_gpio_probe, - .remove = altr_a10sr_gpio_remove, .driver = { .name = "altr_a10sr_gpio", .of_match_table = of_match_ptr(altr_a10sr_gpio_of_match), -- cgit v1.2.3 From 5a195c6d4ecf43be26ee1c8be6140025832adfd2 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Oct 2016 11:31:23 -0500 Subject: gpio: gpiolib-devprop: Check chip->parent pointer before dereferencing Confirm the chip->parent is valid before dereferencing because the parent parameter is optional. Signed-off-by: Thor Thayer Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-devprop.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-devprop.c b/drivers/gpio/gpiolib-devprop.c index 17bfc41692ef..27f383bda7d9 100644 --- a/drivers/gpio/gpiolib-devprop.c +++ b/drivers/gpio/gpiolib-devprop.c @@ -31,6 +31,11 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip) const char **names; int ret, i; + if (!chip->parent) { + dev_warn(&gdev->dev, "GPIO chip parent is NULL\n"); + return; + } + ret = device_property_read_string_array(chip->parent, "gpio-line-names", NULL, 0); if (ret < 0) -- cgit v1.2.3 From 1b6998c96ccc60a61bdb812b4a55866224ab9708 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 16:11:57 +0000 Subject: ACPI / gpio: add missing fwnode_handle_put() in acpi_gpiochip_scan_gpios() fwnode_handle_put() should be used when terminating device_for_each_child_node() iteration with break or return to prevent stale device node references from being left behind. This is detected by Coccinelle semantic patch. Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 53266ef12008..aa879d5eaa19 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -922,6 +922,7 @@ static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip) ret = gpiod_hog(desc, name, lflags, dflags); if (ret) { dev_err(chip->parent, "Failed to hog GPIO\n"); + fwnode_handle_put(fwnode); return; } } -- cgit v1.2.3 From 550a9532b8093ef554947e5d24b469ffb1ff9930 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 16:13:12 +0000 Subject: ACPI / gpio: make acpi_gpiochip_parse_own_gpio static Fixes the following sparse warning: drivers/gpio/gpiolib-acpi.c:863:18: warning: symbol 'acpi_gpiochip_parse_own_gpio' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index aa879d5eaa19..83fcfff19cd6 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -857,9 +857,9 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) } } -struct gpio_desc *acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip, - struct fwnode_handle *fwnode, const char **name, unsigned int *lflags, - unsigned int *dflags) +static struct gpio_desc *acpi_gpiochip_parse_own_gpio( + struct acpi_gpio_chip *achip, struct fwnode_handle *fwnode, + const char **name, unsigned int *lflags, unsigned int *dflags) { struct gpio_chip *chip = achip->chip; struct gpio_desc *desc; -- cgit v1.2.3 From 09e258af4edaa10ee9aa3164923ee07d5863d637 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 16:13:52 +0000 Subject: gpio: of: add missing of_node_put() in of_gpiochip_scan_gpios() When terminating for_each_available_child_of_node() iteration with break or return, of_node_put() should be used to prevent stale device node references from being left behind. This is detected by Coccinelle semantic patch. Signed-off-by: Wei Yongjun Reviewed-by: Vladimir Zapolskiy Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 3fa4e84b4327..5236966b1bdf 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -247,8 +247,10 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) continue; ret = gpiod_hog(desc, name, lflags, dflags); - if (ret < 0) + if (ret < 0) { + of_node_put(np); return ret; + } } return 0; -- cgit v1.2.3 From 43bbf94c333ac1b1bee2bf05efb48e9ae8ea3e82 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 31 Oct 2016 14:27:07 -0400 Subject: gpio: htc-egpio: Make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/gpio/Kconfig:config HTC_EGPIO drivers/gpio/Kconfig: bool "HTC EGPIO support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Cc: Linus Walleij Cc: Alexandre Courbot Cc: Kevin O'Connor Cc: linux-gpio@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Linus Walleij --- drivers/gpio/gpio-htc-egpio.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 0b4df6051097..5ab895b41819 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include struct egpio_chip { int reg_start; @@ -367,24 +367,6 @@ fail: return ret; } -static int __exit egpio_remove(struct platform_device *pdev) -{ - struct egpio_info *ei = platform_get_drvdata(pdev); - unsigned int irq, irq_end; - - if (ei->chained_irq) { - irq_end = ei->irq_start + ei->nirqs; - for (irq = ei->irq_start; irq < irq_end; irq++) { - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } - irq_set_chained_handler(ei->chained_irq, NULL); - device_init_wakeup(&pdev->dev, 0); - } - - return 0; -} - #ifdef CONFIG_PM static int egpio_suspend(struct platform_device *pdev, pm_message_t state) { @@ -416,8 +398,8 @@ static int egpio_resume(struct platform_device *pdev) static struct platform_driver egpio_driver = { .driver = { .name = "htc-egpio", + .suppress_bind_attrs = true, }, - .remove = __exit_p(egpio_remove), .suspend = egpio_suspend, .resume = egpio_resume, }; @@ -426,15 +408,5 @@ static int __init egpio_init(void) { return platform_driver_probe(&egpio_driver, egpio_probe); } - -static void __exit egpio_exit(void) -{ - platform_driver_unregister(&egpio_driver); -} - /* start early for dependencies */ subsys_initcall(egpio_init); -module_exit(egpio_exit) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kevin O'Connor "); -- cgit v1.2.3 From e0275034ad94c413090bab4bf65ccb70906725ed Mon Sep 17 00:00:00 2001 From: Axel Haslam Date: Thu, 3 Nov 2016 12:34:10 +0100 Subject: gpio: davinci: Use unique labels for each gpio chip The gpiod framework uses the chip label to match a specific chip. The davinci gpio driver, creates several chips using always the same label, which is not compatible with gpiod. To allow platform data to declare gpio lookup tables, and for drivers to use the gpiod framework, allocate unique label per registered chip. Signed-off-by: Axel Haslam Reviewed-by: Sekhar Nori Acked-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index dd262f00295d..9191056548fe 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -40,6 +40,7 @@ struct davinci_gpio_regs { typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ +#define MAX_LABEL_SIZE 20 static void __iomem *gpio_base; @@ -201,6 +202,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) struct davinci_gpio_regs __iomem *regs; struct device *dev = &pdev->dev; struct resource *res; + char label[MAX_LABEL_SIZE]; pdata = davinci_gpio_get_pdata(pdev); if (!pdata) { @@ -237,7 +239,10 @@ static int davinci_gpio_probe(struct platform_device *pdev) return PTR_ERR(gpio_base); for (i = 0, base = 0; base < ngpio; i++, base += 32) { - chips[i].chip.label = "DaVinci"; + snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", i); + chips[i].chip.label = devm_kstrdup(dev, label, GFP_KERNEL); + if (!chips[i].chip.label) + return -ENOMEM; chips[i].chip.direction_input = davinci_direction_in; chips[i].chip.get = davinci_gpio_get; -- cgit v1.2.3 From c82064f26f44ea13f097dfb58d5ffd4359dcabbb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Nov 2016 14:40:06 +0100 Subject: ACPI / gpio: avoid warning for gpio hogging code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The newly added acpi_gpiochip_scan_gpios function produces a few harmless warnings: drivers/gpio/gpiolib-acpi.c: In function ‘acpi_gpiochip_add’: drivers/gpio/gpiolib-acpi.c:925:7: error: ‘dflags’ may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/gpio/gpiolib-acpi.c:925:9: error: ‘lflags’ may be used uninitialized in this function [-Werror=maybe-uninitialized] The problem is that he compiler cannot know that a negative return value from fwnode_property_read_u32_array() or acpi_gpiochip_pin_to_gpio_offset() implies that the IS_ERR(gpio_desc) is true, as the value could in theory be below -MAX_ERRNO. The function already initializes its output values to zero, and moving that intialization a little higher up ensures that we can never have uninitialized data in the caller. Fixes: c80f1ba75df2 ("ACPI / gpio: Add hogging support") Signed-off-by: Arnd Bergmann Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 83fcfff19cd6..fec93b994fe9 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -866,6 +866,10 @@ static struct gpio_desc *acpi_gpiochip_parse_own_gpio( u32 gpios[2]; int ret; + *lflags = 0; + *dflags = 0; + *name = NULL; + ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios, ARRAY_SIZE(gpios)); if (ret < 0) @@ -879,10 +883,6 @@ static struct gpio_desc *acpi_gpiochip_parse_own_gpio( if (IS_ERR(desc)) return desc; - *lflags = 0; - *dflags = 0; - *name = NULL; - if (gpios[1]) *lflags |= GPIO_ACTIVE_LOW; -- cgit v1.2.3 From 9298539c0472c1bd7516c62d444e561493e3f26c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 12 Nov 2016 14:36:17 +0100 Subject: gpio: htc-egpio: add .get_direction() support This makes is possible to read out the current direction of a GPIO line on the HTC CPLD GPIO expander. Suggested-by: Russell King Signed-off-by: Linus Walleij --- drivers/gpio/gpio-htc-egpio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 5ab895b41819..27af52850927 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -225,6 +225,15 @@ static int egpio_direction_output(struct gpio_chip *chip, } } +static int egpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct egpio_chip *egpio; + + egpio = gpiochip_get_data(chip); + + return !test_bit(offset, &egpio->is_out); +} + static void egpio_write_cache(struct egpio_info *ei) { int i; @@ -327,6 +336,7 @@ static int __init egpio_probe(struct platform_device *pdev) chip->set = egpio_set; chip->direction_input = egpio_direction_input; chip->direction_output = egpio_direction_output; + chip->get_direction = egpio_get_direction; chip->base = pdata->chip[i].gpio_base; chip->ngpio = pdata->chip[i].num_gpios; -- cgit v1.2.3 From 24b35ed9a84ab1e7ad96c67434841120ca7fbf36 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 13 Nov 2016 11:50:22 +0100 Subject: gpio: htc-egpio: read output value from cache When the hardware is in output mode, reading the value from the hardware is not giving the correct value back. Instead read the value from the cache so we get the right value. Suggested-by: Russell King Signed-off-by: Linus Walleij --- drivers/gpio/gpio-htc-egpio.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 27af52850927..271356effb2e 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -160,10 +160,14 @@ static int egpio_get(struct gpio_chip *chip, unsigned offset) bit = egpio_bit(ei, offset); reg = egpio->reg_start + egpio_pos(ei, offset); - value = egpio_readw(ei, reg); - pr_debug("readw(%p + %x) = %x\n", - ei->base_addr, reg << ei->bus_shift, value); - return !!(value & bit); + if (test_bit(offset, &egpio->is_out)) { + return !!(egpio->cached_values & (1 << offset)); + } else { + value = egpio_readw(ei, reg); + pr_debug("readw(%p + %x) = %x\n", + ei->base_addr, reg << ei->bus_shift, value); + return !!(value & bit); + } } static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) -- cgit v1.2.3 From ad17731d7bd1c379f83d4bde844169588441266f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 13 Nov 2016 23:02:44 +0100 Subject: gpio: clamp values on gpio[d]_direction_output() I saw weird values != [0,1] being passed down to drivers in their .set_direction_output() callbacks. Go over the gpiolib and make sure to hammer it to [0,1] before hitting the driver to avoid undesired side effects. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0fc3a0d37c8..b7452c5223be 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2150,6 +2150,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input); static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { struct gpio_chip *gc = desc->gdev->chip; + int val = !!value; int ret; /* GPIOs used for IRQs shall not be set as output */ @@ -2169,7 +2170,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) goto set_output_value; } /* Emulate open drain by not actively driving the line high */ - if (value) + if (val) return gpiod_direction_input(desc); } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { @@ -2180,7 +2181,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) goto set_output_value; } /* Emulate open source by not actively driving the line low */ - if (!value) + if (!val) return gpiod_direction_input(desc); } else { /* Make sure to disable open drain/source hardware, if any */ @@ -2198,10 +2199,10 @@ set_output_value: return -EIO; } - ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), value); + ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); - trace_gpio_value(desc_to_gpio(desc), 0, value); + trace_gpio_value(desc_to_gpio(desc), 0, val); trace_gpio_direction(desc_to_gpio(desc), 0, ret); return ret; } @@ -2241,6 +2242,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) VALIDATE_DESC(desc); if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; + else + value = !!value; return _gpiod_direction_output_raw(desc, value); } EXPORT_SYMBOL_GPL(gpiod_direction_output); @@ -3094,7 +3097,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, /* Process flags */ if (dflags & GPIOD_FLAGS_BIT_DIR_OUT) status = gpiod_direction_output(desc, - dflags & GPIOD_FLAGS_BIT_DIR_VAL); + !!(dflags & GPIOD_FLAGS_BIT_DIR_VAL)); else status = gpiod_direction_input(desc); -- cgit v1.2.3 From 3940c34ac898b15afb72271394444199401bbe99 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 Nov 2016 00:09:07 +0100 Subject: gpio: tag line labels used for interrupts When a GPIO line is marked as used for an interrupt, it is helpful to set the label to "interrupt" so we know what is going on when inspecting the lines. If a GPIO is already properly named by gpiod_get*() we don't need to do this. It only happens when a line is used from the irqchip side of a GPIO driver without communicating with the GPIO side, such as when gpiochip is used as interrupt provider in the device tree. If the line is still marked as used by "interrupt" when we unmark it as used by an interrupt, also remove this label from the descriptor. Also shape up the code around unmarking IRQ lines. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b7452c5223be..e97e88e48191 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2685,6 +2685,15 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) } set_bit(FLAG_USED_AS_IRQ, &desc->flags); + + /* + * If the consumer has not set up a label (such as when the + * IRQ is referenced from .to_irq()) we set up a label here + * so it is clear this is used as an interrupt. + */ + if (!desc->label) + desc_set_label(desc, "interrupt"); + return 0; } EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); @@ -2699,10 +2708,17 @@ EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); */ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) { - if (offset >= chip->ngpio) + struct gpio_desc *desc; + + desc = gpiochip_get_desc(chip, offset); + if (IS_ERR(desc)) return; - clear_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); + clear_bit(FLAG_USED_AS_IRQ, &desc->flags); + + /* If we only had this marking, erase it */ + if (desc->label && !strcmp(desc->label, "interrupt")) + desc_set_label(desc, NULL); } EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); -- cgit v1.2.3 From 5261bee8f29ca8f1a5ddd96ffcaa496414168ed0 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 14 Nov 2016 20:52:25 +0800 Subject: gpio: intel-mid: use builtin_pci_driver Use builtin_pci_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-intel-mid.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index 164de64b11fc..a1e44c221f66 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -421,9 +421,4 @@ static struct pci_driver intel_gpio_driver = { }, }; -static int __init intel_gpio_init(void) -{ - return pci_register_driver(&intel_gpio_driver); -} - -device_initcall(intel_gpio_init); +builtin_pci_driver(intel_gpio_driver); -- cgit v1.2.3 From 3107d572349f3d45b531bff4243dc6f1b630dedc Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Wed, 16 Nov 2016 14:47:23 +0530 Subject: gpio: max77620: add compatible string to device id list Adding max20024 compatible string to the device id list to support both max77620 and max20024 devices. Signed-off-by: Venkat Reddy Talla Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max77620.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index df035866d7a2..ec8de4190db9 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -290,6 +290,7 @@ static int max77620_gpio_probe(struct platform_device *pdev) static const struct platform_device_id max77620_gpio_devtype[] = { { .name = "max77620-gpio", }, + { .name = "max20024-gpio", }, {}, }; MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype); -- cgit v1.2.3 From 6f1bd54ca49cdd4f98386212c8029e2d5b9f7865 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 18 Nov 2016 22:12:27 +0800 Subject: gpio: etraxfs: use builtin_platform_driver Use builtin_platform_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-etraxfs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 00b022c9acb3..a254d5b07b94 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -471,9 +471,4 @@ static struct platform_driver etraxfs_gpio_driver = { .probe = etraxfs_gpio_probe, }; -static int __init etraxfs_gpio_init(void) -{ - return platform_driver_register(&etraxfs_gpio_driver); -} - -device_initcall(etraxfs_gpio_init); +builtin_platform_driver(etraxfs_gpio_driver); -- cgit v1.2.3 From d65aa4b67b4f47f303bdeaef1e4d42ef18e6b293 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 18 Nov 2016 22:12:28 +0800 Subject: gpio: mb86s7x: use builtin_platform_driver Use builtin_platform_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mb86s7x.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index d55af50e7034..ffb73f688ae1 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -217,8 +217,4 @@ static struct platform_driver mb86s70_gpio_driver = { .remove = mb86s70_gpio_remove, }; -static int __init mb86s70_gpio_init(void) -{ - return platform_driver_register(&mb86s70_gpio_driver); -} -device_initcall(mb86s70_gpio_init); +builtin_platform_driver(mb86s70_gpio_driver); -- cgit v1.2.3 From 72aba2e25e0fad0c5bd24a1dd10725c99fcef3c6 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Sun, 20 Nov 2016 17:37:25 +0000 Subject: gpio: x86: update config dependencies for x86 specific hardware The devices here are specific to x86 so lets depend on x86. Signed-off-by: Peter Robinson Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cdff5748f5be..b19e84747f31 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -455,7 +455,7 @@ config GPIO_VR41XX config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" - depends on PCI + depends on (X86 || COMPILE_TEST) && PCI select MFD_CORE select MFD_VX855 help @@ -607,7 +607,7 @@ config GPIO_IT87 config GPIO_SCH tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" - depends on PCI + depends on (X86 || COMPILE_TEST) && PCI select MFD_CORE select LPC_SCH help @@ -832,7 +832,7 @@ config GPIO_ARIZONA config GPIO_CRYSTAL_COVE tristate "GPIO support for Crystal Cove PMIC" - depends on INTEL_SOC_PMIC + depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC select GPIOLIB_IRQCHIP help Support for GPIO pins on Crystal Cove PMIC. @@ -845,6 +845,7 @@ config GPIO_CRYSTAL_COVE config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" + depends on X86 || MIPS || COMPILE_TEST depends on MFD_CS5535 help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that @@ -937,7 +938,7 @@ config GPIO_MAX77620 config GPIO_MSIC bool "Intel MSIC mixed signal gpio support" - depends on MFD_INTEL_MSIC + depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC help Enable support for GPIO on intel MSIC controllers found in intel MID devices @@ -1038,7 +1039,7 @@ config GPIO_UCB1400 config GPIO_WHISKEY_COVE tristate "GPIO support for Whiskey Cove PMIC" - depends on INTEL_SOC_PMIC + depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC select GPIOLIB_IRQCHIP help Support for GPIO pins on Whiskey Cove PMIC. @@ -1077,6 +1078,7 @@ menu "PCI GPIO expanders" config GPIO_AMD8111 tristate "AMD 8111 GPIO driver" + depends on X86 || COMPILE_TEST help The AMD 8111 south bridge contains 32 GPIO pins which can be used. @@ -1118,6 +1120,7 @@ config GPIO_MERRIFIELD config GPIO_ML_IOH tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" + depends on X86 || COMPILE_TEST select GENERIC_IRQ_CHIP help ML7213 is companion chip for Intel Atom E6xx series. -- cgit v1.2.3 From 752fda89f5f19531351304529e6386634ea1bf27 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Sun, 20 Nov 2016 17:44:48 +0000 Subject: gpio: zx: depend on ARCH_ZX Set GPIO_ZX to depend on ARCH_ZX as it's SOC specific. Signed-off-by: Peter Robinson Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b19e84747f31..3d39ff7a5594 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -524,6 +524,7 @@ config GPIO_ZYNQ config GPIO_ZX bool "ZTE ZX GPIO support" + depends on ARCH_ZX || COMPILE_TEST select GPIOLIB_IRQCHIP help Say yes here to support the GPIO device on ZTE ZX SoCs. -- cgit v1.2.3 From 22eaf13c7ff37a92f4192f8dd1ebff31c4920822 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Sun, 20 Nov 2016 17:48:36 +0000 Subject: gpio: em: depnd on ARCH_SHMOBILE The GPIO_EM is part of the Renesas SoCs so depend on the arch. Signed-off-by: Peter Robinson [Changed to depend on ARCH_EMEV2] Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3d39ff7a5594..28ed4ccc15b4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -171,7 +171,7 @@ config GPIO_DWAPB config GPIO_EM tristate "Emma Mobile GPIO" - depends on ARM && OF_GPIO + depends on (ARCH_EMEV2 || COMPILE_TEST) && OF_GPIO help Say yes here to support GPIO on Renesas Emma Mobile SoCs. -- cgit v1.2.3 From 1516c6350aa2770b8a5e36d40c3ec5078f92ba70 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 23 Nov 2016 23:21:17 +0100 Subject: gpio: stmpe: fix interrupt handling bug commit 43db289d00c6 ("gpio: stmpe: Rework registers access") reworked the STMPE register access so as to use [STMPE_IDX_*_LSB + i] to access the 8bit register for a certain bank, assuming the CSB and MSB will follow after the enumerator. For this to work the index needs to go from (size-1) to 0 not 0 to (size-1). However for the GPIO IRQ handler, the status registers we read register MSB + 3 bytes ahead for the 24 bit GPIOs and index registers from MSB upwards and run an index i over the registers UNLESS we are STMPE1600. This is not working when we get to clearing the interrupt EDGE status register STMPE_IDX_GPEDR_[LCM]SB: it is indexed like all other registers [STMPE_IDX_*_LSB + i] but in this loop we index from 0 to get the right bank index for the calculations, and we need to just add i to the MSB. Before this, interrupts on the STMPE2401 were broken, this patch fixes it so it works again. Cc: stable@vger.kernel.org Cc: Patrice Chotard Fixes: 43db289d00c6 ("gpio: stmpe: Rework registers access") Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stmpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index e7d422a6b90b..e2e1b16a42db 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -413,7 +413,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) stmpe->partnum != STMPE1801) { stmpe_reg_write(stmpe, statmsbreg + i, status[i]); stmpe_reg_write(stmpe, - stmpe->regs[STMPE_IDX_GPEDR_LSB + i], + stmpe->regs[STMPE_IDX_GPEDR_MSB] + i, status[i]); } } -- cgit v1.2.3 From 1d2b2ac05ac6ea59b78e1e239180e69ce25cc85a Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 23 Nov 2016 15:11:50 +0100 Subject: gpio: axp209: use correct register for GPIO input status The GPIO input status was read from control register (AXP20X_GPIO[210]_CTRL) instead of status register (AXP20X_GPIO20_SS). Signed-off-by: Quentin Schulz Signed-off-by: Linus Walleij --- drivers/gpio/gpio-axp209.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c index d9c2a517c6df..4a346b7b4172 100644 --- a/drivers/gpio/gpio-axp209.c +++ b/drivers/gpio/gpio-axp209.c @@ -64,13 +64,9 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) { struct axp20x_gpio *gpio = gpiochip_get_data(chip); unsigned int val; - int reg, ret; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; + int ret; - ret = regmap_read(gpio->regmap, reg, &val); + ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val); if (ret) return ret; -- cgit v1.2.3 From df950da188f7209a640f6eb3afda171a5afdf71f Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Nov 2016 22:47:48 +0800 Subject: gpio: vf610: use builtin_platform_driver Use builtin_platform_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vf610.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 3edb09cb9ee0..521fbe338589 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -283,8 +283,4 @@ static struct platform_driver vf610_gpio_driver = { .probe = vf610_gpio_probe, }; -static int __init gpio_vf610_init(void) -{ - return platform_driver_register(&vf610_gpio_driver); -} -device_initcall(gpio_vf610_init); +builtin_platform_driver(vf610_gpio_driver); -- cgit v1.2.3 From d245b3f9bd36f02fd641cba9931d8b4c77126e74 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 24 Nov 2016 10:57:25 +0100 Subject: gpio: simplify adding threaded interrupts This tries to simplify the use of CONFIG_GPIOLIB_IRQCHIP when using threaded interrupts: add a new call gpiochip_irqchip_add_nested() to indicate that we're dealing with a nested rather than a chained irqchip, then create a separate gpiochip_set_nested_irqchip() to mirror the gpiochip_set_chained_irqchip() call to connect the parent and child interrupts. In the nested case gpiochip_set_nested_irqchip() does nothing more than call irq_set_parent() on each valid child interrupt, which has little semantic effect in the kernel, but this is probably still formally correct. Update all drivers using nested interrupts to use gpiochip_irqchip_add_nested() so we can now see clearly which these users are. The DLN2 driver can drop its specific hack with .irq_not_threaded as we now recognize whether a chip is threaded or not from its use of gpiochip_irqchip_add_nested() signature rather than from inspecting .can_sleep. We rename the .irq_parent to .irq_chained_parent since this parent IRQ is only really kept around for the chained interrupt handlers. Cc: Lars Poeschel Cc: Octavian Purdila Cc: Daniel Baluta Cc: Bin Gao Cc: Mika Westerberg Cc: Ajay Thomas Cc: Semen Protsenko Cc: Alexander Stein Cc: Phil Reid Cc: Bartosz Golaszewski Cc: Patrice Chotard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adnp.c | 10 +++--- drivers/gpio/gpio-crystalcove.c | 4 +-- drivers/gpio/gpio-dln2.c | 1 - drivers/gpio/gpio-max732x.c | 17 +++++----- drivers/gpio/gpio-mcp23s08.c | 17 +++++----- drivers/gpio/gpio-pca953x.c | 16 +++++----- drivers/gpio/gpio-pcf857x.c | 11 ++++--- drivers/gpio/gpio-stmpe.c | 17 +++++----- drivers/gpio/gpio-tc3589x.c | 17 +++++----- drivers/gpio/gpio-wcove.c | 4 +-- drivers/gpio/gpiolib.c | 69 +++++++++++++++++++++++++++++++++-------- 11 files changed, 111 insertions(+), 72 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 8ff7b0d3eac6..7a5c0a93e1ff 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -468,11 +468,11 @@ static int adnp_irq_setup(struct adnp *adnp) return err; } - err = gpiochip_irqchip_add(chip, - &adnp_irq_chip, - 0, - handle_simple_irq, - IRQ_TYPE_NONE); + err = gpiochip_irqchip_add_nested(chip, + &adnp_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); if (err) { dev_err(chip->parent, "could not connect irqchip to gpiochip\n"); diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 7c446d118cd6..d0022d655a09 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -351,8 +351,8 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) return retval; } - gpiochip_irqchip_add(&cg->chip, &crystalcove_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + gpiochip_irqchip_add_nested(&cg->chip, &crystalcove_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler, IRQF_ONESHOT, KBUILD_MODNAME, cg); diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index f7a60a441e95..5d38b08d1ee2 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -467,7 +467,6 @@ static int dln2_gpio_probe(struct platform_device *pdev) dln2->gpio.base = -1; dln2->gpio.ngpio = pins; dln2->gpio.can_sleep = true; - dln2->gpio.irq_not_threaded = true; dln2->gpio.set = dln2_gpio_set; dln2->gpio.get = dln2_gpio_get; dln2->gpio.request = dln2_gpio_request; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index a9aaf9d822b4..4ea4c6a1313b 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -520,20 +520,19 @@ static int max732x_irq_setup(struct max732x_chip *chip, client->irq); return ret; } - ret = gpiochip_irqchip_add(&chip->gpio_chip, - &max732x_irq_chip, - irq_base, - handle_simple_irq, - IRQ_TYPE_NONE); + ret = gpiochip_irqchip_add_nested(&chip->gpio_chip, + &max732x_irq_chip, + irq_base, + handle_simple_irq, + IRQ_TYPE_NONE); if (ret) { dev_err(&client->dev, "could not connect irqchip to gpiochip\n"); return ret; } - gpiochip_set_chained_irqchip(&chip->gpio_chip, - &max732x_irq_chip, - client->irq, - NULL); + gpiochip_set_nested_irqchip(&chip->gpio_chip, + &max732x_irq_chip, + client->irq); } return 0; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 99d37b56c258..504550665091 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -473,21 +473,20 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) return err; } - err = gpiochip_irqchip_add(chip, - &mcp23s08_irq_chip, - 0, - handle_simple_irq, - IRQ_TYPE_NONE); + err = gpiochip_irqchip_add_nested(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; } - gpiochip_set_chained_irqchip(chip, - &mcp23s08_irq_chip, - mcp->irq, - NULL); + gpiochip_set_nested_irqchip(chip, + &mcp23s08_irq_chip, + mcp->irq); return 0; } diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index e422568e14ad..121108b6602d 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -635,20 +635,20 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return ret; } - ret = gpiochip_irqchip_add(&chip->gpio_chip, - &pca953x_irq_chip, - irq_base, - handle_simple_irq, - IRQ_TYPE_NONE); + ret = gpiochip_irqchip_add_nested(&chip->gpio_chip, + &pca953x_irq_chip, + irq_base, + handle_simple_irq, + IRQ_TYPE_NONE); if (ret) { dev_err(&client->dev, "could not connect irqchip to gpiochip\n"); return ret; } - gpiochip_set_chained_irqchip(&chip->gpio_chip, - &pca953x_irq_chip, - client->irq, NULL); + gpiochip_set_nested_irqchip(&chip->gpio_chip, + &pca953x_irq_chip, + client->irq); } return 0; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index d168410e2338..895af42a4513 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -378,9 +378,10 @@ static int pcf857x_probe(struct i2c_client *client, /* Enable irqchip if we have an interrupt */ if (client->irq) { - status = gpiochip_irqchip_add(&gpio->chip, &pcf857x_irq_chip, - 0, handle_level_irq, - IRQ_TYPE_NONE); + status = gpiochip_irqchip_add_nested(&gpio->chip, + &pcf857x_irq_chip, + 0, handle_level_irq, + IRQ_TYPE_NONE); if (status) { dev_err(&client->dev, "cannot add irqchip\n"); goto fail; @@ -393,8 +394,8 @@ static int pcf857x_probe(struct i2c_client *client, if (status) goto fail; - gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip, - client->irq, NULL); + gpiochip_set_nested_irqchip(&gpio->chip, &pcf857x_irq_chip, + client->irq); gpio->irq_parent = client->irq; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index e7d422a6b90b..e194d8ad8612 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -484,21 +484,20 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (stmpe_gpio->norequest_mask & BIT(i)) clear_bit(i, stmpe_gpio->chip.irq_valid_mask); } - ret = gpiochip_irqchip_add(&stmpe_gpio->chip, - &stmpe_gpio_irq_chip, - 0, - handle_simple_irq, - IRQ_TYPE_NONE); + ret = gpiochip_irqchip_add_nested(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); if (ret) { dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); goto out_disable; } - gpiochip_set_chained_irqchip(&stmpe_gpio->chip, - &stmpe_gpio_irq_chip, - irq, - NULL); + gpiochip_set_nested_irqchip(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + irq); } platform_set_drvdata(pdev, stmpe_gpio); diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 5a5a6cb00eea..f041965f1b03 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -337,21 +337,20 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) return ret; } - ret = gpiochip_irqchip_add(&tc3589x_gpio->chip, - &tc3589x_gpio_irq_chip, - 0, - handle_simple_irq, - IRQ_TYPE_NONE); + ret = gpiochip_irqchip_add_nested(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); if (ret) { dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); return ret; } - gpiochip_set_chained_irqchip(&tc3589x_gpio->chip, - &tc3589x_gpio_irq_chip, - irq, - NULL); + gpiochip_set_nested_irqchip(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + irq); platform_set_drvdata(pdev, tc3589x_gpio); diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index d0ddba7a9d08..88f29601f8de 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -426,8 +426,8 @@ static int wcove_gpio_probe(struct platform_device *pdev) return ret; } - ret = gpiochip_irqchip_add(&wg->chip, &wcove_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + ret = gpiochip_irqchip_add_nested(&wg->chip, &wcove_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); if (ret) { dev_err(dev, "Failed to add irqchip: %d\n", ret); return ret; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0fc3a0d37c8..7be4fdafb1a3 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1439,7 +1439,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, } /** - * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip + * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip * @gpiochip: the gpiochip to set the irqchip chain to * @irqchip: the irqchip to chain to the gpiochip * @parent_irq: the irq number corresponding to the parent IRQ for this @@ -1448,10 +1448,10 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, * coming out of the gpiochip. If the interrupt is nested rather than * cascaded, pass NULL in this handler argument */ -void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, - struct irq_chip *irqchip, - int parent_irq, - irq_flow_handler_t parent_handler) +static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + int parent_irq, + irq_flow_handler_t parent_handler) { unsigned int offset; @@ -1475,7 +1475,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, irq_set_chained_handler_and_data(parent_irq, parent_handler, gpiochip); - gpiochip->irq_parent = parent_irq; + gpiochip->irq_chained_parent = parent_irq; } /* Set the parent IRQ for all affected IRQs */ @@ -1486,8 +1486,47 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, parent_irq); } } + +/** + * gpiochip_set_chained_irqchip() - connects a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to set the irqchip chain to + * @irqchip: the irqchip to chain to the gpiochip + * @parent_irq: the irq number corresponding to the parent IRQ for this + * chained irqchip + * @parent_handler: the parent interrupt handler for the accumulated IRQ + * coming out of the gpiochip. If the interrupt is nested rather than + * cascaded, pass NULL in this handler argument + */ +void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + int parent_irq, + irq_flow_handler_t parent_handler) +{ + gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, + parent_handler); +} EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); +/** + * gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip + * @gpiochip: the gpiochip to set the irqchip nested handler to + * @irqchip: the irqchip to nest to the gpiochip + * @parent_irq: the irq number corresponding to the parent IRQ for this + * nested irqchip + */ +void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + int parent_irq) +{ + if (!gpiochip->irq_nested) { + chip_err(gpiochip, "tried to nest a chained gpiochip\n"); + return; + } + gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, + NULL); +} +EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip); + /** * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip * @d: the irqdomain used by this irqchip @@ -1510,8 +1549,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, */ irq_set_lockdep_class(irq, chip->lock_key); irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); - /* Chips that can sleep need nested thread handlers */ - if (chip->can_sleep && !chip->irq_not_threaded) + /* Chips that use nested thread handlers have them marked */ + if (chip->irq_nested) irq_set_nested_thread(irq, 1); irq_set_noprobe(irq); @@ -1529,7 +1568,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) { struct gpio_chip *chip = d->host_data; - if (chip->can_sleep) + if (chip->irq_nested) irq_set_nested_thread(irq, 0); irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); @@ -1584,9 +1623,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) acpi_gpiochip_free_interrupts(gpiochip); - if (gpiochip->irq_parent) { - irq_set_chained_handler(gpiochip->irq_parent, NULL); - irq_set_handler_data(gpiochip->irq_parent, NULL); + if (gpiochip->irq_chained_parent) { + irq_set_chained_handler(gpiochip->irq_chained_parent, NULL); + irq_set_handler_data(gpiochip->irq_chained_parent, NULL); } /* Remove all IRQ mappings and delete the domain */ @@ -1610,7 +1649,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) } /** - * gpiochip_irqchip_add() - adds an irqchip to a gpiochip + * _gpiochip_irqchip_add() - adds an irqchip to a gpiochip * @gpiochip: the gpiochip to add the irqchip to * @irqchip: the irqchip to add to the gpiochip * @first_irq: if not dynamically assigned, the base (first) IRQ to @@ -1618,6 +1657,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) * @handler: the irq handler to use (often a predefined irq core function) * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE * to have the core avoid setting up any default type in the hardware. + * @nested: whether this is a nested irqchip calling handle_nested_irq() + * in its IRQ handler * @lock_key: lockdep class * * This function closely associates a certain irqchip with a certain @@ -1639,6 +1680,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, unsigned int first_irq, irq_flow_handler_t handler, unsigned int type, + bool nested, struct lock_class_key *lock_key) { struct device_node *of_node; @@ -1653,6 +1695,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, pr_err("missing gpiochip .dev parent pointer\n"); return -EINVAL; } + gpiochip->irq_nested = nested; of_node = gpiochip->parent->of_node; #ifdef CONFIG_OF_GPIO /* -- cgit v1.2.3 From 35ca3f61617db77364e40c1977952c5ee0a776cb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 24 Nov 2016 13:27:54 +0100 Subject: gpio: set explicit nesting on drivers The ADNP, CrystalCove and WhiskeyCove are all nested GPIO irqchips, but were avoiding to connect the parent IRQ to the gpiochip. This works, but is kind of sloppy as the child IRQs are not marked as having the parent IRQ as parent. Cc: Mika Westerberg Cc: Ajay Thomas Cc: Bin Gao Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adnp.c | 2 ++ drivers/gpio/gpio-crystalcove.c | 2 ++ drivers/gpio/gpio-wcove.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 7a5c0a93e1ff..89863ea25de1 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -479,6 +479,8 @@ static int adnp_irq_setup(struct adnp *adnp) return err; } + gpiochip_set_nested_irqchip(chip, &adnp_irq_chip, adnp->client->irq); + return 0; } diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index d0022d655a09..2197368cc899 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -362,6 +362,8 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) return retval; } + gpiochip_set_nested_irqchip(&cg->chip, &crystalcove_irqchip, irq); + return 0; } diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 88f29601f8de..34baee5b1dd6 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -446,6 +446,8 @@ static int wcove_gpio_probe(struct platform_device *pdev) return ret; } + gpiochip_set_nested_irqchip(&wg->chip, &wcove_irqchip, virq); + return 0; } -- cgit v1.2.3 From 9c18be8e9342110f6ac89e5c0dc4f6380be8aaa6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Nov 2016 10:41:37 +0100 Subject: gpio: pl061: use local state for parent IRQ storage The driver is poking around in the struct gpio_chip internals, which is a no-no. Use a variable in the local state container. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 6e3c1430616f..8838a44351ce 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -55,6 +55,7 @@ struct pl061_gpio { void __iomem *base; struct gpio_chip gc; + int parent_irq; #ifdef CONFIG_PM struct pl061_context_save_regs csave_regs; @@ -276,8 +277,9 @@ static void pl061_irq_ack(struct irq_data *d) static int pl061_irq_set_wake(struct irq_data *d, unsigned int state) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = gpiochip_get_data(gc); - return irq_set_irq_wake(gc->irq_parent, state); + return irq_set_irq_wake(chip->parent_irq, state); } static struct irq_chip pl061_irqchip = { @@ -345,6 +347,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) dev_err(&adev->dev, "invalid IRQ\n"); return -ENODEV; } + chip->parent_irq = irq; ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, irq_base, handle_bad_irq, -- cgit v1.2.3 From 538f76c566eb37f41d4406ed4c6e7ea387b7032f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Nov 2016 10:43:15 +0100 Subject: gpio: pl061: rename state container struct The PL061 state container is named "pl061_gpio", let's rename it to simply pl061. Less is more. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 8838a44351ce..b944aaefb59f 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -50,7 +50,7 @@ struct pl061_context_save_regs { }; #endif -struct pl061_gpio { +struct pl061 { spinlock_t lock; void __iomem *base; @@ -64,14 +64,14 @@ struct pl061_gpio { static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) { - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); return !(readb(chip->base + GPIODIR) & BIT(offset)); } static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) { - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); unsigned long flags; unsigned char gpiodir; @@ -87,7 +87,7 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, int value) { - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); unsigned long flags; unsigned char gpiodir; @@ -109,14 +109,14 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, static int pl061_get_value(struct gpio_chip *gc, unsigned offset) { - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); return !!readb(chip->base + (BIT(offset + 2))); } static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) { - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); writeb(!!value << offset, chip->base + (BIT(offset + 2))); } @@ -124,7 +124,7 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) static int pl061_irq_type(struct irq_data *d, unsigned trigger) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -214,7 +214,7 @@ static void pl061_irq_handler(struct irq_desc *desc) unsigned long pending; int offset; struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); @@ -232,7 +232,7 @@ static void pl061_irq_handler(struct irq_desc *desc) static void pl061_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; @@ -245,7 +245,7 @@ static void pl061_irq_mask(struct irq_data *d) static void pl061_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; @@ -266,7 +266,7 @@ static void pl061_irq_unmask(struct irq_data *d) static void pl061_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); spin_lock(&chip->lock); @@ -277,7 +277,7 @@ static void pl061_irq_ack(struct irq_data *d) static int pl061_irq_set_wake(struct irq_data *d, unsigned int state) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061_gpio *chip = gpiochip_get_data(gc); + struct pl061 *chip = gpiochip_get_data(gc); return irq_set_irq_wake(chip->parent_irq, state); } @@ -295,7 +295,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct pl061_platform_data *pdata = dev_get_platdata(dev); - struct pl061_gpio *chip; + struct pl061 *chip; int ret, irq, i, irq_base; chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); @@ -379,7 +379,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) #ifdef CONFIG_PM static int pl061_suspend(struct device *dev) { - struct pl061_gpio *chip = dev_get_drvdata(dev); + struct pl061 *chip = dev_get_drvdata(dev); int offset; chip->csave_regs.gpio_data = 0; @@ -400,7 +400,7 @@ static int pl061_suspend(struct device *dev) static int pl061_resume(struct device *dev) { - struct pl061_gpio *chip = dev_get_drvdata(dev); + struct pl061 *chip = dev_get_drvdata(dev); int offset; for (offset = 0; offset < PL061_GPIO_NR; offset++) { -- cgit v1.2.3 From 2796325ffadda1ef149c0f51d29d2c7d4d72d556 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Nov 2016 10:48:40 +0100 Subject: gpio: pl061: rename variable from chip to pl061 Rename the local variable "chip" referring to the struct pl061 state container to "pl061": we already have gpio_chip and irq_chip in the driver, we are needlessly adding yet another "chip" to the confusion. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 186 +++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 93 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b944aaefb59f..47f397236417 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -64,22 +64,22 @@ struct pl061 { static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) { - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); - return !(readb(chip->base + GPIODIR) & BIT(offset)); + return !(readb(pl061->base + GPIODIR) & BIT(offset)); } static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) { - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); unsigned long flags; unsigned char gpiodir; - spin_lock_irqsave(&chip->lock, flags); - gpiodir = readb(chip->base + GPIODIR); + spin_lock_irqsave(&pl061->lock, flags); + gpiodir = readb(pl061->base + GPIODIR); gpiodir &= ~(BIT(offset)); - writeb(gpiodir, chip->base + GPIODIR); - spin_unlock_irqrestore(&chip->lock, flags); + writeb(gpiodir, pl061->base + GPIODIR); + spin_unlock_irqrestore(&pl061->lock, flags); return 0; } @@ -87,44 +87,44 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, int value) { - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); unsigned long flags; unsigned char gpiodir; - spin_lock_irqsave(&chip->lock, flags); - writeb(!!value << offset, chip->base + (BIT(offset + 2))); - gpiodir = readb(chip->base + GPIODIR); + spin_lock_irqsave(&pl061->lock, flags); + writeb(!!value << offset, pl061->base + (BIT(offset + 2))); + gpiodir = readb(pl061->base + GPIODIR); gpiodir |= BIT(offset); - writeb(gpiodir, chip->base + GPIODIR); + writeb(gpiodir, pl061->base + GPIODIR); /* * gpio value is set again, because pl061 doesn't allow to set value of * a gpio pin before configuring it in OUT mode. */ - writeb(!!value << offset, chip->base + (BIT(offset + 2))); - spin_unlock_irqrestore(&chip->lock, flags); + writeb(!!value << offset, pl061->base + (BIT(offset + 2))); + spin_unlock_irqrestore(&pl061->lock, flags); return 0; } static int pl061_get_value(struct gpio_chip *gc, unsigned offset) { - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); - return !!readb(chip->base + (BIT(offset + 2))); + return !!readb(pl061->base + (BIT(offset + 2))); } static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) { - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); - writeb(!!value << offset, chip->base + (BIT(offset + 2))); + writeb(!!value << offset, pl061->base + (BIT(offset + 2))); } static int pl061_irq_type(struct irq_data *d, unsigned trigger) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -144,11 +144,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) } - spin_lock_irqsave(&chip->lock, flags); + spin_lock_irqsave(&pl061->lock, flags); - gpioiev = readb(chip->base + GPIOIEV); - gpiois = readb(chip->base + GPIOIS); - gpioibe = readb(chip->base + GPIOIBE); + gpioiev = readb(pl061->base + GPIOIEV); + gpiois = readb(pl061->base + GPIOIS); + gpioibe = readb(pl061->base + GPIOIBE); if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH; @@ -200,11 +200,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) offset); } - writeb(gpiois, chip->base + GPIOIS); - writeb(gpioibe, chip->base + GPIOIBE); - writeb(gpioiev, chip->base + GPIOIEV); + writeb(gpiois, pl061->base + GPIOIS); + writeb(gpioibe, pl061->base + GPIOIBE); + writeb(gpioiev, pl061->base + GPIOIEV); - spin_unlock_irqrestore(&chip->lock, flags); + spin_unlock_irqrestore(&pl061->lock, flags); return 0; } @@ -214,12 +214,12 @@ static void pl061_irq_handler(struct irq_desc *desc) unsigned long pending; int offset; struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); - pending = readb(chip->base + GPIOMIS); + pending = readb(pl061->base + GPIOMIS); if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(irq_find_mapping(gc->irqdomain, @@ -232,27 +232,27 @@ static void pl061_irq_handler(struct irq_desc *desc) static void pl061_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; - spin_lock(&chip->lock); - gpioie = readb(chip->base + GPIOIE) & ~mask; - writeb(gpioie, chip->base + GPIOIE); - spin_unlock(&chip->lock); + spin_lock(&pl061->lock); + gpioie = readb(pl061->base + GPIOIE) & ~mask; + writeb(gpioie, pl061->base + GPIOIE); + spin_unlock(&pl061->lock); } static void pl061_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; - spin_lock(&chip->lock); - gpioie = readb(chip->base + GPIOIE) | mask; - writeb(gpioie, chip->base + GPIOIE); - spin_unlock(&chip->lock); + spin_lock(&pl061->lock); + gpioie = readb(pl061->base + GPIOIE) | mask; + writeb(gpioie, pl061->base + GPIOIE); + spin_unlock(&pl061->lock); } /** @@ -266,20 +266,20 @@ static void pl061_irq_unmask(struct irq_data *d) static void pl061_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); - spin_lock(&chip->lock); - writeb(mask, chip->base + GPIOIC); - spin_unlock(&chip->lock); + spin_lock(&pl061->lock); + writeb(mask, pl061->base + GPIOIC); + spin_unlock(&pl061->lock); } static int pl061_irq_set_wake(struct irq_data *d, unsigned int state) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct pl061 *chip = gpiochip_get_data(gc); + struct pl061 *pl061 = gpiochip_get_data(gc); - return irq_set_irq_wake(chip->parent_irq, state); + return irq_set_irq_wake(pl061->parent_irq, state); } static struct irq_chip pl061_irqchip = { @@ -295,81 +295,81 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct pl061_platform_data *pdata = dev_get_platdata(dev); - struct pl061 *chip; + struct pl061 *pl061; int ret, irq, i, irq_base; - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL); + if (pl061 == NULL) return -ENOMEM; if (pdata) { - chip->gc.base = pdata->gpio_base; + pl061->gc.base = pdata->gpio_base; irq_base = pdata->irq_base; if (irq_base <= 0) { dev_err(&adev->dev, "invalid IRQ base in pdata\n"); return -ENODEV; } } else { - chip->gc.base = -1; + pl061->gc.base = -1; irq_base = 0; } - chip->base = devm_ioremap_resource(dev, &adev->res); - if (IS_ERR(chip->base)) - return PTR_ERR(chip->base); + pl061->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(pl061->base)) + return PTR_ERR(pl061->base); - spin_lock_init(&chip->lock); + spin_lock_init(&pl061->lock); if (of_property_read_bool(dev->of_node, "gpio-ranges")) { - chip->gc.request = gpiochip_generic_request; - chip->gc.free = gpiochip_generic_free; + pl061->gc.request = gpiochip_generic_request; + pl061->gc.free = gpiochip_generic_free; } - chip->gc.get_direction = pl061_get_direction; - chip->gc.direction_input = pl061_direction_input; - chip->gc.direction_output = pl061_direction_output; - chip->gc.get = pl061_get_value; - chip->gc.set = pl061_set_value; - chip->gc.ngpio = PL061_GPIO_NR; - chip->gc.label = dev_name(dev); - chip->gc.parent = dev; - chip->gc.owner = THIS_MODULE; - - ret = gpiochip_add_data(&chip->gc, chip); + pl061->gc.get_direction = pl061_get_direction; + pl061->gc.direction_input = pl061_direction_input; + pl061->gc.direction_output = pl061_direction_output; + pl061->gc.get = pl061_get_value; + pl061->gc.set = pl061_set_value; + pl061->gc.ngpio = PL061_GPIO_NR; + pl061->gc.label = dev_name(dev); + pl061->gc.parent = dev; + pl061->gc.owner = THIS_MODULE; + + ret = gpiochip_add_data(&pl061->gc, pl061); if (ret) return ret; /* * irq_chip support */ - writeb(0, chip->base + GPIOIE); /* disable irqs */ + writeb(0, pl061->base + GPIOIE); /* disable irqs */ irq = adev->irq[0]; if (irq < 0) { dev_err(&adev->dev, "invalid IRQ\n"); return -ENODEV; } - chip->parent_irq = irq; + pl061->parent_irq = irq; - ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, + ret = gpiochip_irqchip_add(&pl061->gc, &pl061_irqchip, irq_base, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_info(&adev->dev, "could not add irqchip\n"); return ret; } - gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip, + gpiochip_set_chained_irqchip(&pl061->gc, &pl061_irqchip, irq, pl061_irq_handler); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { if (pdata->directions & (BIT(i))) - pl061_direction_output(&chip->gc, i, + pl061_direction_output(&pl061->gc, i, pdata->values & (BIT(i))); else - pl061_direction_input(&chip->gc, i); + pl061_direction_input(&pl061->gc, i); } } - amba_set_drvdata(adev, chip); + amba_set_drvdata(adev, pl061); dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", &adev->res.start); @@ -379,20 +379,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) #ifdef CONFIG_PM static int pl061_suspend(struct device *dev) { - struct pl061 *chip = dev_get_drvdata(dev); + struct pl061 *pl061 = dev_get_drvdata(dev); int offset; - chip->csave_regs.gpio_data = 0; - chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR); - chip->csave_regs.gpio_is = readb(chip->base + GPIOIS); - chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE); - chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV); - chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); + pl061->csave_regs.gpio_data = 0; + pl061->csave_regs.gpio_dir = readb(pl061->base + GPIODIR); + pl061->csave_regs.gpio_is = readb(pl061->base + GPIOIS); + pl061->csave_regs.gpio_ibe = readb(pl061->base + GPIOIBE); + pl061->csave_regs.gpio_iev = readb(pl061->base + GPIOIEV); + pl061->csave_regs.gpio_ie = readb(pl061->base + GPIOIE); for (offset = 0; offset < PL061_GPIO_NR; offset++) { - if (chip->csave_regs.gpio_dir & (BIT(offset))) - chip->csave_regs.gpio_data |= - pl061_get_value(&chip->gc, offset) << offset; + if (pl061->csave_regs.gpio_dir & (BIT(offset))) + pl061->csave_regs.gpio_data |= + pl061_get_value(&pl061->gc, offset) << offset; } return 0; @@ -400,22 +400,22 @@ static int pl061_suspend(struct device *dev) static int pl061_resume(struct device *dev) { - struct pl061 *chip = dev_get_drvdata(dev); + struct pl061 *pl061 = dev_get_drvdata(dev); int offset; for (offset = 0; offset < PL061_GPIO_NR; offset++) { - if (chip->csave_regs.gpio_dir & (BIT(offset))) - pl061_direction_output(&chip->gc, offset, - chip->csave_regs.gpio_data & + if (pl061->csave_regs.gpio_dir & (BIT(offset))) + pl061_direction_output(&pl061->gc, offset, + pl061->csave_regs.gpio_data & (BIT(offset))); else - pl061_direction_input(&chip->gc, offset); + pl061_direction_input(&pl061->gc, offset); } - writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS); - writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE); - writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV); - writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE); + writeb(pl061->csave_regs.gpio_is, pl061->base + GPIOIS); + writeb(pl061->csave_regs.gpio_ibe, pl061->base + GPIOIBE); + writeb(pl061->csave_regs.gpio_iev, pl061->base + GPIOIEV); + writeb(pl061->csave_regs.gpio_ie, pl061->base + GPIOIE); return 0; } -- cgit v1.2.3 From 562b488443f658151abc9732e1a9762e27c694a0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Nov 2016 10:53:39 +0100 Subject: gpio: pl061: move platform data into driver No boardfile defines any PL061 platform data anymore: the Integrator IM/PD-1 includes the file but is not making use of the struct. Let's delete the include and all references, then move the platform data into the driver for later consolidation into the driver state container. The only resource defined by the IM/PD-1 is the IRQ which is passed through the AMBA PrimeCell bus abstraction struct amba_device. Cc: arm@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: Russell King Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 47f397236417..cbcc631181e0 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -39,6 +38,19 @@ #define PL061_GPIO_NR 8 +struct pl061_platform_data { + /* number of the first GPIO */ + unsigned gpio_base; + + /* number of the first IRQ. + * If the IRQ functionality in not desired this must be set to 0. + */ + unsigned irq_base; + + u8 directions; /* startup directions, 1: out, 0: in */ + u8 values; /* startup values */ +}; + #ifdef CONFIG_PM struct pl061_context_save_regs { u8 gpio_data; -- cgit v1.2.3 From 6da7b0dd517592e12966af7ec55eecf6ebd2c589 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Nov 2016 11:02:19 +0100 Subject: gpio: pl061: delete platform data handling Platform data is a remnant of board files and all boards using the PL061 have been migrated to use device tree or ACPI instead. The custom mechanism to set line by default as inputs/outputs has been superceded by the GPIO-internal hogging mechanism. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 41 +++-------------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index cbcc631181e0..0a6bfd2b06e5 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -38,19 +38,6 @@ #define PL061_GPIO_NR 8 -struct pl061_platform_data { - /* number of the first GPIO */ - unsigned gpio_base; - - /* number of the first IRQ. - * If the IRQ functionality in not desired this must be set to 0. - */ - unsigned irq_base; - - u8 directions; /* startup directions, 1: out, 0: in */ - u8 values; /* startup values */ -}; - #ifdef CONFIG_PM struct pl061_context_save_regs { u8 gpio_data; @@ -306,26 +293,13 @@ static struct irq_chip pl061_irqchip = { static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; - struct pl061_platform_data *pdata = dev_get_platdata(dev); struct pl061 *pl061; - int ret, irq, i, irq_base; + int ret, irq; pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL); if (pl061 == NULL) return -ENOMEM; - if (pdata) { - pl061->gc.base = pdata->gpio_base; - irq_base = pdata->irq_base; - if (irq_base <= 0) { - dev_err(&adev->dev, "invalid IRQ base in pdata\n"); - return -ENODEV; - } - } else { - pl061->gc.base = -1; - irq_base = 0; - } - pl061->base = devm_ioremap_resource(dev, &adev->res); if (IS_ERR(pl061->base)) return PTR_ERR(pl061->base); @@ -336,6 +310,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) pl061->gc.free = gpiochip_generic_free; } + pl061->gc.base = -1; pl061->gc.get_direction = pl061_get_direction; pl061->gc.direction_input = pl061_direction_input; pl061->gc.direction_output = pl061_direction_output; @@ -362,7 +337,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) pl061->parent_irq = irq; ret = gpiochip_irqchip_add(&pl061->gc, &pl061_irqchip, - irq_base, handle_bad_irq, + 0, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_info(&adev->dev, "could not add irqchip\n"); @@ -371,16 +346,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) gpiochip_set_chained_irqchip(&pl061->gc, &pl061_irqchip, irq, pl061_irq_handler); - for (i = 0; i < PL061_GPIO_NR; i++) { - if (pdata) { - if (pdata->directions & (BIT(i))) - pl061_direction_output(&pl061->gc, i, - pdata->values & (BIT(i))); - else - pl061_direction_input(&pl061->gc, i); - } - } - amba_set_drvdata(adev, pl061); dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", &adev->res.start); -- cgit v1.2.3 From a3ee78ec6a5d9a86267a09de9ff27d4e0a21acca Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 25 Nov 2016 13:48:29 +0000 Subject: gpio: arizona: Remove pointless set of platform drvdata We use the gpio chip private data in all the callbacks so remove this redundant line of code. Signed-off-by: Charles Keepax Signed-off-by: Linus Walleij --- drivers/gpio/gpio-arizona.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 482462889c8f..ed41537ec831 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -140,8 +140,6 @@ static int arizona_gpio_probe(struct platform_device *pdev) goto err; } - platform_set_drvdata(pdev, arizona_gpio); - return ret; err: -- cgit v1.2.3 From 975acebbbcb78ce7e97ed7abf960e0b93fa3aec4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 25 Nov 2016 13:48:30 +0000 Subject: gpio: arizona: Tidy up probe error path There is some unnecessary complexity in the error path which now things are converted to devm is actually very simple. This patch simplifies things. Signed-off-by: Charles Keepax Signed-off-by: Linus Walleij --- drivers/gpio/gpio-arizona.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index ed41537ec831..1f91557717a6 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -137,13 +137,10 @@ static int arizona_gpio_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); - goto err; + return ret; } - return ret; - -err: - return ret; + return 0; } static struct platform_driver arizona_gpio_driver = { -- cgit v1.2.3 From f4e81c529767b9a33d1b27695c54dc84a14af30d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 30 Nov 2016 13:05:21 +0100 Subject: gpio: chardev: Return error for seek operations The GPIO chardev is used for management tasks (allocating line and event handles) and does neither support read() nor write() operations. Hence it does not make much sense to allow seek operations. Currently the chardev uses noop_llseek() for its seek implementation. This function does not move the pointer and simply returns the current position (always 0 for the GPIO chardev). noop_llseek() is primarily meant for devices that can not support seek, but where there might be a user that depends on the seek() operation succeeding. For newly added devices that can not support seek operations it is recommended to use no_llseek(), which will return an error. For more information see commit 6038f373a3dc ("llseek: automatically add .llseek fop"). Unfortunately this was overlooked when the GPIO chardev ABI was introduced. But it is highly unlikely that since then userspace applications have appeared that rely on being able to perform non-failing seek operations on a GPIO chardev file descriptor. So it should be safe to change from noop_llseel() to no_seek(). Also use nonseekable_open() in the chardev open() callback to clear the FMODE_SEEK, FMODE_PREAD and FMODE_PWRITE flags from the file. Neither of these should be set on a file that does not support seek operations. Cc: stable@vger.kernel.org Fixes: 3c702e9987e2 ("gpio: add a userspace chardev ABI for GPIOs") Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e97e88e48191..0e29cb745648 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -913,7 +913,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) return -ENODEV; get_device(&gdev->dev); filp->private_data = gdev; - return 0; + + return nonseekable_open(inode, filp); } /** @@ -938,7 +939,7 @@ static const struct file_operations gpio_fileops = { .release = gpio_chrdev_release, .open = gpio_chrdev_open, .owner = THIS_MODULE, - .llseek = noop_llseek, + .llseek = no_llseek, .unlocked_ioctl = gpio_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = gpio_ioctl_compat, -- cgit v1.2.3 From e7a718f9b1c106dc7705d96cf0fe2e2f69089cf9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Dec 2016 17:45:51 +0200 Subject: gpio: merrifield: Add support for hardware debouncer By default all pins are configured to use a glitch filter. Writing 1 to the certain bit of the specific register might be useful in case someone needs to bypass the glitch filter completely for a given GPIO pin. This patch adds support for that in the Intel Merrifield GPIO driver. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 82cdcdc779bb..d7cbbc0fc47b 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -161,6 +161,27 @@ static int mrfld_gpio_direction_output(struct gpio_chip *chip, return 0; } +static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned int debounce) +{ + struct mrfld_gpio *priv = gpiochip_get_data(chip); + void __iomem *gfbr = gpio_reg(chip, offset, GFBR); + unsigned long flags; + u32 value; + + raw_spin_lock_irqsave(&priv->lock, flags); + + if (debounce) + value = readl(gfbr) & ~BIT(offset % 32); + else + value = readl(gfbr) | BIT(offset % 32); + writel(value, gfbr); + + raw_spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + static void mrfld_irq_ack(struct irq_data *d) { struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); @@ -384,6 +405,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id priv->chip.direction_output = mrfld_gpio_direction_output; priv->chip.get = mrfld_gpio_get; priv->chip.set = mrfld_gpio_set; + priv->chip.set_debounce = mrfld_gpio_set_debounce; priv->chip.base = gpio_base; priv->chip.ngpio = MRFLD_NGPIO; priv->chip.can_sleep = false; -- cgit v1.2.3 From 46a5c112a401163f5112911166ea78eb4bacdbc2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Dec 2016 18:09:33 +0200 Subject: gpio: merrifield: Implement gpio_get_direction callback Implement gpio_get_direction() callback for Intel Merrifield GPIO. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index d7cbbc0fc47b..69e0f4ace465 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -161,6 +162,13 @@ static int mrfld_gpio_direction_output(struct gpio_chip *chip, return 0; } +static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + + return (readl(gpdr) & BIT(offset % 32)) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, unsigned int debounce) { @@ -405,6 +413,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id priv->chip.direction_output = mrfld_gpio_direction_output; priv->chip.get = mrfld_gpio_get; priv->chip.set = mrfld_gpio_set; + priv->chip.get_direction = mrfld_gpio_get_direction; priv->chip.set_debounce = mrfld_gpio_set_debounce; priv->chip.base = gpio_base; priv->chip.ngpio = MRFLD_NGPIO; -- cgit v1.2.3