From 3c01b9a896c9c592d9edc7439d5e5cf6c411d014 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Mon, 1 Dec 2014 17:39:34 +0530 Subject: gpio: moxart: convert to use basic mmio gpio library This patch converts MOXART GPIO driver to use basic_mmio_gpio generic library. Signed-off-by: Kamlakant Patel Acked-by: Alexandre Courbot Tested-by: Jonas Jensen Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-moxart.c | 101 ++++++++++++++------------------------------- 2 files changed, 32 insertions(+), 70 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 633ec216e185..e367296208a7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -200,6 +200,7 @@ config GPIO_F7188X config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART + select GPIO_GENERIC help Select this option to enable GPIO driver for MOXA ART SoC devices. diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index 31e2551ed903..c3ab46e595da 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -23,21 +23,12 @@ #include #include #include +#include #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_IN 0x04 #define GPIO_PIN_DIRECTION 0x08 -struct moxart_gpio_chip { - struct gpio_chip gpio; - void __iomem *base; -}; - -static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) -{ - return container_of(chip, struct moxart_gpio_chip, gpio); -} - static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); @@ -48,90 +39,60 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) pinctrl_free_gpio(offset); } -static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_DATA_OUT; - u32 reg = readl(ioaddr); - - if (value) - reg = reg | BIT(offset); - else - reg = reg & ~BIT(offset); - - writel(reg, ioaddr); -} - static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - u32 ret = readl(gc->base + GPIO_PIN_DIRECTION); + struct bgpio_chip *bgc = to_bgpio_chip(chip); + u32 ret = bgc->read_reg(bgc->reg_dir); if (ret & BIT(offset)) - return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset)); + return !!(bgc->read_reg(bgc->reg_set) & BIT(offset)); else - return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); -} - -static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) & ~BIT(offset), ioaddr); - return 0; -} - -static int moxart_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - moxart_gpio_set(chip, offset, value); - writel(readl(ioaddr) | BIT(offset), ioaddr); - return 0; + return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset)); } -static struct gpio_chip moxart_template_chip = { - .label = "moxart-gpio", - .request = moxart_gpio_request, - .free = moxart_gpio_free, - .direction_input = moxart_gpio_direction_input, - .direction_output = moxart_gpio_direction_output, - .set = moxart_gpio_set, - .get = moxart_gpio_get, - .ngpio = 32, - .owner = THIS_MODULE, -}; - static int moxart_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - struct moxart_gpio_chip *mgc; + struct bgpio_chip *bgc; + void __iomem *base; int ret; - mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); - if (!mgc) + bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; - mgc->gpio = moxart_template_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mgc->base = devm_ioremap_resource(dev, res); - if (IS_ERR(mgc->base)) - return PTR_ERR(mgc->base); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); - mgc->gpio.dev = dev; + ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN, + base + GPIO_DATA_OUT, NULL, + base + GPIO_PIN_DIRECTION, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + return ret; + } - ret = gpiochip_add(&mgc->gpio); + bgc->gc.label = "moxart-gpio"; + bgc->gc.request = moxart_gpio_request; + bgc->gc.free = moxart_gpio_free; + bgc->gc.get = moxart_gpio_get; + bgc->data = bgc->read_reg(bgc->reg_set); + bgc->gc.base = 0; + bgc->gc.ngpio = 32; + bgc->gc.dev = dev; + bgc->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&bgc->gc); if (ret) { dev_err(dev, "%s: gpiochip_add failed\n", dev->of_node->full_name); return ret; } - return 0; + return ret; } static const struct of_device_id moxart_gpio_match[] = { -- cgit v1.2.3-59-g8ed1b From 093e9435483c8ad630a1432bfdcc10efe1c08a64 Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Thu, 4 Dec 2014 20:12:08 +0800 Subject: gpio: sx150x: move to irqdomain framework for sx150x driver The sx150x gpio driver used a loop to set liner irq map for gpio pins. Now we use the irq domain to rebuild this irq mappig and make sure the codes are still compatible to old users. this patch also adds IRQF_ONESHOT flag to fix the IRQ flooding issues. Signed-off-by: Wei Chen Signed-off-by: Barry Song [Make Kconfig select GPIOLIB_IRQCHIP] Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-sx150x.c | 72 ++++++++++++---------------------------------- 2 files changed, 19 insertions(+), 54 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e367296208a7..d5ee1710d1ff 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -614,6 +614,7 @@ config GPIO_RC5T583 config GPIO_SX150X bool "Semtech SX150x I2C GPIO expander" depends on I2C=y + select GPIOLIB_IRQCHIP default n help Say yes here to provide support for Semtech SX150-series I2C diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index bce6c6108f20..0bc61c2bd079 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -293,27 +293,11 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc, return status; } -static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct sx150x_chip *chip; - - chip = container_of(gc, struct sx150x_chip, gpio_chip); - - if (offset >= chip->dev_cfg->ngpios) - return -EINVAL; - - if (chip->irq_base < 0) - return -EINVAL; - - return chip->irq_base + offset; -} - static void sx150x_irq_mask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked |= (1 << n); chip->irq_update = n; } @@ -321,9 +305,8 @@ static void sx150x_irq_mask(struct irq_data *d) static void sx150x_irq_unmask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked &= ~(1 << n); chip->irq_update = n; } @@ -336,7 +319,7 @@ static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) return -EINVAL; - n = d->irq - chip->irq_base; + n = d->hwirq; if (flow_type & IRQ_TYPE_EDGE_RISING) val |= 0x1; @@ -371,7 +354,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) val); for (n = 0; n < 8; ++n) { if (val & (1 << n)) { - sub_irq = chip->irq_base + (i * 8) + n; + sub_irq = irq_find_mapping( + chip->gpio_chip.irqdomain, + (i * 8) + n); handle_nested_irq(sub_irq); ++nhandled; } @@ -428,12 +413,12 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->client = client; chip->dev_cfg = &sx150x_devices[driver_data]; + chip->gpio_chip.dev = &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.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; @@ -529,31 +514,24 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, int irq_base) { int err; - unsigned n; - unsigned irq; chip->irq_summary = irq_summary; chip->irq_base = irq_base; - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = irq_base + n; - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + /* 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_SHARED | IRQF_TRIGGER_FALLING, - chip->irq_chip.name, - chip); + 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; @@ -562,17 +540,6 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, return err; } -static void sx150x_remove_irq_chip(struct sx150x_chip *chip) -{ - unsigned n; - unsigned irq; - - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = chip->irq_base + n; - irq_set_chip_and_handler(irq, NULL, NULL); - } -} - static int sx150x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -626,9 +593,6 @@ static int sx150x_remove(struct i2c_client *client) chip = i2c_get_clientdata(client); gpiochip_remove(&chip->gpio_chip); - if (chip->irq_summary >= 0) - sx150x_remove_irq_chip(chip); - return 0; } -- cgit v1.2.3-59-g8ed1b From ae9ca493ee2adaebc2bccd60fb6ccf93a214262c Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Thu, 4 Dec 2014 20:12:09 +0800 Subject: gpio: sx150x: add support for sx1506 gpio expander device semtech has two series of sx150x gpio expanders: sx150x-456 and sx150x-789. The current gpio-150x driver in linux only support sx1508 and sx1509. We added sx1506 support code into this driver. Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sx150x.c | 157 ++++++++++++++++++++++++++++++++------------- 1 file changed, 112 insertions(+), 45 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index 0bc61c2bd079..b32fb38ac5c9 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -26,20 +26,43 @@ #define NO_UPDATE_PENDING -1 +/* The chip models of sx150x */ +#define SX150X_456 0 +#define SX150X_789 1 + +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_drain; - u8 reg_polarity; u8 reg_dir; u8 reg_data; u8 reg_irq_mask; u8 reg_irq_src; u8 reg_sense; - u8 reg_clock; - u8 reg_misc; - u8 reg_reset; u8 ngpios; + union { + struct sx150x_456_pri x456; + struct sx150x_789_pri x789; + } pri; }; struct sx150x_chip { @@ -59,40 +82,67 @@ struct sx150x_chip { static const struct sx150x_device_data sx150x_devices[] = { [0] = { /* sx1508q */ - .reg_pullup = 0x03, - .reg_pulldn = 0x04, - .reg_drain = 0x05, - .reg_polarity = 0x06, - .reg_dir = 0x07, - .reg_data = 0x08, - .reg_irq_mask = 0x09, - .reg_irq_src = 0x0c, - .reg_sense = 0x0b, - .reg_clock = 0x0f, - .reg_misc = 0x10, - .reg_reset = 0x7d, - .ngpios = 8 + .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 */ - .reg_pullup = 0x07, - .reg_pulldn = 0x09, - .reg_drain = 0x0b, - .reg_polarity = 0x0d, - .reg_dir = 0x0f, - .reg_data = 0x11, - .reg_irq_mask = 0x13, - .reg_irq_src = 0x19, - .reg_sense = 0x17, - .reg_clock = 0x1e, - .reg_misc = 0x1f, - .reg_reset = 0x7d, - .ngpios = 16 + .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 }, }; static const struct i2c_device_id sx150x_id[] = { {"sx1508q", 0}, {"sx1509q", 1}, + {"sx1506q", 2}, {} }; MODULE_DEVICE_TABLE(i2c, sx150x_id); @@ -191,7 +241,7 @@ static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset) static void sx150x_set_oscio(struct sx150x_chip *chip, int val) { sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_clock, + chip->dev_cfg->pri.x789.reg_clock, (val ? 0x1f : 0x10)); } @@ -455,13 +505,13 @@ static int sx150x_reset(struct sx150x_chip *chip) int err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x12); if (err < 0) return err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x34); return err; } @@ -477,9 +527,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip, return err; } - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_misc, - 0x01); + if (chip->dev_cfg->model == SX150X_789) + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x789.reg_misc, + 0x01); + else + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x456.reg_advance, + 0x04); if (err < 0) return err; @@ -493,15 +548,27 @@ static int sx150x_init_hw(struct sx150x_chip *chip, if (err < 0) return err; - err = sx150x_init_io(chip, chip->dev_cfg->reg_drain, - pdata->io_open_drain_ena); - if (err < 0) - return err; + if (chip->dev_cfg->model == SX150X_789) { + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_drain, + pdata->io_open_drain_ena); + if (err < 0) + return err; + + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_polarity, + pdata->io_polarity); + if (err < 0) + return err; + } else { + /* 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; + } - err = sx150x_init_io(chip, chip->dev_cfg->reg_polarity, - pdata->io_polarity); - if (err < 0) - return err; if (pdata->oscio_is_gpo) sx150x_set_oscio(chip, 0); -- cgit v1.2.3-59-g8ed1b From 920214902502ceb0445a25b530dfe4c465cf8575 Mon Sep 17 00:00:00 2001 From: Chang Rebecca Swee Fun Date: Mon, 8 Dec 2014 17:38:10 +0800 Subject: gpio: sch: Add support for Intel Quark X1000 SoC Intel Quark X1000 provides a total of 16 GPIOs. The GPIOs are split between the legacy I/O bridge and the GPIO controller. GPIO-SCH is the GPIO pins on legacy bridge for Intel Quark SoC. Intel Quark X1000 has 2 GPIOs powered by the core power well and 6 from the suspend power well. This piece of work is derived from Dan O'Donovan's initial work for Quark X1000 enabling. Signed-off-by: Chang Rebecca Swee Fun Reviewed-by: Mika Westerberg Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 11 +++++++++-- drivers/gpio/gpio-sch.c | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d5ee1710d1ff..cb235f3691bc 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -395,25 +395,32 @@ config GPIO_VR41XX Say yes here to support the NEC VR4100 series General-purpose I/O Uint config GPIO_SCH - tristate "Intel SCH/TunnelCreek/Centerton GPIO" + tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" depends on PCI && X86 select MFD_CORE select LPC_SCH help Say yes here to support GPIO interface on Intel Poulsbo SCH, - Intel Tunnel Creek processor or Intel Centerton processor. + Intel Tunnel Creek processor, Intel Centerton processor or + Intel Quark X1000 SoC. + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are powered by the core power rail and are turned off during sleep modes (S3 and higher). The remaining four GPIOs are powered by the Intel SCH suspend power supply. These GPIOs remain active during S3. The suspend powered GPIOs can be used to wake the system from the Suspend-to-RAM state. + The Intel Tunnel Creek processor has 5 GPIOs powered by the core power rail and 9 from suspend power supply. + The Intel Centerton processor has a total of 30 GPIO pins. Twenty-one are powered by the core power rail and 9 from the suspend power supply. + The Intel Quark X1000 SoC has 2 GPIOs powered by the core + power well and 6 from the suspend power well. + config GPIO_ICH tristate "Intel ICH GPIO" depends on PCI && X86 diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 0a0cf1307d2f..0271022a66f6 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -230,6 +230,12 @@ static int sch_gpio_probe(struct platform_device *pdev) sch->chip.ngpio = 30; break; + case PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB: + sch->core_base = 0; + sch->resume_base = 2; + sch->chip.ngpio = 8; + break; + default: return -ENODEV; } -- cgit v1.2.3-59-g8ed1b From bc2f3dc3e2c784efc30acf6f8adde560beedbf57 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:08 +0100 Subject: gpio/xilinx: Remove offset property Instead of calculating the register offset per call, pre-calculate it on probe time. Acked-by: Alexandre Courbot Acked-by: Michal Simek Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index ba18b06c9a21..e668ec4460b5 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -43,14 +43,12 @@ * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks * gpio_state: GPIO state shadow register * gpio_dir: GPIO direction shadow register - * offset: GPIO channel offset * gpio_lock: Lock used for synchronization */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; u32 gpio_state; u32 gpio_dir; - u32 offset; spinlock_t gpio_lock; }; @@ -65,12 +63,8 @@ struct xgpio_instance { static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct xgpio_instance *chip = - container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs + chip->offset; - - return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio)); + return !!(xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET) & BIT(gpio)); } /** @@ -88,7 +82,6 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; spin_lock_irqsave(&chip->gpio_lock, flags); @@ -98,8 +91,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) else chip->gpio_state &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); spin_unlock_irqrestore(&chip->gpio_lock, flags); } @@ -119,13 +111,12 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; spin_lock_irqsave(&chip->gpio_lock, flags); /* Set the GPIO bit in shadow register and set direction as input */ chip->gpio_dir |= BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); spin_unlock_irqrestore(&chip->gpio_lock, flags); @@ -148,7 +139,6 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; spin_lock_irqsave(&chip->gpio_lock, flags); @@ -157,12 +147,11 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) chip->gpio_state |= BIT(gpio); else chip->gpio_state &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); /* Clear the GPIO bit in shadow register and set direction as output */ chip->gpio_dir &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); spin_unlock_irqrestore(&chip->gpio_lock, flags); @@ -178,10 +167,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); - xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET, - chip->gpio_dir); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); } /** @@ -247,9 +234,6 @@ static int xgpio_of_probe(struct device_node *np) if (!chip) return -ENOMEM; - /* Add dual channel offset */ - chip->offset = XGPIO_CHANNEL_OFFSET; - /* Update GPIO state shadow register with default value */ of_property_read_u32(np, "xlnx,dout-default-2", &chip->gpio_state); @@ -285,6 +269,10 @@ static int xgpio_of_probe(struct device_node *np) np->full_name, status); return status; } + + /* Add dual channel offset */ + chip->mmchip.regs += XGPIO_CHANNEL_OFFSET; + pr_info("XGpio: %s: dual channel registered, base is %d\n", np->full_name, chip->mmchip.gc.base); } -- cgit v1.2.3-59-g8ed1b From 749564ffd52d91ddf9917315e6fba2a3dcf3137e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:09 +0100 Subject: gpio/xilinx: Convert the driver to platform device interface This way we do not need to transverse the device tree manually and we support hot plugged devices. Also Implement remove callback so the driver can be unloaded Acked-by: Michal Simek Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 83 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 17 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index e668ec4460b5..c7ed92bb561b 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -44,12 +44,18 @@ * gpio_state: GPIO state shadow register * gpio_dir: GPIO direction shadow register * gpio_lock: Lock used for synchronization + * inited: True if the port has been inited */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; u32 gpio_state; u32 gpio_dir; spinlock_t gpio_lock; + bool inited; +}; + +struct xgpio { + struct xgpio_instance port[2]; }; /** @@ -171,25 +177,57 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); } +/** + * xgpio_remove - Remove method for the GPIO device. + * @pdev: pointer to the platform device + * + * This function remove gpiochips and frees all the allocated resources. + */ +static int xgpio_remove(struct platform_device *pdev) +{ + struct xgpio *xgpio = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < 2; i++) { + if (!xgpio->port[i].inited) + continue; + gpiochip_remove(&xgpio->port[i].mmchip.gc); + + if (i == 1) + xgpio->port[i].mmchip.regs -= XGPIO_CHANNEL_OFFSET; + + iounmap(xgpio->port[i].mmchip.regs); + kfree(xgpio->port[i].mmchip.gc.label); + } + + return 0; +} + /** * xgpio_of_probe - Probe method for the GPIO device. - * @np: pointer to device tree node + * @pdev: pointer to the platform device * * This function probes the GPIO device in the device tree. It initializes the * driver data structure. It returns 0, if the driver is bound to the GPIO * device, or a negative value if there is an error. */ -static int xgpio_of_probe(struct device_node *np) +static int xgpio_probe(struct platform_device *pdev) { + struct xgpio *xgpio; struct xgpio_instance *chip; int status = 0; + struct device_node *np = pdev->dev.of_node; const u32 *tree_info; u32 ngpio; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) + xgpio = devm_kzalloc(&pdev->dev, sizeof(*xgpio), GFP_KERNEL); + if (!xgpio) return -ENOMEM; + platform_set_drvdata(pdev, xgpio); + + chip = &xgpio->port[0]; + /* Update GPIO state shadow register with default value */ of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state); @@ -209,6 +247,7 @@ static int xgpio_of_probe(struct device_node *np) spin_lock_init(&chip->gpio_lock); + chip->mmchip.gc.dev = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.get = xgpio_get; @@ -219,20 +258,18 @@ static int xgpio_of_probe(struct device_node *np) /* Call the OF gpio helper to setup and register the GPIO device */ status = of_mm_gpiochip_add(np, &chip->mmchip); if (status) { - kfree(chip); pr_err("%s: error in probe function with status %d\n", np->full_name, status); return status; } + chip->inited = true; pr_info("XGpio: %s: registered, base is %d\n", np->full_name, chip->mmchip.gc.base); tree_info = of_get_property(np, "xlnx,is-dual", NULL); if (tree_info && be32_to_cpup(tree_info)) { - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; + chip = &xgpio->port[1]; /* Update GPIO state shadow register with default value */ of_property_read_u32(np, "xlnx,dout-default-2", @@ -254,6 +291,7 @@ static int xgpio_of_probe(struct device_node *np) spin_lock_init(&chip->gpio_lock); + chip->mmchip.gc.dev = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.get = xgpio_get; @@ -264,7 +302,7 @@ static int xgpio_of_probe(struct device_node *np) /* Call the OF gpio helper to setup and register the GPIO dev */ status = of_mm_gpiochip_add(np, &chip->mmchip); if (status) { - kfree(chip); + xgpio_remove(pdev); pr_err("%s: error in probe function with status %d\n", np->full_name, status); return status; @@ -272,6 +310,7 @@ static int xgpio_of_probe(struct device_node *np) /* Add dual channel offset */ chip->mmchip.regs += XGPIO_CHANNEL_OFFSET; + chip->inited = true; pr_info("XGpio: %s: dual channel registered, base is %d\n", np->full_name, chip->mmchip.gc.base); @@ -285,19 +324,29 @@ static const struct of_device_id xgpio_of_match[] = { { /* end of list */ }, }; -static int __init xgpio_init(void) -{ - struct device_node *np; +MODULE_DEVICE_TABLE(of, xgpio_of_match); - for_each_matching_node(np, xgpio_of_match) - xgpio_of_probe(np); +static struct platform_driver xgpio_plat_driver = { + .probe = xgpio_probe, + .remove = xgpio_remove, + .driver = { + .name = "gpio-xilinx", + .of_match_table = xgpio_of_match, + }, +}; - return 0; +static int __init xgpio_init(void) +{ + return platform_driver_register(&xgpio_plat_driver); } -/* Make sure we get initialized before anyone else tries to use us */ subsys_initcall(xgpio_init); -/* No exit call at the moment as we cannot unregister of GPIO chips */ + +static void __exit xgpio_exit(void) +{ + platform_driver_unregister(&xgpio_plat_driver); +} +module_exit(xgpio_exit); MODULE_AUTHOR("Xilinx, Inc."); MODULE_DESCRIPTION("Xilinx GPIO driver"); -- cgit v1.2.3-59-g8ed1b From c54c58bad6e64649dfe51c2e8d9e5a1524d673e8 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:10 +0100 Subject: gpio/xilinx: Add support for X86 Arch Core can be accessed via PCIe on X86 platform. This patch also allows the driver to be used as module. Acked-by: Michal Simek Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 4 ++-- drivers/gpio/gpio-xilinx.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cb235f3691bc..1eff81c93b75 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -367,8 +367,8 @@ config GPIO_XGENE here to enable the GFC GPIO functionality. config GPIO_XILINX - bool "Xilinx GPIO support" - depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ + tristate "Xilinx GPIO support" + depends on OF_GPIO && (PPC_OF || MICROBLAZE || ARCH_ZYNQ || ARCH_X86) help Say yes here to support the Xilinx FPGA GPIO device diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index c7ed92bb561b..554060a9fb48 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -30,7 +30,7 @@ #define XGPIO_CHANNEL_OFFSET 0x8 /* Read/Write access to the GPIO registers */ -#ifdef CONFIG_ARCH_ZYNQ +#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) # define xgpio_readreg(offset) readl(offset) # define xgpio_writereg(offset, val) writel(val, offset) #else -- cgit v1.2.3-59-g8ed1b From 4ae798fae200f1d26c820c6e508a6bcd3c5aa8f2 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:11 +0100 Subject: gpio/xilinx: Fix kernel-doc Some documentation were not following the kernel-doc format. Backporting patch from Xilinx git repository. Suggested-by: Michal Simek Acked-by: Michal Simek Acked-by: Alexandre Courbot Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 554060a9fb48..9cf445732675 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -40,11 +40,11 @@ /** * struct xgpio_instance - Stores information about GPIO device - * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks - * gpio_state: GPIO state shadow register - * gpio_dir: GPIO direction shadow register - * gpio_lock: Lock used for synchronization - * inited: True if the port has been inited + * @mmchip: OF GPIO chip for memory mapped banks + * @gpio_state: GPIO state shadow register + * @gpio_dir: GPIO direction shadow register + * @gpio_lock: Lock used for synchronization + * @inited: True if the port has been inited */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; @@ -63,8 +63,11 @@ struct xgpio { * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function reads the specified signal of the GPIO device. It returns 0 if - * the signal clear, 1 if signal is set or negative value on error. + * This function reads the specified signal of the GPIO device. + * + * Return: + * 0 if direction of GPIO signals is set as input otherwise it + * returns negative error value. */ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { @@ -107,9 +110,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function sets the direction of specified GPIO signal as input. - * It returns 0 if direction of GPIO signals is set as input otherwise it - * returns negative error value. + * Return: + * 0 - if direction of GPIO signals is set as input + * otherwise it returns negative error value. */ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { @@ -135,8 +138,10 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * - * This function sets the direction of specified GPIO signal as output. If all - * GPIO signals of GPIO chip is configured as input then it returns + * This function sets the direction of specified GPIO signal as output. + * + * Return: + * If all GPIO signals of GPIO chip is configured as input then it returns * error otherwise it returns 0. */ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) @@ -166,7 +171,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) /** * xgpio_save_regs - Set initial values of GPIO pins - * @mm_gc: pointer to memory mapped GPIO chip structure + * @mm_gc: Pointer to memory mapped GPIO chip structure */ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) { @@ -207,9 +212,9 @@ static int xgpio_remove(struct platform_device *pdev) * xgpio_of_probe - Probe method for the GPIO device. * @pdev: pointer to the platform device * - * This function probes the GPIO device in the device tree. It initializes the - * driver data structure. It returns 0, if the driver is bound to the GPIO - * device, or a negative value if there is an error. + * Return: + * It returns 0, if the driver is bound to the GPIO device, or + * a negative value if there is an error. */ static int xgpio_probe(struct platform_device *pdev) { -- cgit v1.2.3-59-g8ed1b From 1d6902d3a68e83061c979a57d7411e8ae172df67 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:12 +0100 Subject: gpio/xilinx: Create a single gpio chip on dual cores Currently, we had two gpio chips on cores configured as dual. This lead to mapping the same memory region twice and duplicating the init and remove code. This patch creates a single gpiochip for single and dual cores. Suggested-by: Alexandre Courbot Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 217 +++++++++++++++++++++++---------------------- 1 file changed, 109 insertions(+), 108 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 9cf445732675..e89fb4201280 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -48,15 +48,35 @@ */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; - u32 gpio_state; - u32 gpio_dir; - spinlock_t gpio_lock; - bool inited; + unsigned int gpio_width[2]; + u32 gpio_state[2]; + u32 gpio_dir[2]; + spinlock_t gpio_lock[2]; }; -struct xgpio { - struct xgpio_instance port[2]; -}; +static inline int xgpio_index(struct xgpio_instance *chip, int gpio) +{ + if (gpio >= chip->gpio_width[0]) + return 1; + + return 0; +} + +static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio) +{ + if (xgpio_index(chip, gpio)) + return XGPIO_CHANNEL_OFFSET; + + return 0; +} + +static inline int xgpio_offset(struct xgpio_instance *chip, int gpio) +{ + if (xgpio_index(chip, gpio)) + return gpio - chip->gpio_width[0]; + + return gpio; +} /** * xgpio_get - Read the specified signal of the GPIO device. @@ -72,8 +92,14 @@ struct xgpio { static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + u32 val; - return !!(xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET) & BIT(gpio)); + val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio)); + + return !!(val & BIT(xgpio_offset(chip, gpio))); } /** @@ -91,18 +117,21 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write to GPIO signal and set its direction to output */ if (val) - chip->gpio_state |= BIT(gpio); + chip->gpio_state[index] |= BIT(offset); else - chip->gpio_state &= ~BIT(gpio); + chip->gpio_state[index] &= ~BIT(offset); - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); } /** @@ -120,14 +149,17 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Set the GPIO bit in shadow register and set direction as input */ - chip->gpio_dir |= BIT(gpio); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + chip->gpio_dir[index] |= BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; } @@ -150,21 +182,25 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write state of GPIO signal */ if (val) - chip->gpio_state |= BIT(gpio); + chip->gpio_state[index] |= BIT(offset); else - chip->gpio_state &= ~BIT(gpio); - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); + chip->gpio_state[index] &= ~BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); /* Clear the GPIO bit in shadow register and set direction as output */ - chip->gpio_dir &= ~BIT(gpio); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + chip->gpio_dir[index] &= ~BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; } @@ -178,8 +214,16 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); + + if (!chip->gpio_width[1]) + return; + + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_TRI_OFFSET, + chip->gpio_state[1]); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_TRI_OFFSET, + chip->gpio_dir[1]); } /** @@ -190,20 +234,12 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) */ static int xgpio_remove(struct platform_device *pdev) { - struct xgpio *xgpio = platform_get_drvdata(pdev); - int i; + struct xgpio_instance *chip = platform_get_drvdata(pdev); - for (i = 0; i < 2; i++) { - if (!xgpio->port[i].inited) - continue; - gpiochip_remove(&xgpio->port[i].mmchip.gc); + gpiochip_remove(&chip->mmchip.gc); - if (i == 1) - xgpio->port[i].mmchip.regs -= XGPIO_CHANNEL_OFFSET; - - iounmap(xgpio->port[i].mmchip.regs); - kfree(xgpio->port[i].mmchip.gc.label); - } + iounmap(chip->mmchip.regs); + kfree(chip->mmchip.gc.label); return 0; } @@ -218,40 +254,58 @@ static int xgpio_remove(struct platform_device *pdev) */ static int xgpio_probe(struct platform_device *pdev) { - struct xgpio *xgpio; struct xgpio_instance *chip; int status = 0; struct device_node *np = pdev->dev.of_node; - const u32 *tree_info; - u32 ngpio; + u32 is_dual; - xgpio = devm_kzalloc(&pdev->dev, sizeof(*xgpio), GFP_KERNEL); - if (!xgpio) + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) return -ENOMEM; - platform_set_drvdata(pdev, xgpio); - - chip = &xgpio->port[0]; + platform_set_drvdata(pdev, chip); /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state); - - /* By default, all pins are inputs */ - chip->gpio_dir = 0xFFFFFFFF; + of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]); /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir); + if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0])) + chip->gpio_dir[0] = 0xFFFFFFFF; /* * Check device node and parent device node for device width * and assume default width of 32 */ - if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio)) - ngpio = 32; - chip->mmchip.gc.ngpio = (u16)ngpio; + if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) + chip->gpio_width[0] = 32; + + spin_lock_init(&chip->gpio_lock[0]); + + if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) + is_dual = 0; - spin_lock_init(&chip->gpio_lock); + if (is_dual) { + /* Update GPIO state shadow register with default value */ + of_property_read_u32(np, "xlnx,dout-default-2", + &chip->gpio_state[1]); + + /* Update GPIO direction shadow register with default value */ + if (of_property_read_u32(np, "xlnx,tri-default-2", + &chip->gpio_dir[1])) + chip->gpio_dir[1] = 0xFFFFFFFF; + /* + * Check device node and parent device node for device width + * and assume default width of 32 + */ + if (of_property_read_u32(np, "xlnx,gpio2-width", + &chip->gpio_width[1])) + chip->gpio_width[1] = 32; + + spin_lock_init(&chip->gpio_lock[1]); + } + + chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; chip->mmchip.gc.dev = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; @@ -267,59 +321,6 @@ static int xgpio_probe(struct platform_device *pdev) np->full_name, status); return status; } - chip->inited = true; - - pr_info("XGpio: %s: registered, base is %d\n", np->full_name, - chip->mmchip.gc.base); - - tree_info = of_get_property(np, "xlnx,is-dual", NULL); - if (tree_info && be32_to_cpup(tree_info)) { - chip = &xgpio->port[1]; - - /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default-2", - &chip->gpio_state); - - /* By default, all pins are inputs */ - chip->gpio_dir = 0xFFFFFFFF; - - /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir); - - /* - * Check device node and parent device node for device width - * and assume default width of 32 - */ - if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio)) - ngpio = 32; - chip->mmchip.gc.ngpio = (u16)ngpio; - - spin_lock_init(&chip->gpio_lock); - - chip->mmchip.gc.dev = &pdev->dev; - chip->mmchip.gc.direction_input = xgpio_dir_in; - chip->mmchip.gc.direction_output = xgpio_dir_out; - chip->mmchip.gc.get = xgpio_get; - chip->mmchip.gc.set = xgpio_set; - - chip->mmchip.save_regs = xgpio_save_regs; - - /* Call the OF gpio helper to setup and register the GPIO dev */ - status = of_mm_gpiochip_add(np, &chip->mmchip); - if (status) { - xgpio_remove(pdev); - pr_err("%s: error in probe function with status %d\n", - np->full_name, status); - return status; - } - - /* Add dual channel offset */ - chip->mmchip.regs += XGPIO_CHANNEL_OFFSET; - chip->inited = true; - - pr_info("XGpio: %s: dual channel registered, base is %d\n", - np->full_name, chip->mmchip.gc.base); - } return 0; } -- cgit v1.2.3-59-g8ed1b From d621e8bae5ac9c67de4de90c5cded12adc8ee1e1 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:13 +0100 Subject: gpio/gpiolib-of: Create of_mm_gpiochip_remove Create counterpart of of_mm_gpiochip_add(). This way the modules that can be removable do not duplicate the cleanup code. Suggested-by: Alexandre Courbot Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 17 +++++++++++++++++ include/linux/of_gpio.h | 1 + 2 files changed, 18 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 604dbe60bdee..3e2c6afeab11 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -204,6 +204,23 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +/** + * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank) + * @mm_gc: pointer to the of_mm_gpio_chip allocated structure + */ +void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) +{ + struct gpio_chip *gc = &mm_gc->gc; + + if (!mm_gc) + return; + + gpiochip_remove(gc); + iounmap(mm_gc->regs); + kfree(gc->label); +} +EXPORT_SYMBOL(of_mm_gpiochip_remove); + #ifdef CONFIG_PINCTRL static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 38fc05036015..69dbe312b11b 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -52,6 +52,7 @@ extern int of_get_named_gpio_flags(struct device_node *np, extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); +extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); extern void of_gpiochip_add(struct gpio_chip *gc); extern void of_gpiochip_remove(struct gpio_chip *gc); -- cgit v1.2.3-59-g8ed1b From c458e45045da96b4d3506ba2acab02af8c98c8c2 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 17 Dec 2014 16:51:14 +0100 Subject: gpio/xilinx: Use of_mm_gpiochip_remove Use the newly created of_mm_gpiochip_remove function for cleaning up of_mm_gpiochip_add Suggested-by: Alexandre Courbot Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index e89fb4201280..61243d177740 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -236,10 +236,7 @@ static int xgpio_remove(struct platform_device *pdev) { struct xgpio_instance *chip = platform_get_drvdata(pdev); - gpiochip_remove(&chip->mmchip.gc); - - iounmap(chip->mmchip.regs); - kfree(chip->mmchip.gc.label); + of_mm_gpiochip_remove(&chip->mmchip); return 0; } -- cgit v1.2.3-59-g8ed1b From 5b6a342ba9594f1636f85e4c58004d87de9570ab Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 12 Dec 2014 12:17:41 +0800 Subject: gpio: vx855: Switch to use managed resources APIs Use devm_* APIs to simplify the code a bit. Signed-off-by: Axel Lin Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vx855.c | 44 ++++++-------------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 9d21d2fcc327..57b470d5b39e 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -52,8 +52,6 @@ struct vx855_gpio { spinlock_t lock; u32 io_gpi; u32 io_gpo; - bool gpi_reserved; - bool gpo_reserved; }; /* resolve a GPIx into the corresponding bit position */ @@ -224,14 +222,13 @@ static int vx855gpio_probe(struct platform_device *pdev) struct resource *res_gpi; struct resource *res_gpo; struct vx855_gpio *vg; - int ret; res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0); res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1); if (!res_gpi || !res_gpo) return -EBUSY; - vg = kzalloc(sizeof(*vg), GFP_KERNEL); + vg = devm_kzalloc(&pdev->dev, sizeof(*vg), GFP_KERNEL); if (!vg) return -ENOMEM; @@ -250,56 +247,27 @@ static int vx855gpio_probe(struct platform_device *pdev) * succeed. Ignore and continue. */ - if (!request_region(res_gpi->start, resource_size(res_gpi), - MODULE_NAME "_gpi")) + if (!devm_request_region(&pdev->dev, res_gpi->start, + resource_size(res_gpi), MODULE_NAME "_gpi")) dev_warn(&pdev->dev, "GPI I/O resource busy, probably claimed by ACPI\n"); - else - vg->gpi_reserved = true; - if (!request_region(res_gpo->start, resource_size(res_gpo), - MODULE_NAME "_gpo")) + if (!devm_request_region(&pdev->dev, res_gpo->start, + resource_size(res_gpo), MODULE_NAME "_gpo")) dev_warn(&pdev->dev, "GPO I/O resource busy, probably claimed by ACPI\n"); - else - vg->gpo_reserved = true; vx855gpio_gpio_setup(vg); - ret = gpiochip_add(&vg->gpio); - if (ret) { - dev_err(&pdev->dev, "failed to register GPIOs\n"); - goto out_release; - } - - return 0; - -out_release: - if (vg->gpi_reserved) - release_region(res_gpi->start, resource_size(res_gpi)); - if (vg->gpo_reserved) - release_region(res_gpi->start, resource_size(res_gpo)); - kfree(vg); - return ret; + return gpiochip_add(&vg->gpio); } static int vx855gpio_remove(struct platform_device *pdev) { struct vx855_gpio *vg = platform_get_drvdata(pdev); - struct resource *res; gpiochip_remove(&vg->gpio); - if (vg->gpi_reserved) { - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, resource_size(res)); - } - if (vg->gpo_reserved) { - res = platform_get_resource(pdev, IORESOURCE_IO, 1); - release_region(res->start, resource_size(res)); - } - - kfree(vg); return 0; } -- cgit v1.2.3-59-g8ed1b From 53e41f554a0cbad139ee5072bbb49b4951f680c2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 15 Dec 2014 10:39:47 +0100 Subject: gpio: tc3589x: get rid of platform data This device is only used from the device tree, and the startup() and remove() callbacks are not used anywhere in the kernel, so retire them and the pdata altogether. Cc: Samuel Ortiz Acked-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tc3589x.c | 15 ++------------- include/linux/mfd/tc3589x.h | 12 ------------ 2 files changed, 2 insertions(+), 25 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index abdcf58935f5..11aed2671065 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -232,16 +232,13 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); - struct tc3589x_gpio_platform_data *pdata; struct device_node *np = pdev->dev.of_node; struct tc3589x_gpio *tc3589x_gpio; int ret; int irq; - pdata = tc3589x->pdata->gpio; - - if (!(pdata || np)) { - dev_err(&pdev->dev, "No platform data or Device Tree found\n"); + if (!np) { + dev_err(&pdev->dev, "No Device Tree node found\n"); return -EINVAL; } @@ -305,9 +302,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) irq, NULL); - if (pdata && pdata->setup) - pdata->setup(tc3589x, tc3589x_gpio->chip.base); - platform_set_drvdata(pdev, tc3589x_gpio); return 0; @@ -316,11 +310,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) static int tc3589x_gpio_remove(struct platform_device *pdev) { struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); - struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; - struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - - if (pdata && pdata->remove) - pdata->remove(tc3589x, tc3589x_gpio->chip.base); gpiochip_remove(&tc3589x_gpio->chip); diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h index e1c12d84c26a..c203c9c56776 100644 --- a/include/linux/mfd/tc3589x.h +++ b/include/linux/mfd/tc3589x.h @@ -162,25 +162,13 @@ struct tc3589x_keypad_platform_data { bool no_autorepeat; }; -/** - * struct tc3589x_gpio_platform_data - TC3589x GPIO platform data - * @setup: callback for board-specific initialization - * @remove: callback for board-specific teardown - */ -struct tc3589x_gpio_platform_data { - void (*setup)(struct tc3589x *tc3589x, unsigned gpio_base); - void (*remove)(struct tc3589x *tc3589x, unsigned gpio_base); -}; - /** * struct tc3589x_platform_data - TC3589x platform data * @block: bitmask of blocks to enable (use TC3589x_BLOCK_*) - * @gpio: GPIO-specific platform data * @keypad: keypad-specific platform data */ struct tc3589x_platform_data { unsigned int block; - struct tc3589x_gpio_platform_data *gpio; const struct tc3589x_keypad_platform_data *keypad; }; -- cgit v1.2.3-59-g8ed1b From d3c2155ce5889731de5d18c53f7fbde2d1b87e00 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 17 Dec 2014 02:53:59 +0300 Subject: gpio: grgpio: off by one in grgpio_to_irq() "gc->ngpio" is a number between 1 and GRGPIO_MAX_NGPIO. If "offset" is GRGPIO_MAX_NGPIO then we're going one step beyond the end of the priv->lirqs[] array. Signed-off-by: Dan Carpenter Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-grgpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 09daaf2aeb56..d5bc70fce4df 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -121,7 +121,7 @@ static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct grgpio_priv *priv = grgpio_gc_to_priv(gc); - if (offset > gc->ngpio) + if (offset >= gc->ngpio) return -ENXIO; if (priv->lirqs[offset].index < 0) -- cgit v1.2.3-59-g8ed1b From aab0b129cc73f7f01fad3a05fe61f03525087783 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 16 Dec 2014 14:22:27 +0800 Subject: gpio: sx150x: Fix comparing wrong value with chip->irq_masked Fix a copy-paste bug. Signed-off-by: Axel Lin Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sx150x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index b32fb38ac5c9..20573ac714fc 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -436,7 +436,7 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) /* Avoid updates if nothing changed */ if (chip->dev_sense == chip->irq_sense && - chip->dev_sense == chip->irq_masked) + chip->dev_masked == chip->irq_masked) goto out; chip->dev_sense = chip->irq_sense; -- cgit v1.2.3-59-g8ed1b From a7ce835376fd300ae4ec08f9aa3dfe6f8568111b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:28 +0100 Subject: gpio: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vf610.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 4ee4cee832ec..971c73964ef1 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -278,7 +278,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) static struct platform_driver vf610_gpio_driver = { .driver = { .name = "gpio-vf610", - .owner = THIS_MODULE, .of_match_table = vf610_gpio_dt_ids, }, .probe = vf610_gpio_probe, -- cgit v1.2.3-59-g8ed1b From 08b89fa20bf292b6b7cd4c7fbaa6c147d4cc9e07 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Dec 2014 14:00:39 +0800 Subject: gpio: tz1090: Use resource_size to fix off-by-one Use resource_size to fix off-by-one resource size calculation Signed-off-by: Axel Lin Acked-by: James Hogan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tz1090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index e3024bbba447..445660adc898 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -573,7 +573,7 @@ static int tz1090_gpio_probe(struct platform_device *pdev) /* Ioremap the registers */ priv.reg = devm_ioremap(&pdev->dev, res_regs->start, - res_regs->end - res_regs->start); + resource_size(res_regs)); if (!priv.reg) { dev_err(&pdev->dev, "unable to ioremap registers\n"); return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From da9df93e9e0fd1d8c14315c6c0f989a30c291a11 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Dec 2014 15:23:14 +0800 Subject: gpio: dwapb: Convert to use resource managed APIs Use resource managed APIs to simplify the code a bit. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 53 +++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 39 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b4eb6a657d34..58faf04fce5d 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -469,15 +469,13 @@ dwapb_gpio_get_pdata_of(struct device *dev) if (nports == 0) return ERR_PTR(-ENODEV); - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL); - if (!pdata->properties) { - kfree(pdata); + pdata->properties = devm_kcalloc(dev, nports, sizeof(*pp), GFP_KERNEL); + if (!pdata->properties) return ERR_PTR(-ENOMEM); - } pdata->nports = nports; @@ -490,8 +488,6 @@ dwapb_gpio_get_pdata_of(struct device *dev) pp->idx >= DWAPB_MAX_PORTS) { dev_err(dev, "missing/invalid port index for %s\n", port_np->full_name); - kfree(pdata->properties); - kfree(pdata); return ERR_PTR(-EINVAL); } @@ -523,15 +519,6 @@ dwapb_gpio_get_pdata_of(struct device *dev) return pdata; } -static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata) -{ - if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata) - return; - - kfree(pdata->properties); - kfree(pdata); -} - static int dwapb_gpio_probe(struct platform_device *pdev) { unsigned int i; @@ -540,40 +527,32 @@ static int dwapb_gpio_probe(struct platform_device *pdev) int err; struct device *dev = &pdev->dev; struct dwapb_platform_data *pdata = dev_get_platdata(dev); - bool is_pdata_alloc = !pdata; - if (is_pdata_alloc) { + if (!pdata) { pdata = dwapb_gpio_get_pdata_of(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); } - if (!pdata->nports) { - err = -ENODEV; - goto out_err; - } + if (!pdata->nports) + return -ENODEV; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) { - err = -ENOMEM; - goto out_err; - } + if (!gpio) + return -ENOMEM; + gpio->dev = &pdev->dev; gpio->nr_ports = pdata->nports; gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL); - if (!gpio->ports) { - err = -ENOMEM; - goto out_err; - } + if (!gpio->ports) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gpio->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(gpio->regs)) { - err = PTR_ERR(gpio->regs); - goto out_err; - } + if (IS_ERR(gpio->regs)) + return PTR_ERR(gpio->regs); for (i = 0; i < gpio->nr_ports; i++) { err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); @@ -582,16 +561,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, gpio); - goto out_err; + return 0; out_unregister: dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); -out_err: - if (is_pdata_alloc) - dwapb_free_pdata_of(pdata); - return err; } -- cgit v1.2.3-59-g8ed1b From ffe4770b9b3483f74bccd0566fd1013ddc1b6d6b Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 29 Dec 2014 14:09:01 +0530 Subject: gpio-amd8111: check ioport_map return value ioport_map() may fail. Its safe to check the return value. Signed-off-by: Varka Bhadram Signed-off-by: Linus Walleij --- drivers/gpio/gpio-amd8111.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index d3d2d1099f64..2c4d9ab34acc 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -213,6 +213,11 @@ found: goto out; } gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + if (!gp.pm) { + dev_err(&pdev->dev, "Couldn't map io port into io memory\n"); + err = -ENOMEM; + goto out; + } gp.pdev = pdev; gp.chip.dev = &pdev->dev; -- cgit v1.2.3-59-g8ed1b From b9b4d9f2b91a9f1de1b93aee0bbd0259e8b67c53 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Wed, 7 Jan 2015 10:08:39 +0100 Subject: gpio:gpiolib: use static const char const * for a suffixes array Checkpatch complains, and probably with good reason that we should use const char const * for the static constant array that never gets changed. Signed-off-by: Olliver Schinagl Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 487afe6f22fc..9d2a37199806 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1657,7 +1657,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - static const char *suffixes[] = { "gpios", "gpio" }; + static const char const *suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; -- cgit v1.2.3-59-g8ed1b From a4319a611bcdc32f042578c9c9b75bbdc23149e3 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 10 Jan 2015 00:34:47 +0100 Subject: gpio: mvebu: checkpatch fixes Wrap some long lines. Prefer seq_puts() over seq_printf(). space to tab conversions. Spelling error fix. Signed-off-by: Andrew Lunn Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 77 ++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7bc3e9b288f3..7533d446b820 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -59,7 +59,7 @@ #define GPIO_LEVEL_MASK_OFF 0x001c /* The MV78200 has per-CPU registers for edge mask and level mask */ -#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) +#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) #define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C) /* The Armada XP has per-CPU registers for interrupt cause, interrupt @@ -69,11 +69,11 @@ #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4) #define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4) -#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 -#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 +#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 +#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3 -#define MVEBU_MAX_GPIO_PER_BANK 32 +#define MVEBU_MAX_GPIO_PER_BANK 32 struct mvebu_gpio_chip { struct gpio_chip chip; @@ -82,9 +82,9 @@ struct mvebu_gpio_chip { void __iomem *percpu_membase; int irqbase; struct irq_domain *domain; - int soc_variant; + int soc_variant; - /* Used to preserve GPIO registers accross suspend/resume */ + /* Used to preserve GPIO registers across suspend/resume */ u32 out_reg; u32 io_conf_reg; u32 blink_en_reg; @@ -107,7 +107,8 @@ static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_BLINK_EN_OFF; } -static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; } @@ -117,12 +118,14 @@ static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_IN_POL_OFF; } -static inline void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_DATA_IN_OFF; } -static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -132,13 +135,15 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc return mvchip->membase + GPIO_EDGE_CAUSE_OFF; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); default: BUG(); } } -static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -150,7 +155,8 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu); case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); default: BUG(); } @@ -168,7 +174,8 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu); case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); default: BUG(); } @@ -364,22 +371,22 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d) * value of the line or the opposite value. * * Level IRQ handlers: DATA_IN is used directly as cause register. - * Interrupt are masked by LEVEL_MASK registers. + * Interrupt are masked by LEVEL_MASK registers. * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. - * Interrupt are masked by EDGE_MASK registers. + * Interrupt are masked by EDGE_MASK registers. * Both-edge handlers: Similar to regular Edge handlers, but also swaps - * the polarity to catch the next line transaction. - * This is a race condition that might not perfectly - * work on some use cases. + * the polarity to catch the next line transaction. + * This is a race condition that might not perfectly + * work on some use cases. * * Every eight GPIO lines are grouped (OR'ed) before going up to main * cause register. * - * EDGE cause mask - * data-in /--------| |-----| |----\ - * -----| |----- ---- to main cause reg - * X \----------------| |----/ - * polarity LEVEL mask + * EDGE cause mask + * data-in /--------| |-----| |----\ + * -----| |----- ---- to main cause reg + * X \----------------| |----/ + * polarity LEVEL mask * ****************************************************************************/ @@ -394,9 +401,8 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin = d->hwirq; u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin); - if (!u) { + if (!u) return -EINVAL; - } type &= IRQ_TYPE_SENSE_MASK; if (type == IRQ_TYPE_NONE) @@ -529,13 +535,13 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) (data_in ^ in_pol) & msk ? "hi" : "lo", in_pol & msk ? "lo" : "hi"); if (!((edg_msk | lvl_msk) & msk)) { - seq_printf(s, " disabled\n"); + seq_puts(s, " disabled\n"); continue; } if (edg_msk & msk) - seq_printf(s, " edge "); + seq_puts(s, " edge "); if (lvl_msk & msk) - seq_printf(s, " level"); + seq_puts(s, " level"); seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); } } @@ -546,15 +552,15 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static const struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, }, { .compatible = "marvell,mv78200-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, }, { .compatible = "marvell,armadaxp-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, }, { /* sentinel */ @@ -668,7 +674,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) else soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; - mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); + mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), + GFP_KERNEL); if (!mvchip) return -ENOMEM; @@ -767,8 +774,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) * interrupt handlers, with each handler dealing with 8 GPIO * pins. */ for (i = 0; i < 4; i++) { - int irq; - irq = platform_get_irq(pdev, i); + int irq = platform_get_irq(pdev, i); + if (irq < 0) continue; irq_set_handler_data(irq, mvchip); @@ -827,7 +834,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) static struct platform_driver mvebu_gpio_driver = { .driver = { - .name = "mvebu-gpio", + .name = "mvebu-gpio", .of_match_table = mvebu_gpio_of_match, }, .probe = mvebu_gpio_probe, -- cgit v1.2.3-59-g8ed1b From f1d2d081e8d13b23ea53f32932ae03af76934b9a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 10 Jan 2015 00:34:48 +0100 Subject: gpio: mvebu: Fix probe cleanup on error Ensure that when there is an error during probe that the gpiochip is removed and the generic irq chip is removed. Signed-off-by: Andrew Lunn Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7533d446b820..d0bc123c7975 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -667,6 +667,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) unsigned int ngpios; int soc_variant; int i, cpu, id; + int err; match = of_match_device(mvebu_gpio_of_match, &pdev->dev); if (match) @@ -785,14 +786,16 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); if (mvchip->irqbase < 0) { dev_err(&pdev->dev, "no irqs\n"); - return mvchip->irqbase; + err = mvchip->irqbase; + goto err_gpiochip_add; } gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase, mvchip->membase, handle_level_irq); if (!gc) { dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_gpiochip_add; } gc->private = mvchip; @@ -823,13 +826,21 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (!mvchip->domain) { dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", mvchip->chip.label); - irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, - IRQ_LEVEL | IRQ_NOPROBE); - kfree(gc); - return -ENODEV; + err = -ENODEV; + goto err_generic_chip; } return 0; + +err_generic_chip: + irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, + IRQ_LEVEL | IRQ_NOPROBE); + kfree(gc); + +err_gpiochip_add: + gpiochip_remove(&mvchip->chip); + + return err; } static struct platform_driver mvebu_gpio_driver = { -- cgit v1.2.3-59-g8ed1b From 7d82bf3419c103dbb730e7834186fc5d577b9da1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Jan 2015 11:07:58 +0100 Subject: gpio: rcar: Fix error path for devm_kzalloc() failure If the call to devm_kzalloc() fails, nothing must be cleant up. This was missed before because gpio_rcar_probe() had a "return" statement after the first "goto err0". Signed-off-by: Geert Uytterhoeven Fixes: df0c6c80232f2ad4 ("gpio: rcar: Add minimal runtime PM support") Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 584484e3f1e3..ca2b6310f8f7 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -372,10 +372,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) int ret; p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); - if (!p) { - ret = -ENOMEM; - goto err0; - } + if (!p) + return -ENOMEM; p->pdev = pdev; spin_lock_init(&p->lock); -- cgit v1.2.3-59-g8ed1b From c7f3c5d3ac2d683169485b2f14d1aff19de2b2fe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Jan 2015 11:07:59 +0100 Subject: gpio: rcar: Switch to use gpiolib irqchip helpers Switch the R-Car Gen2 GPIO driver to use the gpiolib irqchip helpers. While doing this also make sure that gpiochip_irqchip_add() is called after the gpiochip itself is registered, as required. Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-rcar.c | 69 ++++++++++++++++-------------------------------- 2 files changed, 24 insertions(+), 46 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1eff81c93b75..ba1bc73d9d7d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -286,6 +286,7 @@ config GPIO_PXA config GPIO_RCAR tristate "Renesas R-Car GPIO" depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST) + select GPIOLIB_IRQCHIP help Say yes here to support GPIO on Renesas R-Car SoCs. diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index ca2b6310f8f7..c49522efa7b3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -38,7 +37,6 @@ struct gpio_rcar_priv { struct platform_device *pdev; struct gpio_chip gpio_chip; struct irq_chip irq_chip; - struct irq_domain *irq_domain; }; #define IOINTSEL 0x00 @@ -82,14 +80,18 @@ static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs, static void gpio_rcar_irq_disable(struct irq_data *d) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d))); } static void gpio_rcar_irq_enable(struct irq_data *d) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d))); } @@ -131,7 +133,9 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); unsigned int hwirq = irqd_to_hwirq(d); dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type); @@ -175,7 +179,8 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) gpio_rcar_read(p, INTMSK))) { offset = __ffs(pending); gpio_rcar_write(p, INTCLR, BIT(offset)); - generic_handle_irq(irq_find_mapping(p->irq_domain, offset)); + generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain, + offset)); irqs_handled++; } @@ -265,29 +270,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) -{ - return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); -} - -static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct gpio_rcar_priv *p = h->host_data; - - dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq); - - irq_set_chip_data(irq, h->host_data); - irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); /* kill me now */ - return 0; -} - -static struct irq_domain_ops gpio_rcar_irq_domain_ops = { - .map = gpio_rcar_irq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - struct gpio_rcar_info { bool has_both_edge_trigger; }; @@ -411,7 +393,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->get = gpio_rcar_get; gpio_chip->direction_output = gpio_rcar_direction_output; gpio_chip->set = gpio_rcar_set; - gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->label = name; gpio_chip->dev = dev; gpio_chip->owner = THIS_MODULE; @@ -426,16 +407,19 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - p->config.number_of_pins, - p->config.irq_base, - &gpio_rcar_irq_domain_ops, p); - if (!p->irq_domain) { - ret = -ENXIO; - dev_err(dev, "cannot initialize irq domain\n"); + ret = gpiochip_add(gpio_chip); + if (ret) { + dev_err(dev, "failed to add GPIO controller\n"); goto err0; } + ret = gpiochip_irqchip_add(&p->gpio_chip, irq_chip, p->config.irq_base, + handle_level_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "cannot add irqchip\n"); + goto err1; + } + if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { dev_err(dev, "failed to request IRQ\n"); @@ -443,17 +427,11 @@ static int gpio_rcar_probe(struct platform_device *pdev) goto err1; } - ret = gpiochip_add(gpio_chip); - if (ret) { - dev_err(dev, "failed to add GPIO controller\n"); - goto err1; - } - dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins); /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { - ret = irq_find_mapping(p->irq_domain, 0); + ret = irq_find_mapping(p->gpio_chip.irqdomain, 0); if (p->config.irq_base != ret) dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); @@ -469,7 +447,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) return 0; err1: - irq_domain_remove(p->irq_domain); + gpiochip_remove(&p->gpio_chip); err0: pm_runtime_put(dev); pm_runtime_disable(dev); @@ -482,7 +460,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - irq_domain_remove(p->irq_domain); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; -- cgit v1.2.3-59-g8ed1b From f28f8eff9148eb2a3a568cc378167ba28dd2f225 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 13 Jan 2015 10:41:57 +0100 Subject: gpio/Kconfig: Fix X86 arch name X86 Kconfig symbol is X86, not ARCH_X86. Fixes: c586b3075d5b47d8 (gpio/xilinx: Add support for X86 Arch) Reported-by: Paul Bolle Signed-off-by: Ricardo Ribalda Delgado 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 ba1bc73d9d7d..192f97396d12 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -369,7 +369,7 @@ config GPIO_XGENE config GPIO_XILINX tristate "Xilinx GPIO support" - depends on OF_GPIO && (PPC_OF || MICROBLAZE || ARCH_ZYNQ || ARCH_X86) + depends on OF_GPIO && (PPC_OF || MICROBLAZE || ARCH_ZYNQ || X86) help Say yes here to support the Xilinx FPGA GPIO device -- cgit v1.2.3-59-g8ed1b From 43c4bcf9425ef596f9651bd0c647065dc5e9ad50 Mon Sep 17 00:00:00 2001 From: Semen Protsenko Date: Tue, 13 Jan 2015 15:41:42 +0200 Subject: gpio: max732x: Add device tree support Signed-off-by: Semen Protsenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 62 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 11 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 6c676225b886..a642f780901d 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -21,6 +21,7 @@ #include #include #include +#include /* @@ -116,6 +117,22 @@ static const struct i2c_device_id max732x_id[] = { }; MODULE_DEVICE_TABLE(i2c, max732x_id); +#ifdef CONFIG_OF +static const struct of_device_id max732x_of_table[] = { + { .compatible = "maxim,max7319" }, + { .compatible = "maxim,max7320" }, + { .compatible = "maxim,max7321" }, + { .compatible = "maxim,max7322" }, + { .compatible = "maxim,max7323" }, + { .compatible = "maxim,max7324" }, + { .compatible = "maxim,max7325" }, + { .compatible = "maxim,max7326" }, + { .compatible = "maxim,max7327" }, + { } +}; +MODULE_DEVICE_TABLE(of, max732x_of_table); +#endif + struct max732x_chip { struct gpio_chip gpio_chip; @@ -457,10 +474,12 @@ static int max732x_irq_setup(struct max732x_chip *chip, int has_irq = max732x_features[id->driver_data] >> 32; int ret; - if (pdata->irq_base && has_irq != INT_NONE) { + if (((pdata && pdata->irq_base) || client->irq) + && has_irq != INT_NONE) { int lvl; - chip->irq_base = pdata->irq_base; + if (pdata) + chip->irq_base = pdata->irq_base; chip->irq_features = has_irq; mutex_init(&chip->irq_lock); @@ -515,7 +534,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); int has_irq = max732x_features[id->driver_data] >> 32; - if (pdata->irq_base && has_irq != INT_NONE) + if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; @@ -574,28 +593,47 @@ static int max732x_setup_gpio(struct max732x_chip *chip, return port; } +static struct max732x_platform_data *of_gpio_max732x(struct device *dev) +{ + struct max732x_platform_data *pdata; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->gpio_base = -1; + + return pdata; +} + static int max732x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max732x_platform_data *pdata; + struct device_node *node; struct max732x_chip *chip; struct i2c_client *c; uint16_t addr_a, addr_b; int ret, nr_port; pdata = dev_get_platdata(&client->dev); - if (pdata == NULL) { + node = client->dev.of_node; + + if (!pdata && node) + pdata = of_gpio_max732x(&client->dev); + + if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; } - chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip), - GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->client = client; nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base); + chip->gpio_chip.dev = &client->dev; addr_a = (client->addr & 0x0f) | 0x60; addr_b = (client->addr & 0x0f) | 0x50; @@ -643,7 +681,7 @@ static int max732x_probe(struct i2c_client *client, if (ret) goto out_failed; - if (pdata->setup) { + if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) @@ -664,9 +702,10 @@ static int max732x_remove(struct i2c_client *client) { struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); struct max732x_chip *chip = i2c_get_clientdata(client); - int ret; - if (pdata->teardown) { + if (pdata && pdata->teardown) { + int ret; + ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) { @@ -689,8 +728,9 @@ static int max732x_remove(struct i2c_client *client) static struct i2c_driver max732x_driver = { .driver = { - .name = "max732x", - .owner = THIS_MODULE, + .name = "max732x", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max732x_of_table), }, .probe = max732x_probe, .remove = max732x_remove, -- cgit v1.2.3-59-g8ed1b From 479f8a5744d8141e95ef40ab364ae2d3648848ef Mon Sep 17 00:00:00 2001 From: Semen Protsenko Date: Tue, 13 Jan 2015 15:41:43 +0200 Subject: gpio: max732x: Rewrite IRQ code to use irq_domain API Signed-off-by: Semen Protsenko Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-max732x.c | 100 ++++++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 35 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 192f97396d12..d24492c59bf9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -528,6 +528,7 @@ config GPIO_MAX7300 config GPIO_MAX732X tristate "MAX7319, MAX7320-7327 I2C Port Expanders" depends on I2C + select IRQ_DOMAIN help Say yes here to support the MAX7319, MAX7320-7327 series of I2C Port Expanders. Each IO port on these chips has a fixed role of diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index a642f780901d..f8f3e8081a89 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -149,13 +150,14 @@ struct max732x_chip { uint8_t reg_out[2]; #ifdef CONFIG_GPIO_MAX732X_IRQ - struct mutex irq_lock; - int irq_base; - uint8_t irq_mask; - uint8_t irq_mask_cur; - uint8_t irq_trig_raise; - uint8_t irq_trig_fall; - uint8_t irq_features; + struct irq_domain *irq_domain; + struct mutex irq_lock; + int irq_base; + uint8_t irq_mask; + uint8_t irq_mask_cur; + uint8_t irq_trig_raise; + uint8_t irq_trig_fall; + uint8_t irq_features; #endif }; @@ -341,21 +343,27 @@ static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) struct max732x_chip *chip; chip = container_of(gc, struct max732x_chip, gpio_chip); - return chip->irq_base + off; + + if (chip->irq_domain) { + return irq_create_mapping(chip->irq_domain, + chip->irq_base + off); + } else { + return -ENXIO; + } } static void max732x_irq_mask(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask_cur &= ~(1 << d->hwirq); } static void max732x_irq_unmask(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base); + chip->irq_mask_cur |= 1 << d->hwirq; } static void max732x_irq_bus_lock(struct irq_data *d) @@ -377,7 +385,7 @@ static void max732x_irq_bus_sync_unlock(struct irq_data *d) static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - uint16_t off = d->irq - chip->irq_base; + uint16_t off = d->hwirq; uint16_t mask = 1 << off; if (!(mask & chip->dir_input)) { @@ -458,7 +466,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->irq_domain, level)); pending &= ~(1 << level); } while (pending); @@ -466,6 +474,44 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) return IRQ_HANDLED; } +static int max732x_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct max732x_chip *chip = h->host_data; + + if (!(chip->dir_input & (1 << hw))) { + dev_err(&chip->client->dev, + "Attempt to map output line as IRQ line: %lu\n", + hw); + return -EPERM; + } + + irq_set_chip_data(virq, chip); + irq_set_chip_and_handler(virq, &max732x_irq_chip, + handle_edge_irq); + irq_set_nested_thread(virq, 1); +#ifdef CONFIG_ARM + /* ARM needs us to explicitly flag the IRQ as valid + * and will set them noprobe when we do so. */ + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + + return 0; +} + +static struct irq_domain_ops max732x_irq_domain_ops = { + .map = max732x_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void max732x_irq_teardown(struct max732x_chip *chip) +{ + if (chip->client->irq && chip->irq_domain) + irq_domain_remove(chip->irq_domain); +} + static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { @@ -476,28 +522,17 @@ static int max732x_irq_setup(struct max732x_chip *chip, if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE) { - int lvl; - if (pdata) chip->irq_base = pdata->irq_base; chip->irq_features = has_irq; mutex_init(&chip->irq_lock); - for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { - int irq = lvl + chip->irq_base; - - if (!(chip->dir_input & (1 << lvl))) - continue; - - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &max732x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + chip->irq_domain = irq_domain_add_simple(client->dev.of_node, + chip->gpio_chip.ngpio, chip->irq_base, + &max732x_irq_domain_ops, chip); + if (!chip->irq_domain) { + dev_err(&client->dev, "Failed to create IRQ domain\n"); + return -ENOMEM; } ret = request_threaded_irq(client->irq, @@ -517,15 +552,10 @@ static int max732x_irq_setup(struct max732x_chip *chip, return 0; out_failed: - chip->irq_base = 0; + max732x_irq_teardown(chip); return ret; } -static void max732x_irq_teardown(struct max732x_chip *chip) -{ - if (chip->irq_base) - free_irq(chip->client->irq, chip); -} #else /* CONFIG_GPIO_MAX732X_IRQ */ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) -- cgit v1.2.3-59-g8ed1b From 09afa276d52ea5a7ff8fcd2ad9dfe204bfb18372 Mon Sep 17 00:00:00 2001 From: Semen Protsenko Date: Tue, 13 Jan 2015 15:41:44 +0200 Subject: gpio: max732x: Fix possible deadlock This patch was derived from next one: "gpio: fix pca953x set_type 'scheduling while atomic' bug". After adding entry that consumes max732x GPIO as interrupt line to dts file, deadlock appears somewhere in max732x probe function. Deadlock caught by lockdep (from kernel log): <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< cut here >>>>>>>>>>>>>>>>>>>>>>>>>>> [ 0.473419] ====================================================== [ 0.473419] [ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ] [ 0.473449] 3.x.xx-xxxxx-xxxxxxxx-dirty #2 Tainted: G W [ 0.473449] ------------------------------------------------------ [ 0.473449] swapper/0/1 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: [ 0.473449] (&lock->wait_lock){+.+...}, at: [] rt_mutex_trylock+0xc/0x74 [ 0.473480] [ 0.473480] and this task is already holding: [ 0.473510] (&chip->lock){......}, at: [] max732x_gpio_set_value+0x2c/0xa4 [ 0.473541] which would create a new lock dependency: [ 0.473541] (&chip->lock){......} -> (&lock->wait_lock){+.+...} ... [ 0.474273] *** DEADLOCK *** [ 0.474273] [ 0.474273] 5 locks held by swapper/0/1: [ 0.474273] #0: (&__lockdep_no_validate__){......}, at: [] __driver_attach+0x48/0x98 [ 0.474304] #1: (&__lockdep_no_validate__){......}, at: [] __driver_attach+0x58/0x98 [ 0.474334] #2: (&chip->irq_lock){+.+...}, at: [] max732x_irq_bus_lock+0x14/0x20 [ 0.474365] #3: (&irq_desc_lock_class){-.....}, at: [] __irq_get_desc_lock+0x48/0x88 [ 0.474365] #4: (&chip->lock){......}, at: [] max732x_gpio <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< cut here >>>>>>>>>>>>>>>>>>>>>>>>>>> Signed-off-by: Semen Protsenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index f8f3e8081a89..5fbab135f4a7 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -377,8 +377,18 @@ static void max732x_irq_bus_lock(struct irq_data *d) static void max732x_irq_bus_sync_unlock(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t new_irqs; + uint16_t level; max732x_irq_update_mask(chip); + + new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; + while (new_irqs) { + level = __ffs(new_irqs); + max732x_gpio_direction_input(&chip->gpio_chip, level); + new_irqs &= ~(1 << level); + } + mutex_unlock(&chip->irq_lock); } @@ -410,7 +420,7 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type) else chip->irq_trig_raise &= ~mask; - return max732x_gpio_direction_input(&chip->gpio_chip, off); + return 0; } static struct irq_chip max732x_irq_chip = { -- cgit v1.2.3-59-g8ed1b From 1fbb29c2f7b41c78c618ac80592b5ed43aa296cf Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Tue, 13 Jan 2015 20:39:38 +0530 Subject: gpio: gpio-dln2: Added a Blank line after declaration Fix the coding style issue by adding a blank line after declaration Signed-off-by: Mohammad Jamal Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dln2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index 978b51eae2ec..3e07232b8370 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -400,6 +400,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo, const void *data, int len) { int pin, irq; + const struct { __le16 count; __u8 type; -- cgit v1.2.3-59-g8ed1b From 866010fb7ea03b73a0528b99298254c43ac12888 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Mon, 1 Dec 2014 17:39:37 +0530 Subject: gpio: ge: convert to use basic mmio gpio library This patch converts GE GPIO driver to use basic_mmio_gpio generic library. Signed-off-by: Kamlakant Patel Acked-by: Martyn Welch Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-ge.c | 96 ++++++++++++++++++++------------------------------ 2 files changed, 40 insertions(+), 57 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d24492c59bf9..8dcd0bd5b0fa 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -459,6 +459,7 @@ config GPIO_VX855 config GPIO_GE_FPGA bool "GE FPGA based GPIO" depends on GE_FPGA + select GPIO_GENERIC help Support for common GPIO functionality provided on some GE Single Board Computers. diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index aea5c2a53cc0..2456f6489bd1 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -21,7 +21,9 @@ #include #include #include +#include #include +#include #define GEF_GPIO_DIRECT 0x00 #define GEF_GPIO_IN 0x04 @@ -33,53 +35,6 @@ #define GEF_GPIO_OVERRUN 0x1C #define GEF_GPIO_MODE 0x20 -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - unsigned int data; - - data = ioread32be(mmchip->regs + GEF_GPIO_OUT); - if (value) - data = data | BIT(offset); - else - data = data & ~BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_OUT); -} - -static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - /* Set value before switching to output */ - gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset)); -} - static const struct of_device_id gef_gpio_ids[] = { { .compatible = "gef,sbc610-gpio", @@ -99,22 +54,49 @@ static int __init gef_gpio_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(gef_gpio_ids, &pdev->dev); - struct of_mm_gpio_chip *mmchip; + struct bgpio_chip *bgc; + void __iomem *regs; + int ret; - mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL); - if (!mmchip) + bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; + regs = of_iomap(pdev->dev.of_node, 0); + if (!regs) + return -ENOMEM; + + ret = bgpio_init(bgc, &pdev->dev, 4, regs + GEF_GPIO_IN, + regs + GEF_GPIO_OUT, NULL, NULL, + regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + goto err0; + } + /* Setup pointers to chip functions */ - mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data; - mmchip->gc.of_gpio_n_cells = 2; - mmchip->gc.direction_input = gef_gpio_dir_in; - mmchip->gc.direction_output = gef_gpio_dir_out; - mmchip->gc.get = gef_gpio_get; - mmchip->gc.set = gef_gpio_set; + bgc->gc.label = kstrdup(pdev->dev.of_node->full_name, GFP_KERNEL); + if (!bgc->gc.label) + goto err0; + + bgc->gc.base = -1; + bgc->gc.ngpio = (u16)(uintptr_t)of_id->data; + bgc->gc.of_gpio_n_cells = 2; + bgc->gc.of_node = pdev->dev.of_node; /* This function adds a memory mapped GPIO chip */ - return of_mm_gpiochip_add(pdev->dev.of_node, mmchip); + ret = gpiochip_add(&bgc->gc); + if (ret) + goto err1; + + return 0; +err1: + kfree(bgc->gc.label); +err0: + iounmap(regs); + pr_err("%s: GPIO chip registration failed\n", + pdev->dev.of_node->full_name); + return ret; }; static struct platform_driver gef_gpio_driver = { -- cgit v1.2.3-59-g8ed1b From a0b66e3f5a2522d1a5cf1127bc8cba0834b0fbf6 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Mon, 19 Jan 2015 10:52:06 +0530 Subject: gpio: ge: fix compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include linux/slab.h to fix following compilation error. drivers/gpio/gpio-ge.c: In function ‘gef_gpio_probe’: drivers/gpio/gpio-ge.c:95:2: error: implicit declaration of function ‘kfree’ [-Werror=implicit-function-declaration] kfree(bgc->gc.label); Signed-off-by: Kamlakant Patel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ge.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 2456f6489bd1..6ea930372028 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 513858585202171d7603024ea65659335df4c8e9 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 19 Jan 2015 13:35:48 +0530 Subject: gpio-amd8111: add release_region on ioport_map failure Commit ffe4770b9b3483f74 ("gpio-amd8111: check ioport_map return value") adds the error check on ioport_map(). It doesnt release the requested region. On failure this patch release the region that has requested before. Signed-off-by: Varka Bhadram Reported-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-amd8111.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 2c4d9ab34acc..d00d81928fe8 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -215,6 +215,7 @@ found: gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); if (!gp.pm) { dev_err(&pdev->dev, "Couldn't map io port into io memory\n"); + release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); err = -ENOMEM; goto out; } -- cgit v1.2.3-59-g8ed1b From 73c4ceda09db2c9a2ff8bb2e90cc98ce1a827c34 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Wed, 14 Jan 2015 15:46:38 +0100 Subject: gpio-generic: add bgpio_set_multiple functions Add set_multiple functions to the generic driver for memory-mapped GPIO controllers to improve performance when setting multiple outputs simultaneously. Signed-off-by: Rojhalat Ibrahim Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 16f6115e5bdb..b92a690f5765 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) spin_unlock_irqrestore(&bgc->lock, flags); } +static void bgpio_multiple_get_masks(struct bgpio_chip *bgc, + unsigned long *mask, unsigned long *bits, + unsigned long *set_mask, + unsigned long *clear_mask) +{ + int i; + + *set_mask = 0; + *clear_mask = 0; + + for (i = 0; i < bgc->bits; i++) { + if (*mask == 0) + break; + if (__test_and_clear_bit(i, mask)) { + if (test_bit(i, bits)) + *set_mask |= bgc->pin2mask(bgc, i); + else + *clear_mask |= bgc->pin2mask(bgc, i); + } + } +} + +static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc, + unsigned long *mask, + unsigned long *bits, + void __iomem *reg) +{ + unsigned long flags; + unsigned long set_mask, clear_mask; + + spin_lock_irqsave(&bgc->lock, flags); + + bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); + + bgc->data |= set_mask; + bgc->data &= ~clear_mask; + + bgc->write_reg(reg, bgc->data); + + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat); +} + +static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set); +} + +static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + unsigned long set_mask, clear_mask; + + bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); + + if (set_mask) + bgc->write_reg(bgc->reg_set, set_mask); + if (clear_mask) + bgc->write_reg(bgc->reg_clr, clear_mask); +} + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) { return 0; @@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, bgc->reg_set = set; bgc->reg_clr = clr; bgc->gc.set = bgpio_set_with_clear; + bgc->gc.set_multiple = bgpio_set_multiple_with_clear; } else if (set && !clr) { bgc->reg_set = set; bgc->gc.set = bgpio_set_set; + bgc->gc.set_multiple = bgpio_set_multiple_set; } else { bgc->gc.set = bgpio_set; + bgc->gc.set_multiple = bgpio_set_multiple; } bgc->gc.get = bgpio_get; -- cgit v1.2.3-59-g8ed1b From 04d2264c3bf07f5c3d18165ba78de0a93360c6c0 Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Thu, 15 Jan 2015 08:16:10 +0800 Subject: gpio: sx150x: add dts support for sx150x driver Current sx150x gpio expander driver doesn't support DTS. Now we added dts support for this driver. Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-sx150x.txt | 40 ++++++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/gpio/gpio-sx150x.c | 17 ++++++++- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-sx150x.txt (limited to 'drivers/gpio') diff --git a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt new file mode 100644 index 000000000000..ba2bb84eeac3 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt @@ -0,0 +1,40 @@ +SEMTECH SX150x GPIO expander bindings + + +Required properties: + +- compatible: should be "semtech,sx1506q", + "semtech,sx1508q", + "semtech,sx1509q". + +- reg: The I2C slave address for this device. + +- interrupt-parent: phandle of the parent interrupt controller. + +- interrupts: Interrupt specifier for the controllers interrupt. + +- #gpio-cells: Should be 2. The first cell is the GPIO number and the + second cell is used to specify optional parameters: + bit 0: polarity (0: normal, 1: inverted) + +- gpio-controller: Marks the device as a GPIO controller. + +- interrupt-controller: Marks the device as a interrupt controller. + +The GPIO expander can optionally be used as an interrupt controller, in +which case it uses the default two cell specifier as described in +Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + +Example: + + i2c_gpio_expander@20{ + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "semtech,sx1506q"; + reg = <0x20>; + interrupt-parent = <&gpio_1>; + interrupts = <16 0>; + + gpio-controller; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index b1df0ad1306c..ce751cb0ce1a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -141,6 +141,7 @@ sandisk Sandisk Corporation sbs Smart Battery System schindler Schindler seagate Seagate Technology PLC +semtech Semtech Corporation sil Silicon Image silabs Silicon Laboratories simtek diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index 20573ac714fc..88012e2b5b15 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -23,6 +23,11 @@ #include #include #include +#include +#include +#include +#include +#include #define NO_UPDATE_PENDING -1 @@ -147,6 +152,13 @@ static const struct i2c_device_id sx150x_id[] = { }; MODULE_DEVICE_TABLE(i2c, sx150x_id); +static const struct of_device_id sx150x_dt_id[] = { + { .compatible = "semtech,sx1508q" }, + { .compatible = "semtech,sx1509q" }, + { .compatible = "semtech,sx1506q" }, + {}, +}; + static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { s32 err = i2c_smbus_write_byte_data(client, reg, val); @@ -472,6 +484,8 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->gpio_chip.base = pdata->gpio_base; chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; + chip->gpio_chip.of_node = client->dev.of_node; + chip->gpio_chip.of_gpio_n_cells = 2; if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; @@ -666,7 +680,8 @@ static int sx150x_remove(struct i2c_client *client) static struct i2c_driver sx150x_driver = { .driver = { .name = "sx150x", - .owner = THIS_MODULE + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sx150x_dt_id), }, .probe = sx150x_probe, .remove = sx150x_remove, -- cgit v1.2.3-59-g8ed1b From b2b35e10892cb1253c93c582e6a3d7ad91ed9f3f Mon Sep 17 00:00:00 2001 From: Y Vo Date: Fri, 16 Jan 2015 14:34:19 +0700 Subject: gpio: Add APM X-Gene standby GPIO controller driver Driver for standby GPIO controller of APM X-Gene SoCs on arm64. Signed-off-by: Y Vo Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 8 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-xgene-sb.c | 160 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 drivers/gpio/gpio-xgene-sb.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8dcd0bd5b0fa..4187fcbc88fd 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -367,6 +367,14 @@ config GPIO_XGENE the generic flash controller's address and data pins. Say yes here to enable the GFC GPIO functionality. +config GPIO_XGENE_SB + tristate "APM X-Gene GPIO standby controller support" + depends on ARCH_XGENE && OF_GPIO + select GPIO_GENERIC + help + This driver supports the GPIO block within the APM X-Gene + Standby Domain. Say yes here to enable the GPIO functionality. + config GPIO_XILINX tristate "Xilinx GPIO support" depends on OF_GPIO && (PPC_OF || MICROBLAZE || ARCH_ZYNQ || X86) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 81755f1305e6..3031b19f06ba 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o +obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c new file mode 100644 index 000000000000..b6a15c39293e --- /dev/null +++ b/drivers/gpio/gpio-xgene-sb.c @@ -0,0 +1,160 @@ +/* + * AppliedMicro X-Gene SoC GPIO-Standby Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Tin Huynh . + * Y Vo . + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#define XGENE_MAX_GPIO_DS 22 +#define XGENE_MAX_GPIO_DS_IRQ 6 + +#define GPIO_MASK(x) (1U << ((x) % 32)) + +#define MPA_GPIO_INT_LVL 0x0290 +#define MPA_GPIO_OE_ADDR 0x029c +#define MPA_GPIO_OUT_ADDR 0x02a0 +#define MPA_GPIO_IN_ADDR 0x02a4 +#define MPA_GPIO_SEL_LO 0x0294 + +/** + * struct xgene_gpio_sb - GPIO-Standby private data structure. + * @bgc: memory-mapped GPIO controllers. + * @irq: Mapping GPIO pins and interrupt number + * nirq: Number of GPIO pins that supports interrupt + */ +struct xgene_gpio_sb { + struct bgpio_chip bgc; + u32 *irq; + u32 nirq; +}; + +static inline struct xgene_gpio_sb *to_xgene_gpio_sb(struct gpio_chip *gc) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return container_of(bgc, struct xgene_gpio_sb, bgc); +} + +static void xgene_gpio_set_bit(struct bgpio_chip *bgc, void __iomem *reg, u32 gpio, int val) +{ + u32 data; + + data = bgc->read_reg(reg); + if (val) + data |= GPIO_MASK(gpio); + else + data &= ~GPIO_MASK(gpio); + bgc->write_reg(reg, data); +} + +static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) +{ + struct xgene_gpio_sb *priv = to_xgene_gpio_sb(gc); + + if (priv->irq[gpio]) + return priv->irq[gpio]; + + return -ENXIO; +} + +static int xgene_gpio_sb_probe(struct platform_device *pdev) +{ + struct xgene_gpio_sb *priv; + u32 ret, i; + u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D}; + struct resource *res; + void __iomem *regs; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (!regs) + return PTR_ERR(regs); + + ret = bgpio_init(&priv->bgc, &pdev->dev, 4, + regs + MPA_GPIO_IN_ADDR, + regs + MPA_GPIO_OUT_ADDR, NULL, + regs + MPA_GPIO_OE_ADDR, NULL, 0); + if (ret) + return ret; + + priv->bgc.gc.to_irq = apm_gpio_sb_to_irq; + priv->bgc.gc.ngpio = XGENE_MAX_GPIO_DS; + + priv->nirq = XGENE_MAX_GPIO_DS_IRQ; + + priv->irq = devm_kzalloc(&pdev->dev, sizeof(u32) * XGENE_MAX_GPIO_DS, + GFP_KERNEL); + if (!priv->irq) + return -ENOMEM; + memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS); + + for (i = 0; i < priv->nirq; i++) { + priv->irq[default_lines[i]] = platform_get_irq(pdev, i); + xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_SEL_LO, + default_lines[i] * 2, 1); + xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_INT_LVL, i, 1); + } + + platform_set_drvdata(pdev, priv); + + ret = gpiochip_add(&priv->bgc.gc); + if (ret) + dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n"); + else + dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); + + return ret; +} + +static int xgene_gpio_sb_remove(struct platform_device *pdev) +{ + struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); + + return bgpio_remove(&priv->bgc); +} + +static const struct of_device_id xgene_gpio_sb_of_match[] = { + {.compatible = "apm,xgene-gpio-sb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match); + +static struct platform_driver xgene_gpio_sb_driver = { + .driver = { + .name = "xgene-gpio-sb", + .of_match_table = xgene_gpio_sb_of_match, + }, + .probe = xgene_gpio_sb_probe, + .remove = xgene_gpio_sb_remove, +}; +module_platform_driver(xgene_gpio_sb_driver); + +MODULE_AUTHOR("AppliedMicro"); +MODULE_DESCRIPTION("APM X-Gene GPIO Standby driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 1dfb4a0d7615811ec4a61b0a7631c8ddc0baf335 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 13 Jan 2015 08:00:29 +0100 Subject: gpio: stmpe: enforce device tree only mode Require that device tree be used with STMPE (all platforms use this) and enforce OF_GPIO, then delete the platform data. Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-stmpe.c | 23 +++-------------------- include/linux/mfd/stmpe.h | 16 ---------------- 3 files changed, 4 insertions(+), 36 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4187fcbc88fd..22b46567b3bb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -644,6 +644,7 @@ config GPIO_SX150X config GPIO_STMPE bool "STMPE GPIOs" depends on MFD_STMPE + depends on OF_GPIO select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the STMPE I/O diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 85c5b1974294..dabfb99dddef 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -30,7 +30,7 @@ struct stmpe_gpio { struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; - unsigned norequest_mask; + u32 norequest_mask; /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -340,13 +340,10 @@ static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; - struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; int irq = 0; - pdata = stmpe->pdata->gpio; - irq = platform_get_irq(pdev, 0); stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); @@ -360,19 +357,14 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.dev = &pdev->dev; -#ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; -#endif stmpe_gpio->chip.base = -1; if (IS_ENABLED(CONFIG_DEBUG_FS)) stmpe_gpio->chip.dbg_show = stmpe_dbg_show; - if (pdata) - stmpe_gpio->norequest_mask = pdata->norequest_mask; - else if (np) - of_property_read_u32(np, "st,norequest-mask", - &stmpe_gpio->norequest_mask); + of_property_read_u32(np, "st,norequest-mask", + &stmpe_gpio->norequest_mask); if (irq < 0) dev_info(&pdev->dev, @@ -414,9 +406,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) NULL); } - if (pdata && pdata->setup) - pdata->setup(stmpe, stmpe_gpio->chip.base); - platform_set_drvdata(pdev, stmpe_gpio); return 0; @@ -433,15 +422,9 @@ static int stmpe_gpio_remove(struct platform_device *pdev) { struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); struct stmpe *stmpe = stmpe_gpio->stmpe; - struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio; - - if (pdata && pdata->remove) - pdata->remove(stmpe, stmpe_gpio->chip.base); gpiochip_remove(&stmpe_gpio->chip); - stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - kfree(stmpe_gpio); return 0; diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index f742b6717d52..c9d869027300 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -117,20 +117,6 @@ extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks); #define STMPE_GPIO_NOREQ_811_TOUCH (0xf0) -/** - * struct stmpe_gpio_platform_data - STMPE GPIO platform data - * @norequest_mask: bitmask specifying which GPIOs should _not_ be - * requestable due to different usage (e.g. touch, keypad) - * STMPE_GPIO_NOREQ_* macros can be used here. - * @setup: board specific setup callback. - * @remove: board specific remove callback - */ -struct stmpe_gpio_platform_data { - unsigned norequest_mask; - void (*setup)(struct stmpe *stmpe, unsigned gpio_base); - void (*remove)(struct stmpe *stmpe, unsigned gpio_base); -}; - /** * struct stmpe_ts_platform_data - stmpe811 touch screen controller platform * data @@ -182,7 +168,6 @@ struct stmpe_ts_platform_data { * @irq_over_gpio: true if gpio is used to get irq * @irq_gpio: gpio number over which irq will be requested (significant only if * irq_over_gpio is true) - * @gpio: GPIO-specific platform data * @ts: touchscreen-specific platform data */ struct stmpe_platform_data { @@ -194,7 +179,6 @@ struct stmpe_platform_data { int irq_gpio; int autosleep_timeout; - struct stmpe_gpio_platform_data *gpio; struct stmpe_ts_platform_data *ts; }; -- cgit v1.2.3-59-g8ed1b From f91b2dbba5fdbe2d211aa8a4b353a8d3b5126f45 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sun, 18 Jan 2015 12:39:26 +0100 Subject: gpio: mpc5200: Use of_mm_gpiochip_remove Since d621e8bae5ac9c67 (Create of_mm_gpiochip_remove), there is a counterpart for of_mm_gpiochip_add. This patch implements the remove function of the driver making use of it. Cc: Alexandre Courbot Cc: Sascha Hauer Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc5200.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index 8ce6c9510035..4c542153e923 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -155,10 +155,12 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) struct gpio_chip *gc; int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(ofdev, chip); + gc = &chip->mmchip.gc; gc->ngpio = 8; @@ -181,7 +183,11 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) static int mpc52xx_gpiochip_remove(struct platform_device *ofdev) { - return -EBUSY; + struct mpc52xx_gpiochip *chip = platform_get_drvdata(ofdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = { @@ -314,10 +320,12 @@ static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) struct mpc52xx_gpio __iomem *regs; int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(ofdev, chip); + gc = &chip->mmchip.gc; gc->ngpio = 32; @@ -363,11 +371,16 @@ static int __init mpc52xx_gpio_init(void) return 0; } - /* Make sure we get initialised before anyone else tries to use us */ subsys_initcall(mpc52xx_gpio_init); -/* No exit call at the moment as we cannot unregister of gpio chips */ +static void __exit mpc52xx_gpio_exit(void) +{ + platform_driver_unregister(&mpc52xx_wkup_gpiochip_driver); + + platform_driver_unregister(&mpc52xx_simple_gpiochip_driver); +} +module_exit(mpc52xx_gpio_exit); MODULE_DESCRIPTION("Freescale MPC52xx gpio driver"); MODULE_AUTHOR("Sascha Hauer Date: Sun, 18 Jan 2015 12:39:27 +0100 Subject: gpio :gpio-mm-lantiq: Use devm_kzalloc Replace kzalloc with the device managed devm_kzalloc Cc: Alexandre Courbot Cc: John Crispin Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mm-lantiq.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index f228b1ce0ce0..789016397c4f 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -107,14 +107,13 @@ static int ltq_mm_probe(struct platform_device *pdev) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct ltq_mm *chip; const __be32 *shadow; - int ret = 0; if (!res) { dev_err(&pdev->dev, "failed to get memory resource\n"); return -ENOENT; } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -129,10 +128,7 @@ static int ltq_mm_probe(struct platform_device *pdev) if (shadow) chip->shadow = be32_to_cpu(*shadow); - ret = of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); - if (ret) - kfree(chip); - return ret; + return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); } static const struct of_device_id ltq_mm_match[] = { -- cgit v1.2.3-59-g8ed1b From f3f26c2f4b15b5b56ed87610403e4a98a13d6369 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sun, 18 Jan 2015 12:39:28 +0100 Subject: gpio: gpio-mm-lantiq: Do not replicate code Do not replicate code from of_mm_gpiochip_add. Cc: Alexandre Courbot Cc: John Crispin Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mm-lantiq.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index 789016397c4f..7d551610244b 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -104,21 +104,14 @@ static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc) static int ltq_mm_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct ltq_mm *chip; const __be32 *shadow; - if (!res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); - return -ENOENT; - } - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->mmchip.gc.ngpio = 16; - chip->mmchip.gc.label = "gpio-mm-ltq"; chip->mmchip.gc.direction_output = ltq_mm_dir_out; chip->mmchip.gc.set = ltq_mm_set; chip->mmchip.save_regs = ltq_mm_save_regs; -- cgit v1.2.3-59-g8ed1b From 68a99b187df3f4675f22a4a3f54c9d7645ab6409 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Mon, 19 Jan 2015 12:27:24 +0100 Subject: gpio: gpio-mm-lantiq: Use of_property_read_u32 Instead of parsing manually the shadow content, use the much simpler helper of_property_read_u32. Cc: Alexandre Courbot Cc: Grant Likely Cc: Rob Herring Cc: John Crispin Cc: devicetree@vger.kernel.org Cc: Mark Rutland Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mm-lantiq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index 7d551610244b..95ff180d261e 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -105,7 +105,7 @@ static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc) static int ltq_mm_probe(struct platform_device *pdev) { struct ltq_mm *chip; - const __be32 *shadow; + u32 shadow; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -117,9 +117,8 @@ static int ltq_mm_probe(struct platform_device *pdev) chip->mmchip.save_regs = ltq_mm_save_regs; /* store the shadow value if one was passed by the devicetree */ - shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); - if (shadow) - chip->shadow = be32_to_cpu(*shadow); + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow)) + chip->shadow = shadow; return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); } -- cgit v1.2.3-59-g8ed1b From da2382218c37fe7f8186c20b6b18aba477ec9b19 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sun, 18 Jan 2015 12:39:30 +0100 Subject: gpio: gpio-mm-lantiq: Use of_mm_gpiochip_remove Since d621e8bae5ac9c67 (Create of_mm_gpiochip_remove), there is a counterpart for of_mm_gpiochip_add. This patch implements the remove function of the driver making use of it. Cc: Alexandre Courbot Cc: John Crispin Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mm-lantiq.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index 95ff180d261e..f67ef2283d64 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -111,6 +111,8 @@ static int ltq_mm_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; + platform_set_drvdata(pdev, chip); + chip->mmchip.gc.ngpio = 16; chip->mmchip.gc.direction_output = ltq_mm_dir_out; chip->mmchip.gc.set = ltq_mm_set; @@ -123,6 +125,15 @@ static int ltq_mm_probe(struct platform_device *pdev) return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); } +static int ltq_mm_remove(struct platform_device *pdev) +{ + struct ltq_mm *chip = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; +} + static const struct of_device_id ltq_mm_match[] = { { .compatible = "lantiq,gpio-mm" }, {}, @@ -131,6 +142,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match); static struct platform_driver ltq_mm_driver = { .probe = ltq_mm_probe, + .remove = ltq_mm_remove, .driver = { .name = "gpio-mm-ltq", .of_match_table = ltq_mm_match, @@ -143,3 +155,9 @@ static int __init ltq_mm_init(void) } subsys_initcall(ltq_mm_init); + +static void __exit ltq_mm_exit(void) +{ + platform_driver_unregister(<q_mm_driver); +} +module_exit(ltq_mm_exit); -- cgit v1.2.3-59-g8ed1b From ff00be69fd95ea02b1274ea2ea1474727adeffd5 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sun, 18 Jan 2015 12:39:31 +0100 Subject: gpio: zevio: Use of_mm_gpiochip_remove Since d621e8bae5ac9c67 (Create of_mm_gpiochip_remove), there is a counterpart for of_mm_gpiochip_add. This patch implements the remove function of the driver making use of it. Cc: Alexandre Courbot Cc: Fabian Vogt Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-zevio.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index f769cd53f4e4..6f02d7c4cc57 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -181,6 +181,8 @@ static int zevio_gpio_probe(struct platform_device *pdev) if (!controller) return -ENOMEM; + platform_set_drvdata(pdev, controller); + /* Copy our reference */ controller->chip.gc = zevio_gpio_chip; controller->chip.gc.dev = &pdev->dev; @@ -202,6 +204,15 @@ static int zevio_gpio_probe(struct platform_device *pdev) return 0; } +static int zevio_gpio_remove(struct platform_device *pdev) +{ + struct zevio_gpio *controller = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&controller->chip); + + return 0; +} + static const struct of_device_id zevio_gpio_of_match[] = { { .compatible = "lsi,zevio-gpio", }, { }, @@ -215,6 +226,7 @@ static struct platform_driver zevio_gpio_driver = { .of_match_table = zevio_gpio_of_match, }, .probe = zevio_gpio_probe, + .remove = zevio_gpio_remove, }; module_platform_driver(zevio_gpio_driver); -- cgit v1.2.3-59-g8ed1b From 98686d9a52eeeab83a33fca5c19448954d109458 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sun, 18 Jan 2015 12:39:32 +0100 Subject: gpio: mpc8xxx: Convert to platform device interface. This way we do not need to transverse the device tree manually. Cc: Grant Likely Cc: Rob Herring Cc: devicetree@vger.kernel.org Acked-by: Peter Korsgaard Acked-by: Alexandre Courbot Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 48 +++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index d1ff879e6ff2..57eb794b6fc9 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -342,8 +343,9 @@ static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { {} }; -static void __init mpc8xxx_add_controller(struct device_node *np) +static int mpc8xxx_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; @@ -351,11 +353,9 @@ static void __init mpc8xxx_add_controller(struct device_node *np) unsigned hwirq; int ret; - mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); - if (!mpc8xxx_gc) { - ret = -ENOMEM; - goto err; - } + mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); + if (!mpc8xxx_gc) + return -ENOMEM; spin_lock_init(&mpc8xxx_gc->lock); @@ -375,16 +375,16 @@ static void __init mpc8xxx_add_controller(struct device_node *np) ret = of_mm_gpiochip_add(np, mm_gc); if (ret) - goto err; + return ret; hwirq = irq_of_parse_and_map(np, 0); if (hwirq == NO_IRQ) - goto skip_irq; + return 0; mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, &mpc8xxx_gpio_irq_ops, mpc8xxx_gc); if (!mpc8xxx_gc->irq) - goto skip_irq; + return 0; id = of_match_node(mpc8xxx_gpio_ids, np); if (id) @@ -397,24 +397,20 @@ static void __init mpc8xxx_add_controller(struct device_node *np) irq_set_handler_data(hwirq, mpc8xxx_gc); irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); -skip_irq: - return; - -err: - pr_err("%s: registration failed with status %d\n", - np->full_name, ret); - kfree(mpc8xxx_gc); - - return; + return 0; } -static int __init mpc8xxx_add_gpiochips(void) -{ - struct device_node *np; - - for_each_matching_node(np, mpc8xxx_gpio_ids) - mpc8xxx_add_controller(np); +static struct platform_driver mpc8xxx_plat_driver = { + .probe = mpc8xxx_probe, + .driver = { + .name = "gpio-mpc8xxx", + .of_match_table = mpc8xxx_gpio_ids, + }, +}; - return 0; +static int __init mpc8xxx_init(void) +{ + return platform_driver_register(&mpc8xxx_plat_driver); } -arch_initcall(mpc8xxx_add_gpiochips); + +arch_initcall(mpc8xxx_init); -- cgit v1.2.3-59-g8ed1b From 0da094d82c2741c58eb298d13386a95c7ab92dc7 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Mon, 19 Jan 2015 18:35:53 +0800 Subject: gpio: Add Fujitsu MB86S7x GPIO driver Driver for Fujitsu MB86S7x SoCs that have a memory mapped GPIO controller. Signed-off-by: Jassi Brar Signed-off-by: Andy Green Signed-off-by: Vincent Yang Signed-off-by: Tetsuya Nuriya Signed-off-by: Linus Walleij --- .../bindings/gpio/fujitsu,mb86s70-gpio.txt | 20 ++ drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-mb86s7x.c | 232 +++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt create mode 100644 drivers/gpio/gpio-mb86s7x.c (limited to 'drivers/gpio') diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt new file mode 100644 index 000000000000..bef353f370d8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt @@ -0,0 +1,20 @@ +Fujitsu MB86S7x GPIO Controller +------------------------------- + +Required properties: +- compatible: Should be "fujitsu,mb86s70-gpio" +- reg: Base address and length of register space +- clocks: Specify the clock +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be <2>. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted). + +Examples: + gpio0: gpio@31000000 { + compatible = "fujitsu,mb86s70-gpio"; + reg = <0 0x31000000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&clk 0 2 1>; + }; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 22b46567b3bb..ae5cb4d517c6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -197,6 +197,12 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_MB86S7X + bool "GPIO support for Fujitsu MB86S7x Platforms" + depends on ARCH_MB86S7X + help + Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs. + config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 3031b19f06ba..bdda6a94d2cd 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o +obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c new file mode 100644 index 000000000000..21b1ce5abdfe --- /dev/null +++ b/drivers/gpio/gpio-mb86s7x.c @@ -0,0 +1,232 @@ +/* + * linux/drivers/gpio/gpio-mb86s7x.c + * + * Copyright (C) 2015 Fujitsu Semiconductor Limited + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Only first 8bits of a register correspond to each pin, + * so there are 4 registers for 32 pins. + */ +#define PDR(x) (0x0 + x / 8 * 4) +#define DDR(x) (0x10 + x / 8 * 4) +#define PFR(x) (0x20 + x / 8 * 4) + +#define OFFSET(x) BIT((x) % 8) + +struct mb86s70_gpio_chip { + struct gpio_chip gc; + void __iomem *base; + struct clk *clk; + spinlock_t lock; +}; + +static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc) +{ + return container_of(gc, struct mb86s70_gpio_chip, gc); +} + +static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PFR(gpio)); + val &= ~OFFSET(gpio); + writel(val, gchip->base + PFR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PFR(gpio)); + val |= OFFSET(gpio); + writel(val, gchip->base + PFR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); +} + +static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + DDR(gpio)); + val &= ~OFFSET(gpio); + writel(val, gchip->base + DDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static int mb86s70_gpio_direction_output(struct gpio_chip *gc, + unsigned gpio, int value) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PDR(gpio)); + if (value) + val |= OFFSET(gpio); + else + val &= ~OFFSET(gpio); + writel(val, gchip->base + PDR(gpio)); + + val = readl(gchip->base + DDR(gpio)); + val |= OFFSET(gpio); + writel(val, gchip->base + DDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + + return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio)); +} + +static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PDR(gpio)); + if (value) + val |= OFFSET(gpio); + else + val &= ~OFFSET(gpio); + writel(val, gchip->base + PDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); +} + +static int mb86s70_gpio_probe(struct platform_device *pdev) +{ + struct mb86s70_gpio_chip *gchip; + struct resource *res; + int ret; + + gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); + if (gchip == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, gchip); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gchip->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gchip->base)) + return PTR_ERR(gchip->base); + + gchip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gchip->clk)) + return PTR_ERR(gchip->clk); + + clk_prepare_enable(gchip->clk); + + spin_lock_init(&gchip->lock); + + gchip->gc.direction_output = mb86s70_gpio_direction_output; + gchip->gc.direction_input = mb86s70_gpio_direction_input; + gchip->gc.request = mb86s70_gpio_request; + gchip->gc.free = mb86s70_gpio_free; + gchip->gc.get = mb86s70_gpio_get; + gchip->gc.set = mb86s70_gpio_set; + gchip->gc.label = dev_name(&pdev->dev); + gchip->gc.ngpio = 32; + gchip->gc.owner = THIS_MODULE; + gchip->gc.dev = &pdev->dev; + gchip->gc.base = -1; + + platform_set_drvdata(pdev, gchip); + + ret = gpiochip_add(&gchip->gc); + if (ret) { + dev_err(&pdev->dev, "couldn't register gpio driver\n"); + clk_disable_unprepare(gchip->clk); + } + + return ret; +} + +static int mb86s70_gpio_remove(struct platform_device *pdev) +{ + struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); + + gpiochip_remove(&gchip->gc); + clk_disable_unprepare(gchip->clk); + + return 0; +} + +static const struct of_device_id mb86s70_gpio_dt_ids[] = { + { .compatible = "fujitsu,mb86s70-gpio" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); + +static struct platform_driver mb86s70_gpio_driver = { + .driver = { + .name = "mb86s70-gpio", + .of_match_table = mb86s70_gpio_dt_ids, + }, + .probe = mb86s70_gpio_probe, + .remove = mb86s70_gpio_remove, +}; + +static int __init mb86s70_gpio_init(void) +{ + return platform_driver_register(&mb86s70_gpio_driver); +} +module_init(mb86s70_gpio_init); + +MODULE_DESCRIPTION("MB86S7x GPIO Driver"); +MODULE_ALIAS("platform:mb86s70-gpio"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 257e10752c13f2698d53e5df1744f4d7e41fdfa7 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sun, 18 Jan 2015 12:39:33 +0100 Subject: gpio: mpc8xxx: Use of_mm_gpiochip_remove Since d621e8bae5ac9c67 (Create of_mm_gpiochip_remove), there is a counterpart for of_mm_gpiochip_add. This patch implements the remove function of the driver making use of it. Cc: Linus Walleij Cc: Alexandre Courbot Cc: Peter Korsgaard Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 57eb794b6fc9..a6952ba343a8 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -40,6 +40,7 @@ struct mpc8xxx_gpio_chip { */ u32 data; struct irq_domain *irq; + unsigned int irqn; const void *of_dev_id_data; }; @@ -350,13 +351,14 @@ static int mpc8xxx_probe(struct platform_device *pdev) struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; const struct of_device_id *id; - unsigned hwirq; int ret; mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); if (!mpc8xxx_gc) return -ENOMEM; + platform_set_drvdata(pdev, mpc8xxx_gc); + spin_lock_init(&mpc8xxx_gc->lock); mm_gc = &mpc8xxx_gc->mm_gc; @@ -377,8 +379,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) if (ret) return ret; - hwirq = irq_of_parse_and_map(np, 0); - if (hwirq == NO_IRQ) + mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0); + if (mpc8xxx_gc->irqn == NO_IRQ) return 0; mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, @@ -394,14 +396,30 @@ static int mpc8xxx_probe(struct platform_device *pdev) out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); - irq_set_handler_data(hwirq, mpc8xxx_gc); - irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); + irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc); + irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade); + + return 0; +} + +static int mpc8xxx_remove(struct platform_device *pdev) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); + + if (mpc8xxx_gc->irq) { + irq_set_handler_data(mpc8xxx_gc->irqn, NULL); + irq_set_chained_handler(mpc8xxx_gc->irqn, NULL); + irq_domain_remove(mpc8xxx_gc->irq); + } + + of_mm_gpiochip_remove(&mpc8xxx_gc->mm_gc); return 0; } static struct platform_driver mpc8xxx_plat_driver = { .probe = mpc8xxx_probe, + .remove = mpc8xxx_remove, .driver = { .name = "gpio-mpc8xxx", .of_match_table = mpc8xxx_gpio_ids, -- cgit v1.2.3-59-g8ed1b From 16858cc5d9a65a0aa03b81214e234e33fbfbd64a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 22 Jan 2015 09:45:24 +0100 Subject: gpio: sx150x: fixup OF support Make OF conditional on CONFIG_OF_GPIO, rename and register the match table. Reported-by: Mike Krinkin Cc: Wei Chen Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sx150x.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index 88012e2b5b15..458d9d7952b8 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -152,12 +152,13 @@ static const struct i2c_device_id sx150x_id[] = { }; MODULE_DEVICE_TABLE(i2c, sx150x_id); -static const struct of_device_id sx150x_dt_id[] = { +static const struct of_device_id sx150x_of_match[] = { { .compatible = "semtech,sx1508q" }, { .compatible = "semtech,sx1509q" }, { .compatible = "semtech,sx1506q" }, {}, }; +MODULE_DEVICE_TABLE(of, sx150x_of_match); static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { @@ -484,8 +485,10 @@ static void sx150x_init_chip(struct sx150x_chip *chip, 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; @@ -681,7 +684,7 @@ static struct i2c_driver sx150x_driver = { .driver = { .name = "sx150x", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(sx150x_dt_id), + .of_match_table = of_match_ptr(sx150x_of_match), }, .probe = sx150x_probe, .remove = sx150x_remove, -- cgit v1.2.3-59-g8ed1b From ef3b2bd6f3c797d6672cf2739565752019458824 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Wed, 21 Jan 2015 21:35:37 +0100 Subject: gpio: correctly use const char * const On my previous patch I was overly hasty and made the suffixes string array const char const *suffixes, instaed of const char * const suffixes. This patch corrects that Signed-off-by: Olliver Schinagl Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9d2a37199806..c9266410d84c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1657,7 +1657,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - static const char const *suffixes[] = { "gpios", "gpio" }; + static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; -- cgit v1.2.3-59-g8ed1b From 74b18de94cfb7b7a12b581015e8e317d4fa5d752 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 21 Jan 2015 09:50:06 +0800 Subject: gpio: ge: Convert to use devm_kstrdup Use devm_kstrdup to simplify the error handling path. Also return -ENOMEM instead of 0 if devm_kstrdup fails. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ge.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 6ea930372028..f9ac3f351753 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -76,9 +76,12 @@ static int __init gef_gpio_probe(struct platform_device *pdev) } /* Setup pointers to chip functions */ - bgc->gc.label = kstrdup(pdev->dev.of_node->full_name, GFP_KERNEL); - if (!bgc->gc.label) + bgc->gc.label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name, + GFP_KERNEL); + if (!bgc->gc.label) { + ret = -ENOMEM; goto err0; + } bgc->gc.base = -1; bgc->gc.ngpio = (u16)(uintptr_t)of_id->data; @@ -88,11 +91,9 @@ static int __init gef_gpio_probe(struct platform_device *pdev) /* This function adds a memory mapped GPIO chip */ ret = gpiochip_add(&bgc->gc); if (ret) - goto err1; + goto err0; return 0; -err1: - kfree(bgc->gc.label); err0: iounmap(regs); pr_err("%s: GPIO chip registration failed\n", -- cgit v1.2.3-59-g8ed1b From 68d77d5168bdb922e0f100d0ee5e5e78aa0989af Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 21 Jan 2015 09:52:01 +0800 Subject: gpio: tz1090-pdc: Use resource_size to fix off-by-one resource size calculation Signed-off-by: Axel Lin Acked-by: James Hogan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tz1090-pdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c index d7536226b847..ede7e403ffde 100644 --- a/drivers/gpio/gpio-tz1090-pdc.c +++ b/drivers/gpio/gpio-tz1090-pdc.c @@ -190,7 +190,7 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev) /* Ioremap the registers */ priv->reg = devm_ioremap(&pdev->dev, res_regs->start, - res_regs->end - res_regs->start); + resource_size(res_regs)); if (!priv->reg) { dev_err(&pdev->dev, "unable to ioremap registers\n"); return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 920dfd824789b4058e91d26e2c6dd01a00ab28ec Mon Sep 17 00:00:00 2001 From: Chang Rebecca Swee Fun Date: Wed, 21 Jan 2015 18:32:21 +0800 Subject: gpio: sch: Consolidate similar algorithms Consolidating similar algorithms into common functions to make GPIO SCH simpler and manageable. Signed-off-by: Chang Rebecca Swee Fun Reviewed-by: Alexandre Courbot Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch.c | 83 +++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 54 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 0271022a66f6..b72906f5b999 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -41,7 +41,7 @@ struct sch_gpio { unsigned short resume_base; }; -#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip) +#define to_sch_gpio(gc) container_of(gc, struct sch_gpio, chip) static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio, unsigned reg) @@ -63,75 +63,59 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio) return gpio % 8; } -static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio) +static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg) { + struct sch_gpio *sch = to_sch_gpio(gc); unsigned short offset, bit; - u8 enable; - - spin_lock(&sch->lock); + u8 reg_val; - offset = sch_gpio_offset(sch, gpio, GEN); + offset = sch_gpio_offset(sch, gpio, reg); bit = sch_gpio_bit(sch, gpio); - enable = inb(sch->iobase + offset); - if (!(enable & (1 << bit))) - outb(enable | (1 << bit), sch->iobase + offset); + reg_val = !!(inb(sch->iobase + offset) & BIT(bit)); - spin_unlock(&sch->lock); + return reg_val; } -static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg, + int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_dirs; unsigned short offset, bit; + u8 reg_val; - spin_lock(&sch->lock); + offset = sch_gpio_offset(sch, gpio, reg); + bit = sch_gpio_bit(sch, gpio); - offset = sch_gpio_offset(sch, gpio_num, GIO); - bit = sch_gpio_bit(sch, gpio_num); + reg_val = inb(sch->iobase + offset); - curr_dirs = inb(sch->iobase + offset); + if (val) + outb(reg_val | BIT(bit), sch->iobase + offset); + else + outb((reg_val & ~BIT(bit)), sch->iobase + offset); +} - if (!(curr_dirs & (1 << bit))) - outb(curr_dirs | (1 << bit), sch->iobase + offset); +static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +{ + struct sch_gpio *sch = to_sch_gpio(gc); + spin_lock(&sch->lock); + sch_gpio_reg_set(gc, gpio_num, GIO, 1); spin_unlock(&sch->lock); return 0; } static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num) { - struct sch_gpio *sch = to_sch_gpio(gc); - int res; - unsigned short offset, bit; - - offset = sch_gpio_offset(sch, gpio_num, GLV); - bit = sch_gpio_bit(sch, gpio_num); - - res = !!(inb(sch->iobase + offset) & (1 << bit)); - - return res; + return sch_gpio_reg_get(gc, gpio_num, GLV); } static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_vals; - unsigned short offset, bit; spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GLV); - bit = sch_gpio_bit(sch, gpio_num); - - curr_vals = inb(sch->iobase + offset); - - if (val) - outb(curr_vals | (1 << bit), sch->iobase + offset); - else - outb((curr_vals & ~(1 << bit)), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GLV, val); spin_unlock(&sch->lock); } @@ -139,18 +123,9 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_dirs; - unsigned short offset, bit; spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GIO); - bit = sch_gpio_bit(sch, gpio_num); - - curr_dirs = inb(sch->iobase + offset); - if (curr_dirs & (1 << bit)) - outb(curr_dirs & ~(1 << bit), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GIO, 0); spin_unlock(&sch->lock); /* @@ -209,13 +184,13 @@ static int sch_gpio_probe(struct platform_device *pdev) * GPIO7 is configured by the CMC as SLPIOVR * Enable GPIO[9:8] core powered gpios explicitly */ - sch_gpio_enable(sch, 8); - sch_gpio_enable(sch, 9); + sch_gpio_reg_set(&sch->chip, 8, GEN, 1); + sch_gpio_reg_set(&sch->chip, 9, GEN, 1); /* * SUS_GPIO[2:0] enabled by default * Enable SUS_GPIO3 resume powered gpio explicitly */ - sch_gpio_enable(sch, 13); + sch_gpio_reg_set(&sch->chip, 13, GEN, 1); break; case PCI_DEVICE_ID_INTEL_ITC_LPC: -- cgit v1.2.3-59-g8ed1b From 161af6cd899508506ac5df101af7e569f28aa0e6 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Wed, 21 Jan 2015 17:17:49 +0000 Subject: gpio: max732x: add set_multiple function This adds a set_multiple function to the MAX732x GPIO driver, allowing for performance gains when using gpiod_set_array(). Signed-off-by: Mans Rullgard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 5fbab135f4a7..745698d977a5 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -212,10 +212,11 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) return reg_val & (1u << (off & 0x7)); } -static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask, + int val) { struct max732x_chip *chip; - uint8_t reg_out, mask = 1u << (off & 0x7); + uint8_t reg_out; int ret; chip = container_of(gc, struct max732x_chip, gpio_chip); @@ -223,7 +224,7 @@ static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) mutex_lock(&chip->lock); reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0]; - reg_out = (val) ? reg_out | mask : reg_out & ~mask; + reg_out = (reg_out & ~mask) | (val & mask); ret = max732x_writeb(chip, is_group_a(chip, off), reg_out); if (ret < 0) @@ -238,6 +239,26 @@ out: mutex_unlock(&chip->lock); } +static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +{ + unsigned base = off & ~0x7; + uint8_t mask = 1u << (off & 0x7); + + max732x_gpio_set_mask(gc, base, mask, val << (off & 0x7)); +} + +static void max732x_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + unsigned mask_lo = mask[0] & 0xff; + unsigned mask_hi = (mask[0] >> 8) & 0xff; + + if (mask_lo) + max732x_gpio_set_mask(gc, 0, mask_lo, bits[0] & 0xff); + if (mask_hi) + max732x_gpio_set_mask(gc, 8, mask_hi, (bits[0] >> 8) & 0xff); +} + static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct max732x_chip *chip; @@ -621,6 +642,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, if (chip->dir_output) { gc->direction_output = max732x_gpio_direction_output; gc->set = max732x_gpio_set_value; + gc->set_multiple = max732x_gpio_set_multiple; } gc->get = max732x_gpio_get_value; gc->can_sleep = true; -- cgit v1.2.3-59-g8ed1b From 9e089246a53cce0e14f04fb24de0e1bc62ec5400 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Wed, 21 Jan 2015 22:33:45 +0100 Subject: gpio: use sizeof() instead of hardcoded values gpiolib uses a fixed string for the suffixes and defines it at 32 bytes. Later in the code snprintf is used with this fixed value of 32. Using sizeof() is safer in case the size for the suffixes is ever changed. Signed-off-by: Olliver Schinagl Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c9266410d84c..bf6016d7a023 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1665,9 +1665,11 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, for (i = 0; i < ARRAY_SIZE(suffixes); i++) { if (con_id) - snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]); + snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, + suffixes[i]); else - snprintf(prop_name, 32, "%s", suffixes[i]); + snprintf(prop_name, sizeof(prop_name), "%s", + suffixes[i]); desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags); -- cgit v1.2.3-59-g8ed1b From 37fc8a92daf5e775a18790ccd935240ef72ddd83 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 30 Jan 2015 10:56:05 +0100 Subject: gpio: max732x: use an inline function for container cast Cast the struct gpio_chip into a max732x_chip using an inline macro and move the assignment to the variable declaration to save lines and simplify things. Cc: Semen Protsenko Acked-by: Mans Rullgard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 745698d977a5..a095b2393fe9 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -161,6 +161,11 @@ struct max732x_chip { #endif }; +static inline struct max732x_chip *to_max732x(struct gpio_chip *gc) +{ + return container_of(gc, struct max732x_chip, gpio_chip); +} + static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val) { struct i2c_client *client; @@ -199,12 +204,10 @@ static inline int is_group_a(struct max732x_chip *chip, unsigned off) static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); uint8_t reg_val; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - ret = max732x_readb(chip, is_group_a(chip, off), ®_val); if (ret < 0) return 0; @@ -215,12 +218,10 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask, int val) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); uint8_t reg_out; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - mutex_lock(&chip->lock); reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0]; @@ -261,11 +262,9 @@ static void max732x_gpio_set_multiple(struct gpio_chip *gc, static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_input) == 0) { dev_dbg(&chip->client->dev, "%s port %d is output only\n", chip->client->name, off); @@ -285,11 +284,9 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int max732x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_output) == 0) { dev_dbg(&chip->client->dev, "%s port %d is input only\n", chip->client->name, off); @@ -361,9 +358,7 @@ static void max732x_irq_update_mask(struct max732x_chip *chip) static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; - - chip = container_of(gc, struct max732x_chip, gpio_chip); + struct max732x_chip *chip = to_max732x(gc); if (chip->irq_domain) { return irq_create_mapping(chip->irq_domain, -- cgit v1.2.3-59-g8ed1b From ae4f4cfd8e9f6844c32a8913b8cb4f39ac9216ce Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Jan 2015 22:46:04 -0600 Subject: gpio: pxa: remove mach IRQ includes In preparation to enable ARCH_MMP on ARM64, the include of mach/irqs.h must be eliminated. mach/irqs.h was being included for IRQ_GPIO{0,1}, but these IRQs are always passed in as resources now. We can use irq0 and irq1 and get rid of IRQ_GPIOx. Get rid of the ifdef in the process as it is no longer needed. Signed-off-by: Rob Herring Cc: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index ad3feec0075e..b4fb8de374c8 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -27,8 +28,6 @@ #include #include -#include - /* * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with * one set of registers. The register offsets are organized below: @@ -629,19 +628,18 @@ static int pxa_gpio_probe(struct platform_device *pdev) } if (!use_of) { -#ifdef CONFIG_ARCH_PXA - irq = gpio_to_irq(0); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); - - irq = gpio_to_irq(1); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); -#endif + if (irq0 > 0) { + irq = gpio_to_irq(0); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + if (irq1 > 0) { + irq = gpio_to_irq(1); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } for (irq = gpio_to_irq(gpio_offset); irq <= gpio_to_irq(pxa_last_gpio); irq++) { @@ -649,13 +647,13 @@ static int pxa_gpio_probe(struct platform_device *pdev) handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - } else { - if (irq0 > 0) - irq_set_chained_handler(irq0, pxa_gpio_demux_handler); - if (irq1 > 0) - irq_set_chained_handler(irq1, pxa_gpio_demux_handler); } + if (irq0 > 0) + irq_set_chained_handler(irq0, pxa_gpio_demux_handler); + if (irq1 > 0) + irq_set_chained_handler(irq1, pxa_gpio_demux_handler); + irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler); return 0; } -- cgit v1.2.3-59-g8ed1b From 684bba2ff854c4a25727ee64f99b5bddcfa69777 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Jan 2015 22:46:06 -0600 Subject: gpio: pxa: add PXA1928 gpio type support Add support for PXA1928 GPIOs. The PXA1928 adds a 6th bank from previous generations. Signed-off-by: Jing Xiang Signed-off-by: Xiangzhan Meng [robh: ported to 3.19 from vendor kernel] Signed-off-by: Rob Herring Cc: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index b4fb8de374c8..2fdb04b6f101 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -41,9 +41,12 @@ * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 * + * BANK 6 - 0x0200 0x020C 0x0218 0x0224 0x0230 0x023C 0x0248 + * * NOTE: * BANK 3 is only available on PXA27x and later processors. - * BANK 4 and 5 are only available on PXA935 + * BANK 4 and 5 are only available on PXA935, PXA1928 + * BANK 6 is only available on PXA1928 */ #define GPLR_OFFSET 0x00 @@ -56,7 +59,8 @@ #define GAFR_OFFSET 0x54 #define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ -#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) +#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : ((n) > 5 ? 0x200 : 0x100) \ + + (((n) % 3) << 2)) int pxa_last_gpio; static int irq_base; @@ -92,6 +96,7 @@ enum pxa_gpio_type { PXA93X_GPIO, MMP_GPIO = 0x10, MMP2_GPIO, + PXA1928_GPIO, }; struct pxa_gpio_id { @@ -139,6 +144,11 @@ static struct pxa_gpio_id mmp2_id = { .gpio_nums = 192, }; +static struct pxa_gpio_id pxa1928_id = { + .type = PXA1928_GPIO, + .gpio_nums = 224, +}; + #define for_each_gpio_chip(i, c) \ for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) @@ -486,6 +496,7 @@ static int pxa_gpio_nums(struct platform_device *pdev) case PXA93X_GPIO: case MMP_GPIO: case MMP2_GPIO: + case PXA1928_GPIO: gpio_type = pxa_id->type; count = pxa_id->gpio_nums - 1; break; @@ -505,6 +516,7 @@ static const struct of_device_id pxa_gpio_dt_ids[] = { { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, }, { .compatible = "marvell,mmp-gpio", .data = &mmp_id, }, { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, }, + { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, }, {} }; @@ -666,6 +678,7 @@ static const struct platform_device_id gpio_id_table[] = { { "pxa93x-gpio", (unsigned long)&pxa93x_id }, { "mmp-gpio", (unsigned long)&mmp_id }, { "mmp2-gpio", (unsigned long)&mmp2_id }, + { "pxa1928-gpio", (unsigned long)&pxa1928_id }, { }, }; -- cgit v1.2.3-59-g8ed1b From 0a4a3529df40c4be163b3909942b16c6c46b9d03 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Sat, 31 Jan 2015 21:47:40 +0800 Subject: gpio: kconfig: replace PPC_OF with PPC The PPC_OF is a ppc specific option which is used to mean that the firmware device tree access functions are available. Since all the ppc platforms have a device tree, it is aways set to 'y' for ppc. So it makes no sense to keep a such option in the current kernel. Replace it with PPC. Signed-off-by: Kevin Hao 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 ae5cb4d517c6..c1e2ca3d9a51 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -383,7 +383,7 @@ config GPIO_XGENE_SB config GPIO_XILINX tristate "Xilinx GPIO support" - depends on OF_GPIO && (PPC_OF || MICROBLAZE || ARCH_ZYNQ || X86) + depends on OF_GPIO && (PPC || MICROBLAZE || ARCH_ZYNQ || X86) help Say yes here to support the Xilinx FPGA GPIO device -- cgit v1.2.3-59-g8ed1b