From 9caf1f2202da2affedf0c9e3c1ccda8ea6d353e1 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Jun 2013 15:27:43 +0100 Subject: gpio-tz1090: add TZ1090 gpio driver Add a GPIO driver for the main GPIOs found in the TZ1090 (Comet) SoC. This doesn't include low-power GPIOs as they're controlled separately via the Powerdown Controller (PDC) registers. The driver is instantiated by device tree and supports interrupts for all GPIOs. Changes in v4: - fix typos in DT bindings compatible properties - reference Documentation/devicetree/bindings/gpio/gpio.txt in gpio-ranges description in DT bindings - fix gpio-ranges examples in DT bindings (it must now have 3 cells) - gpio-tz1090: use of_property_read_u32 instead of of_get_property Changes in v3: - separated from irq-imgpdc and removed arch/metag changes to allow these patches to go upstream separately via the pinctrl[/gpio] trees (particularly the pinctrl drivers depend on the new pinconf DT bindings). - some s/unsigned/unsigned int/. - some s/unsigned int/bool/ and use of BIT(). - gpio-tz1090*: refer to and flags in bindings. - gpio-tz1090*: move initcall from postcore to subsys. - gpio-tz1090: add REG_ prefix to some constants for consistency. - gpio-tz1090: add comment to explain tz1090_gpio_irq_next_edge cunningness. Changes in v2: - gpio-tz1090: remove references to Linux flags in dt bindings - gpio-tz1090: make use of BIT() from linux/bitops.h - gpio-tz1090: make register accessors inline to match pinctrl - gpio-tz1090: update gpio-ranges to use 3 cells after recent ABI breakage Signed-off-by: James Hogan Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: Linus Walleij Cc: linux-doc@vger.kernel.org Cc: devicetree-discuss@lists.ozlabs.org Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-tz1090.c | 633 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 641 insertions(+) create mode 100644 drivers/gpio/gpio-tz1090.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b2450ba14138..e9761641f149 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -242,6 +242,13 @@ config GPIO_TS5500 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 LCD port. +config GPIO_TZ1090 + bool "Toumaz Xenif TZ1090 GPIO support" + depends on SOC_TZ1090 + default y + help + Say yes here to support Toumaz Xenif TZ1090 GPIOs. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ef3e983a2f1e..2baf456392f9 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o +obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c new file mode 100644 index 000000000000..b725a6bef3e1 --- /dev/null +++ b/drivers/gpio/gpio-tz1090.c @@ -0,0 +1,633 @@ +/* + * Toumaz Xenif TZ1090 GPIO handling. + * + * Copyright (C) 2008-2013 Imagination Technologies Ltd. + * + * Based on ARM PXA code and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offsets from bank base address */ +#define REG_GPIO_DIR 0x00 +#define REG_GPIO_IRQ_PLRT 0x20 +#define REG_GPIO_IRQ_TYPE 0x30 +#define REG_GPIO_IRQ_EN 0x40 +#define REG_GPIO_IRQ_STS 0x50 +#define REG_GPIO_BIT_EN 0x60 +#define REG_GPIO_DIN 0x70 +#define REG_GPIO_DOUT 0x80 + +/* REG_GPIO_IRQ_PLRT */ +#define REG_GPIO_IRQ_PLRT_LOW 0 +#define REG_GPIO_IRQ_PLRT_HIGH 1 + +/* REG_GPIO_IRQ_TYPE */ +#define REG_GPIO_IRQ_TYPE_LEVEL 0 +#define REG_GPIO_IRQ_TYPE_EDGE 1 + +/** + * struct tz1090_gpio_bank - GPIO bank private data + * @chip: Generic GPIO chip for GPIO bank + * @domain: IRQ domain for GPIO bank (may be NULL) + * @reg: Base of registers, offset for this GPIO bank + * @irq: IRQ number for GPIO bank + * @label: Debug GPIO bank label, used for storage of chip->label + * + * This is the main private data for a GPIO bank. It encapsulates a gpio_chip, + * and the callbacks for the gpio_chip can access the private data with the + * to_bank() macro below. + */ +struct tz1090_gpio_bank { + struct gpio_chip chip; + struct irq_domain *domain; + void __iomem *reg; + int irq; + char label[16]; +}; +#define to_bank(c) container_of(c, struct tz1090_gpio_bank, chip) + +/** + * struct tz1090_gpio - Overall GPIO device private data + * @dev: Device (from platform device) + * @reg: Base of GPIO registers + * + * Represents the overall GPIO device. This structure is actually only + * temporary, and used during init. + */ +struct tz1090_gpio { + struct device *dev; + void __iomem *reg; +}; + +/** + * struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank + * @priv: Overall GPIO device private data + * @node: Device tree node specific to this GPIO bank + * @index: Index of bank in range 0-2 + */ +struct tz1090_gpio_bank_info { + struct tz1090_gpio *priv; + struct device_node *node; + unsigned int index; +}; + +/* Convenience register accessors */ +static inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, u32 data) +{ + iowrite32(data, bank->reg + reg_offs); +} + +static inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank, + unsigned int reg_offs) +{ + return ioread32(bank->reg + reg_offs); +} + +/* caller must hold LOCK2 */ +static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + u32 value; + + value = tz1090_gpio_read(bank, reg_offs); + value &= ~BIT(offset); + tz1090_gpio_write(bank, reg_offs, value); +} + +static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_clear_bit(bank, reg_offs, offset); + __global_unlock2(lstat); +} + +/* caller must hold LOCK2 */ +static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + u32 value; + + value = tz1090_gpio_read(bank, reg_offs); + value |= BIT(offset); + tz1090_gpio_write(bank, reg_offs, value); +} + +static void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_set_bit(bank, reg_offs, offset); + __global_unlock2(lstat); +} + +/* caller must hold LOCK2 */ +static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset, + bool val) +{ + u32 value; + + value = tz1090_gpio_read(bank, reg_offs); + value &= ~BIT(offset); + if (val) + value |= BIT(offset); + tz1090_gpio_write(bank, reg_offs, value); +} + +static void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset, + bool val) +{ + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_mod_bit(bank, reg_offs, offset, val); + __global_unlock2(lstat); +} + +static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + return tz1090_gpio_read(bank, reg_offs) & BIT(offset); +} + +/* GPIO chip callbacks */ + +static int tz1090_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset); + + return 0; +} + +static int tz1090_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int output_value) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value); + _tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset); + __global_unlock2(lstat); + + return 0; +} + +/* + * Return GPIO level + */ +static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset); +} + +/* + * Set output GPIO level + */ +static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset, + int output_value) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value); +} + +static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + int ret; + + ret = pinctrl_request_gpio(chip->base + offset); + if (ret) + return ret; + + tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset); + tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset); + + return 0; +} + +static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + pinctrl_free_gpio(chip->base + offset); + + tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset); +} + +static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + if (!bank->domain) + return -EINVAL; + + return irq_create_mapping(bank->domain, offset); +} + +/* IRQ chip handlers */ + +/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */ +static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data) +{ + return (struct tz1090_gpio_bank *)data->domain->host_data; +} + +static void tz1090_gpio_irq_clear(struct tz1090_gpio_bank *bank, + unsigned int offset) +{ + tz1090_gpio_clear_bit(bank, REG_GPIO_IRQ_STS, offset); +} + +static void tz1090_gpio_irq_enable(struct tz1090_gpio_bank *bank, + unsigned int offset, bool enable) +{ + tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_EN, offset, enable); +} + +static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank, + unsigned int offset, unsigned int polarity) +{ + tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity); +} + +static int tz1090_gpio_valid_handler(struct irq_desc *desc) +{ + return desc->handle_irq == handle_level_irq || + desc->handle_irq == handle_edge_irq; +} + +static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank, + unsigned int offset, unsigned int type) +{ + tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type); +} + +/* set polarity to trigger on next edge, whether rising or falling */ +static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank, + unsigned int offset) +{ + unsigned int value_p, value_i; + int lstat; + + /* + * Set the GPIO's interrupt polarity to the opposite of the current + * input value so that the next edge triggers an interrupt. + */ + __global_lock2(lstat); + value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN); + value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT); + value_p &= ~BIT(offset); + value_p |= value_i & BIT(offset); + tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p); + __global_unlock2(lstat); +} + +static void gpio_ack_irq(struct irq_data *data) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + + tz1090_gpio_irq_clear(bank, data->hwirq); +} + +static void gpio_mask_irq(struct irq_data *data) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + + tz1090_gpio_irq_enable(bank, data->hwirq, false); +} + +static void gpio_unmask_irq(struct irq_data *data) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + + tz1090_gpio_irq_enable(bank, data->hwirq, true); +} + +static unsigned int gpio_startup_irq(struct irq_data *data) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + irq_hw_number_t hw = data->hwirq; + struct irq_desc *desc = irq_to_desc(data->irq); + + /* + * This warning indicates that the type of the irq hasn't been set + * before enabling the irq. This would normally be done by passing some + * trigger flags to request_irq(). + */ + WARN(!tz1090_gpio_valid_handler(desc), + "irq type not set before enabling gpio irq %d", data->irq); + + tz1090_gpio_irq_clear(bank, hw); + tz1090_gpio_irq_enable(bank, hw, true); + return 0; +} + +static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + unsigned int type; + unsigned int polarity; + + switch (flow_type) { + case IRQ_TYPE_EDGE_BOTH: + type = REG_GPIO_IRQ_TYPE_EDGE; + polarity = REG_GPIO_IRQ_PLRT_LOW; + break; + case IRQ_TYPE_EDGE_RISING: + type = REG_GPIO_IRQ_TYPE_EDGE; + polarity = REG_GPIO_IRQ_PLRT_HIGH; + break; + case IRQ_TYPE_EDGE_FALLING: + type = REG_GPIO_IRQ_TYPE_EDGE; + polarity = REG_GPIO_IRQ_PLRT_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + type = REG_GPIO_IRQ_TYPE_LEVEL; + polarity = REG_GPIO_IRQ_PLRT_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + type = REG_GPIO_IRQ_TYPE_LEVEL; + polarity = REG_GPIO_IRQ_PLRT_LOW; + break; + default: + return -EINVAL; + } + + tz1090_gpio_irq_type(bank, data->hwirq, type); + if (type == REG_GPIO_IRQ_TYPE_LEVEL) + __irq_set_handler_locked(data->irq, handle_level_irq); + else + __irq_set_handler_locked(data->irq, handle_edge_irq); + + if (flow_type == IRQ_TYPE_EDGE_BOTH) + tz1090_gpio_irq_next_edge(bank, data->hwirq); + else + tz1090_gpio_irq_polarity(bank, data->hwirq, polarity); + + return 0; +} + +#ifdef CONFIG_SUSPEND +static int gpio_set_irq_wake(struct irq_data *data, unsigned int on) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + +#ifdef CONFIG_PM_DEBUG + pr_info("irq_wake irq%d state:%d\n", data->irq, on); +#endif + + /* wake on gpio block interrupt */ + return irq_set_irq_wake(bank->irq, on); +} +#else +#define gpio_set_irq_wake NULL +#endif + +/* gpio virtual interrupt functions */ +static struct irq_chip gpio_irq_chip = { + .irq_startup = gpio_startup_irq, + .irq_ack = gpio_ack_irq, + .irq_mask = gpio_mask_irq, + .irq_unmask = gpio_unmask_irq, + .irq_set_type = gpio_set_irq_type, + .irq_set_wake = gpio_set_irq_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, +}; + +static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + irq_hw_number_t hw; + unsigned int irq_stat, irq_no; + struct tz1090_gpio_bank *bank; + struct irq_desc *child_desc; + + bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc); + irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) & + tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) & + tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) & + 0x3FFFFFFF; /* 30 bits only */ + + for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) { + if (!(irq_stat & 1)) + continue; + + irq_no = irq_linear_revmap(bank->domain, hw); + child_desc = irq_to_desc(irq_no); + + /* Toggle edge for pin with both edges triggering enabled */ + if (irqd_get_trigger_type(&child_desc->irq_data) + == IRQ_TYPE_EDGE_BOTH) + tz1090_gpio_irq_next_edge(bank, hw); + + BUG_ON(!tz1090_gpio_valid_handler(child_desc)); + generic_handle_irq_desc(irq_no, child_desc); + } +} + +static int tz1090_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + irq_set_chip(irq, &gpio_irq_chip); + return 0; +} + +static const struct irq_domain_ops tz1090_gpio_irq_domain_ops = { + .map = tz1090_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) +{ + struct device_node *np = info->node; + struct device *dev = info->priv->dev; + struct tz1090_gpio_bank *bank; + + bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); + if (!bank) { + dev_err(dev, "unable to allocate driver data\n"); + return -ENOMEM; + } + + /* Offset the main registers to the first register in this bank */ + bank->reg = info->priv->reg + info->index * 4; + + /* Set up GPIO chip */ + snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u", + info->index); + bank->chip.label = bank->label; + bank->chip.dev = dev; + bank->chip.direction_input = tz1090_gpio_direction_input; + bank->chip.direction_output = tz1090_gpio_direction_output; + bank->chip.get = tz1090_gpio_get; + bank->chip.set = tz1090_gpio_set; + bank->chip.free = tz1090_gpio_free; + bank->chip.request = tz1090_gpio_request; + bank->chip.to_irq = tz1090_gpio_to_irq; + bank->chip.of_node = np; + + /* GPIO numbering from 0 */ + bank->chip.base = info->index * 30; + bank->chip.ngpio = 30; + + /* Add the GPIO bank */ + gpiochip_add(&bank->chip); + + /* Get the GPIO bank IRQ if provided */ + bank->irq = irq_of_parse_and_map(np, 0); + + /* The interrupt is optional (it may be used by another core on chip) */ + if (bank->irq < 0) { + dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n", + info->index); + return 0; + } + + dev_info(dev, "Setting up IRQs for GPIO bank %u\n", + info->index); + + /* + * Initialise all interrupts to disabled so we don't get + * spurious ones on a dirty boot and hit the BUG_ON in the + * handler. + */ + tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0); + + /* Add a virtual IRQ for each GPIO */ + bank->domain = irq_domain_add_linear(np, + bank->chip.ngpio, + &tz1090_gpio_irq_domain_ops, + bank); + + /* Setup chained handler for this GPIO bank */ + irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler); + + return 0; +} + +static void tz1090_gpio_register_banks(struct tz1090_gpio *priv) +{ + struct device_node *np = priv->dev->of_node; + struct device_node *node; + + for_each_available_child_of_node(np, node) { + struct tz1090_gpio_bank_info info; + u32 addr; + int ret; + + ret = of_property_read_u32(node, "reg", &addr); + if (ret) { + dev_err(priv->dev, "invalid reg on %s\n", + node->full_name); + continue; + } + if (addr >= 3) { + dev_err(priv->dev, "index %u in %s out of range\n", + addr, node->full_name); + continue; + } + + info.index = addr; + info.node = of_node_get(node); + info.priv = priv; + + ret = tz1090_gpio_bank_probe(&info); + if (ret) { + dev_err(priv->dev, "failure registering %s\n", + node->full_name); + of_node_put(node); + continue; + } + } +} + +static int tz1090_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res_regs; + struct tz1090_gpio priv; + + if (!np) { + dev_err(&pdev->dev, "must be instantiated via devicetree\n"); + return -ENOENT; + } + + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_regs) { + dev_err(&pdev->dev, "cannot find registers resource\n"); + return -ENOENT; + } + + priv.dev = &pdev->dev; + + /* Ioremap the registers */ + priv.reg = devm_ioremap(&pdev->dev, res_regs->start, + res_regs->end - res_regs->start); + if (!priv.reg) { + dev_err(&pdev->dev, "unable to ioremap registers\n"); + return -ENOMEM; + } + + /* Look for banks */ + tz1090_gpio_register_banks(&priv); + + return 0; +} + +static struct of_device_id tz1090_gpio_of_match[] = { + { .compatible = "img,tz1090-gpio" }, + { }, +}; + +static struct platform_driver tz1090_gpio_driver = { + .driver = { + .name = "tz1090-gpio", + .owner = THIS_MODULE, + .of_match_table = tz1090_gpio_of_match, + }, + .probe = tz1090_gpio_probe, +}; + +static int __init tz1090_gpio_init(void) +{ + return platform_driver_register(&tz1090_gpio_driver); +} +subsys_initcall(tz1090_gpio_init); -- cgit v1.2.3 From 79bb6460012c7c9f40aeb7b7d5f28aaac4455912 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Jun 2013 15:27:44 +0100 Subject: gpio-tz1090-pdc: add TZ1090 PDC gpio driver Add a GPIO driver for the low-power Powerdown Controller GPIOs in the TZ1090 SoC. The driver is instantiated by device tree and supports interrupts for the SysWake GPIOs only. Changes in v4: - fix typos in DT bindings compatible properties - reference Documentation/devicetree/bindings/gpio/gpio.txt in gpio-ranges description in DT bindings - fix gpio-ranges examples in DT bindings (it must now have 3 cells) Changes in v3: - separated from irq-imgpdc and removed arch/metag changes to allow these patches to go upstream separately via the pinctrl[/gpio] trees (particularly the pinctrl drivers depend on the new pinconf DT bindings). - some s/unsigned/unsigned int/. - gpio-tz1090*: refer to and flags in bindings. - gpio-tz1090*: move initcall from postcore to subsys. Changes in v2: - gpio-tz1090-pdc: remove references to Linux flags in dt bindings - gpio-tz1090-pdc: make use of BIT() from linux/bitops.h - gpio-tz1090-pdc: make register accessors inline to match pinctrl - gpio-tz1090-pdc: update gpio-ranges to use 3 cells after recent ABI breakage Signed-off-by: James Hogan Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: Linus Walleij Cc: linux-doc@vger.kernel.org Cc: devicetree-discuss@lists.ozlabs.org Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 7 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-tz1090-pdc.c | 243 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 drivers/gpio/gpio-tz1090-pdc.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e9761641f149..4e44cdcf3612 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -249,6 +249,13 @@ config GPIO_TZ1090 help Say yes here to support Toumaz Xenif TZ1090 GPIOs. +config GPIO_TZ1090_PDC + bool "Toumaz Xenif TZ1090 PDC GPIO support" + depends on SOC_TZ1090 + default y + help + Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2baf456392f9..fa97bf8698ed 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o +obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c new file mode 100644 index 000000000000..f512da299b3d --- /dev/null +++ b/drivers/gpio/gpio-tz1090-pdc.c @@ -0,0 +1,243 @@ +/* + * Toumaz Xenif TZ1090 PDC GPIO handling. + * + * Copyright (C) 2012-2013 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offsets from SOC_GPIO_CONTROL0 */ +#define REG_SOC_GPIO_CONTROL0 0x00 +#define REG_SOC_GPIO_CONTROL1 0x04 +#define REG_SOC_GPIO_CONTROL2 0x08 +#define REG_SOC_GPIO_CONTROL3 0x0c +#define REG_SOC_GPIO_STATUS 0x80 + +/* PDC GPIOs go after normal GPIOs */ +#define GPIO_PDC_BASE 90 +#define GPIO_PDC_NGPIO 7 + +/* Out of PDC gpios, only syswakes have irqs */ +#define GPIO_PDC_IRQ_FIRST 2 +#define GPIO_PDC_NIRQ 3 + +/** + * struct tz1090_pdc_gpio - GPIO bank private data + * @chip: Generic GPIO chip for GPIO bank + * @reg: Base of registers, offset for this GPIO bank + * @irq: IRQ numbers for Syswake GPIOs + * + * This is the main private data for the PDC GPIO driver. It encapsulates a + * gpio_chip, and the callbacks for the gpio_chip can access the private data + * with the to_pdc() macro below. + */ +struct tz1090_pdc_gpio { + struct gpio_chip chip; + void __iomem *reg; + int irq[GPIO_PDC_NIRQ]; +}; +#define to_pdc(c) container_of(c, struct tz1090_pdc_gpio, chip) + +/* Register accesses into the PDC MMIO area */ + +static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs, + unsigned int data) +{ + writel(data, priv->reg + reg_offs); +} + +static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv, + unsigned int reg_offs) +{ + return readl(priv->reg + reg_offs); +} + +/* Generic GPIO interface */ + +static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + u32 value; + int lstat; + + __global_lock2(lstat); + value = pdc_read(priv, REG_SOC_GPIO_CONTROL1); + value |= BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL1, value); + __global_unlock2(lstat); + + return 0; +} + +static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, + int output_value) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + u32 value; + int lstat; + + __global_lock2(lstat); + /* EXT_POWER doesn't seem to have an output value bit */ + if (offset < 6) { + value = pdc_read(priv, REG_SOC_GPIO_CONTROL0); + if (output_value) + value |= BIT(offset); + else + value &= ~BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL0, value); + } + + value = pdc_read(priv, REG_SOC_GPIO_CONTROL1); + value &= ~BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL1, value); + __global_unlock2(lstat); + + return 0; +} + +static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset); +} + +static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset, + int output_value) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + u32 value; + int lstat; + + /* EXT_POWER doesn't seem to have an output value bit */ + if (offset >= 6) + return; + + __global_lock2(lstat); + value = pdc_read(priv, REG_SOC_GPIO_CONTROL0); + if (output_value) + value |= BIT(offset); + else + value &= ~BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL0, value); + __global_unlock2(lstat); +} + +static int tz1090_pdc_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void tz1090_pdc_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST; + int irq; + + /* only syswakes have irqs */ + if (syswake >= GPIO_PDC_NIRQ) + return -EINVAL; + + irq = priv->irq[syswake]; + if (!irq) + return -EINVAL; + + return irq; +} + +static int tz1090_pdc_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res_regs; + struct tz1090_pdc_gpio *priv; + unsigned int i; + + if (!np) { + dev_err(&pdev->dev, "must be instantiated via devicetree\n"); + return -ENOENT; + } + + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_regs) { + dev_err(&pdev->dev, "cannot find registers resource\n"); + return -ENOENT; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate driver data\n"); + return -ENOMEM; + } + + /* Ioremap the registers */ + priv->reg = devm_ioremap(&pdev->dev, res_regs->start, + res_regs->end - res_regs->start); + if (!priv->reg) { + dev_err(&pdev->dev, "unable to ioremap registers\n"); + return -ENOMEM; + } + + /* Set up GPIO chip */ + priv->chip.label = "tz1090-pdc-gpio"; + priv->chip.dev = &pdev->dev; + priv->chip.direction_input = tz1090_pdc_gpio_direction_input; + priv->chip.direction_output = tz1090_pdc_gpio_direction_output; + priv->chip.get = tz1090_pdc_gpio_get; + priv->chip.set = tz1090_pdc_gpio_set; + priv->chip.free = tz1090_pdc_gpio_free; + priv->chip.request = tz1090_pdc_gpio_request; + priv->chip.to_irq = tz1090_pdc_gpio_to_irq; + priv->chip.of_node = np; + + /* GPIO numbering */ + priv->chip.base = GPIO_PDC_BASE; + priv->chip.ngpio = GPIO_PDC_NGPIO; + + /* Map the syswake irqs */ + for (i = 0; i < GPIO_PDC_NIRQ; ++i) + priv->irq[i] = irq_of_parse_and_map(np, i); + + /* Add the GPIO bank */ + gpiochip_add(&priv->chip); + + return 0; +} + +static struct of_device_id tz1090_pdc_gpio_of_match[] = { + { .compatible = "img,tz1090-pdc-gpio" }, + { }, +}; + +static struct platform_driver tz1090_pdc_gpio_driver = { + .driver = { + .name = "tz1090-pdc-gpio", + .owner = THIS_MODULE, + .of_match_table = tz1090_pdc_gpio_of_match, + }, + .probe = tz1090_pdc_gpio_probe, +}; + +static int __init tz1090_pdc_gpio_init(void) +{ + return platform_driver_register(&tz1090_pdc_gpio_driver); +} +subsys_initcall(tz1090_pdc_gpio_init); -- cgit v1.2.3 From 04777396d8d183f3f3edd3872eb8bf50dd458b82 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Jun 2013 15:27:45 +0100 Subject: gpio-tz1090: convert to use generic irqchip Convert gpio-tz1090 driver to use generic irqchips. This allows the irq_ack, irq_mask, and irq_unmask callbacks and associated helper functions to be removed. Also switch to using irq_setup_alt_chip() in the irq_set_type callback instead of using __irq_set_handler_locked(). Signed-off-by: James Hogan Cc: Linus Walleij Cc: Grant Likely Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-tz1090.c | 123 ++++++++++++++++++--------------------------- 2 files changed, 49 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4e44cdcf3612..02db4eafa9df 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -245,6 +245,7 @@ config GPIO_TS5500 config GPIO_TZ1090 bool "Toumaz Xenif TZ1090 GPIO support" depends on SOC_TZ1090 + select GENERIC_IRQ_CHIP default y help Say yes here to support Toumaz Xenif TZ1090 GPIOs. diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index b725a6bef3e1..23e061392411 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -270,30 +270,12 @@ static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data) return (struct tz1090_gpio_bank *)data->domain->host_data; } -static void tz1090_gpio_irq_clear(struct tz1090_gpio_bank *bank, - unsigned int offset) -{ - tz1090_gpio_clear_bit(bank, REG_GPIO_IRQ_STS, offset); -} - -static void tz1090_gpio_irq_enable(struct tz1090_gpio_bank *bank, - unsigned int offset, bool enable) -{ - tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_EN, offset, enable); -} - static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank, unsigned int offset, unsigned int polarity) { tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity); } -static int tz1090_gpio_valid_handler(struct irq_desc *desc) -{ - return desc->handle_irq == handle_level_irq || - desc->handle_irq == handle_edge_irq; -} - static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank, unsigned int offset, unsigned int type) { @@ -320,43 +302,18 @@ static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank, __global_unlock2(lstat); } -static void gpio_ack_irq(struct irq_data *data) -{ - struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); - - tz1090_gpio_irq_clear(bank, data->hwirq); -} - -static void gpio_mask_irq(struct irq_data *data) -{ - struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); - - tz1090_gpio_irq_enable(bank, data->hwirq, false); -} - -static void gpio_unmask_irq(struct irq_data *data) -{ - struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); - - tz1090_gpio_irq_enable(bank, data->hwirq, true); -} - static unsigned int gpio_startup_irq(struct irq_data *data) { - struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); - irq_hw_number_t hw = data->hwirq; - struct irq_desc *desc = irq_to_desc(data->irq); - /* * This warning indicates that the type of the irq hasn't been set * before enabling the irq. This would normally be done by passing some * trigger flags to request_irq(). */ - WARN(!tz1090_gpio_valid_handler(desc), + WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE, "irq type not set before enabling gpio irq %d", data->irq); - tz1090_gpio_irq_clear(bank, hw); - tz1090_gpio_irq_enable(bank, hw, true); + irq_gc_ack_clr_bit(data); + irq_gc_mask_set_bit(data); return 0; } @@ -392,10 +349,7 @@ static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type) } tz1090_gpio_irq_type(bank, data->hwirq, type); - if (type == REG_GPIO_IRQ_TYPE_LEVEL) - __irq_set_handler_locked(data->irq, handle_level_irq); - else - __irq_set_handler_locked(data->irq, handle_edge_irq); + irq_setup_alt_chip(data, flow_type); if (flow_type == IRQ_TYPE_EDGE_BOTH) tz1090_gpio_irq_next_edge(bank, data->hwirq); @@ -421,17 +375,6 @@ static int gpio_set_irq_wake(struct irq_data *data, unsigned int on) #define gpio_set_irq_wake NULL #endif -/* gpio virtual interrupt functions */ -static struct irq_chip gpio_irq_chip = { - .irq_startup = gpio_startup_irq, - .irq_ack = gpio_ack_irq, - .irq_mask = gpio_mask_irq, - .irq_unmask = gpio_unmask_irq, - .irq_set_type = gpio_set_irq_type, - .irq_set_wake = gpio_set_irq_wake, - .flags = IRQCHIP_MASK_ON_SUSPEND, -}; - static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { irq_hw_number_t hw; @@ -457,28 +400,17 @@ static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) == IRQ_TYPE_EDGE_BOTH) tz1090_gpio_irq_next_edge(bank, hw); - BUG_ON(!tz1090_gpio_valid_handler(child_desc)); generic_handle_irq_desc(irq_no, child_desc); } } -static int tz1090_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hw) -{ - irq_set_chip(irq, &gpio_irq_chip); - return 0; -} - -static const struct irq_domain_ops tz1090_gpio_irq_domain_ops = { - .map = tz1090_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) { struct device_node *np = info->node; struct device *dev = info->priv->dev; struct tz1090_gpio_bank *bank; + struct irq_chip_generic *gc; + int err; bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); if (!bank) { @@ -533,9 +465,50 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) /* Add a virtual IRQ for each GPIO */ bank->domain = irq_domain_add_linear(np, bank->chip.ngpio, - &tz1090_gpio_irq_domain_ops, + &irq_generic_chip_ops, bank); + /* Set up a generic irq chip with 2 chip types (level and edge) */ + err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2, + bank->label, handle_bad_irq, 0, 0, + IRQ_GC_INIT_NESTED_LOCK); + if (err) { + dev_info(dev, + "irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n", + info->index); + irq_domain_remove(bank->domain); + return 0; + } + + gc = irq_get_domain_generic_chip(bank->domain, 0); + gc->reg_base = bank->reg; + + /* level chip type */ + gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; + gc->chip_types[0].handler = handle_level_irq; + gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; + gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; + gc->chip_types[0].chip.irq_startup = gpio_startup_irq, + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit, + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit, + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit, + gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type, + gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake, + gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + + /* edge chip type */ + gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; + gc->chip_types[1].handler = handle_edge_irq; + gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; + gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; + gc->chip_types[1].chip.irq_startup = gpio_startup_irq, + gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit, + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit, + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit, + gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type, + gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake, + gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + /* Setup chained handler for this GPIO bank */ irq_set_handler_data(bank->irq, bank); irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler); -- cgit v1.2.3 From 8cd73e4e3807315115122fd4e3ac7c33007cdf9c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 8 Jul 2013 17:14:39 -0300 Subject: gpio: gpio-mxc: Use devm functions By using devm functions we can get a simpler code. Signed-off-by: Fabio Estevam Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxc.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 7176743915d3..91f2ac35038a 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -405,34 +405,19 @@ static int mxc_gpio_probe(struct platform_device *pdev) mxc_gpio_get_hw(pdev); - port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL); + port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) { - err = -ENODEV; - goto out_kfree; - } - - if (!request_mem_region(iores->start, resource_size(iores), - pdev->name)) { - err = -EBUSY; - goto out_kfree; - } - - port->base = ioremap(iores->start, resource_size(iores)); - if (!port->base) { - err = -ENOMEM; - goto out_release_mem; - } + port->base = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); port->irq_high = platform_get_irq(pdev, 1); port->irq = platform_get_irq(pdev, 0); - if (port->irq < 0) { - err = -EINVAL; - goto out_iounmap; - } + if (port->irq < 0) + return -EINVAL; /* disable the interrupt and clear the status */ writel(0, port->base + GPIO_IMR); @@ -462,7 +447,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) port->base + GPIO_DR, NULL, port->base + GPIO_GDIR, NULL, 0); if (err) - goto out_iounmap; + goto out_bgio; port->bgc.gc.to_irq = mxc_gpio_to_irq; port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : @@ -498,12 +483,7 @@ out_gpiochip_remove: WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); out_bgpio_remove: bgpio_remove(&port->bgc); -out_iounmap: - iounmap(port->base); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); -out_kfree: - kfree(port); +out_bgio: dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); return err; } -- cgit v1.2.3 From a5d28d79f568a0a2792e3135b304a82b1f91d4ad Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 12 Jul 2013 13:30:43 +0200 Subject: GPIO: gpio-twl6040: Remove support for legacy (pdata) mode TWL6040 is used only with OMAP4/5 SoCs and they can only boot in in DT mode. The support for pdata/legacy boot can be removed. Signed-off-by: Peter Ujfalusi Signed-off-by: Linus Walleij --- drivers/gpio/gpio-twl6040.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index 0be82c6dd796..d420d30b86e7 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -84,15 +84,11 @@ static struct gpio_chip twl6040gpo_chip = { static int gpo_twl6040_probe(struct platform_device *pdev) { - struct twl6040_gpo_data *pdata = pdev->dev.platform_data; struct device *twl6040_core_dev = pdev->dev.parent; struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev); int ret; - if (pdata) - twl6040gpo_chip.base = pdata->gpio_base; - else - twl6040gpo_chip.base = -1; + twl6040gpo_chip.base = -1; if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0) twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */ -- cgit v1.2.3 From a3d88c92a1d7ebbe1e956fd9f0f37bc383f2571b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 19 Jul 2013 16:12:50 +0900 Subject: gpiolib: replace strict_strtol() with kstrtol() The usage of strict_strtol() is not preferred, because strict_strtol() is obsolete. Thus, kstrtol() should be used. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index ff0fd655729f..d6413b2e0844 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -349,7 +349,7 @@ static ssize_t gpio_value_store(struct device *dev, else { long value; - status = strict_strtol(buf, 0, &value); + status = kstrtol(buf, 0, &value); if (status == 0) { if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -570,7 +570,7 @@ static ssize_t gpio_active_low_store(struct device *dev, } else { long value; - status = strict_strtol(buf, 0, &value); + status = kstrtol(buf, 0, &value); if (status == 0) status = sysfs_set_active_low(desc, dev, value != 0); } @@ -652,7 +652,7 @@ static ssize_t export_store(struct class *class, struct gpio_desc *desc; int status; - status = strict_strtol(buf, 0, &gpio); + status = kstrtol(buf, 0, &gpio); if (status < 0) goto done; @@ -694,7 +694,7 @@ static ssize_t unexport_store(struct class *class, struct gpio_desc *desc; int status; - status = strict_strtol(buf, 0, &gpio); + status = kstrtol(buf, 0, &gpio); if (status < 0) goto done; -- cgit v1.2.3 From d22fcde0b5409a946567387dfdde79a07843bb78 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 23 Jun 2013 21:00:05 -0700 Subject: gpio: Kontron PLD gpio driver Add gpio support for the on-board PLD found on some Kontron embedded modules. Originally-from: Michael Brunner Signed-off-by: Guenter Roeck Signed-off-by: Kevin Strasser Acked-by: Darren Hart Reviewed-by: Linus Walleij Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 12 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-kempld.c | 225 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/gpio/gpio-kempld.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 02db4eafa9df..4b7ba53e96db 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -691,6 +691,18 @@ config GPIO_UCB1400 This enables support for the Philips UCB1400 GPIO pins. The UCB1400 is an AC97 audio codec. +comment "LPC GPIO expanders:" + +config GPIO_KEMPLD + tristate "Kontron ETX / COMexpress GPIO" + depends on MFD_KEMPLD + help + This enables support for the PLD GPIO interface on some Kontron ETX + and COMexpress (ETXexpress) modules. + + This driver can also be built as a module. If so, the module will be + called gpio-kempld. + comment "MODULbus GPIO expanders:" config GPIO_JANZ_TTL diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fa97bf8698ed..156fd283945c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o +obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c new file mode 100644 index 000000000000..1bdc3a2e40dc --- /dev/null +++ b/drivers/gpio/gpio-kempld.c @@ -0,0 +1,225 @@ +/* + * Kontron PLD GPIO driver + * + * Copyright (c) 2010-2013 Kontron Europe GmbH + * Author: Michael Brunner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define KEMPLD_GPIO_MAX_NUM 16 +#define KEMPLD_GPIO_MASK(x) (1 << ((x) % 8)) +#define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) +#define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) +#define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 +#define KEMPLD_GPIO_IEN 0x4A + +struct kempld_gpio_data { + struct gpio_chip chip; + struct kempld_device_data *pld; +}; + +/* + * Set or clear GPIO bit + * kempld_get_mutex must be called prior to calling this function. + */ +static void kempld_gpio_bitop(struct kempld_device_data *pld, + u8 reg, u8 bit, u8 val) +{ + u8 status; + + status = kempld_read8(pld, reg); + if (val) + status |= (1 << bit); + else + status &= ~(1 << bit); + kempld_write8(pld, reg, status); +} + +static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit) +{ + u8 status; + + kempld_get_mutex(pld); + status = kempld_read8(pld, reg); + kempld_release_mutex(pld); + + return !!(status & (1 << bit)); +} + +static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), + KEMPLD_GPIO_MASK(offset)); +} + +static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + kempld_get_mutex(pld); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), + KEMPLD_GPIO_MASK(offset), value); + kempld_release_mutex(pld); +} + +static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + kempld_get_mutex(pld); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), + KEMPLD_GPIO_MASK(offset), 0); + kempld_release_mutex(pld); + + return 0; +} + +static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + kempld_get_mutex(pld); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), + KEMPLD_GPIO_MASK(offset), value); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), + KEMPLD_GPIO_MASK(offset), 1); + kempld_release_mutex(pld); + + return 0; +} + +static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), + KEMPLD_GPIO_MASK(offset)); +} + +static int kempld_gpio_pincount(struct kempld_device_data *pld) +{ + u16 evt, evt_back; + + kempld_get_mutex(pld); + + /* Backup event register as it might be already initialized */ + evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); + /* Clear event register */ + kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000); + /* Read back event register */ + evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); + /* Restore event register */ + kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back); + + kempld_release_mutex(pld); + + return evt ? __ffs(evt) : 16; +} + +static int kempld_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct kempld_device_data *pld = dev_get_drvdata(dev->parent); + struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_gpio_data *gpio; + struct gpio_chip *chip; + int ret; + + if (pld->info.spec_major < 2) { + dev_err(dev, + "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n"); + return -ENODEV; + } + + gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + + gpio->pld = pld; + + platform_set_drvdata(pdev, gpio); + + chip = &gpio->chip; + chip->label = "gpio-kempld"; + chip->owner = THIS_MODULE; + chip->dev = dev; + chip->can_sleep = 1; + if (pdata && pdata->gpio_base) + chip->base = pdata->gpio_base; + else + chip->base = -1; + chip->direction_input = kempld_gpio_direction_input; + chip->direction_output = kempld_gpio_direction_output; + chip->get_direction = kempld_gpio_get_direction; + chip->get = kempld_gpio_get; + chip->set = kempld_gpio_set; + chip->ngpio = kempld_gpio_pincount(pld); + if (chip->ngpio == 0) { + dev_err(dev, "No GPIO pins detected\n"); + return -ENODEV; + } + + ret = gpiochip_add(chip); + if (ret) { + dev_err(dev, "Could not register GPIO chip\n"); + return ret; + } + + dev_info(dev, "GPIO functionality initialized with %d pins\n", + chip->ngpio); + + return 0; +} + +static int kempld_gpio_remove(struct platform_device *pdev) +{ + struct kempld_gpio_data *gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&gpio->chip); +} + +static struct platform_driver kempld_gpio_driver = { + .driver = { + .name = "gpio-kempld", + .owner = THIS_MODULE, + }, + .probe = kempld_gpio_probe, + .remove = kempld_gpio_remove, +}; + +module_platform_driver(kempld_gpio_driver); + +MODULE_DESCRIPTION("KEM PLD GPIO Driver"); +MODULE_AUTHOR("Michael Brunner "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-kempld"); -- cgit v1.2.3 From 640efa08cb635ae43d5ceae302b20c2c3f2035e5 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 3 Jul 2013 13:14:32 +0900 Subject: gpio: em: Add pinctrl support Register the GPIO pin range, and request and free GPIO pins using the pinctrl API. The pctl_name platform data member should be used by platform devices to point out which pinctrl device to use. Follows same style as "dc3465a gpio-rcar: Add pinctrl support", by Laurent Pinchart, thanks to him. Signed-off-by: Magnus Damm Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 5cba855638bf..eca119b58c21 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -30,6 +30,7 @@ #include #include #include +#include #include struct em_gio_priv { @@ -216,6 +217,21 @@ static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } +static int em_gio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void em_gio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); + + /* Set the GPIO as an input to ensure that the next GPIO request won't + * drive the GPIO pin as an output. + */ + em_gio_direction_input(chip, offset); +} + static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { @@ -308,6 +324,8 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->direction_output = em_gio_direction_output; gpio_chip->set = em_gio_set; gpio_chip->to_irq = em_gio_to_irq; + gpio_chip->request = em_gio_request; + gpio_chip->free = em_gio_free; gpio_chip->label = name; gpio_chip->owner = THIS_MODULE; gpio_chip->base = pdata->gpio_base; @@ -351,6 +369,13 @@ static int em_gio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to add GPIO controller\n"); goto err1; } + + if (pdata->pctl_name) { + ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0, + gpio_chip->base, gpio_chip->ngpio); + if (ret < 0) + dev_warn(&pdev->dev, "failed to add pin range\n"); + } return 0; err1: -- cgit v1.2.3 From 5dbb7c637f5adadc02c912fb5fc709ec1d342000 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 11 Jul 2013 17:17:53 +0200 Subject: gpio: pxa: remove dead code Commit f87311743 ("ARM: mmp: add more compatible names in gpio driver") changed the driver logic to determine the number of available GPIOs from the compatible string, and hence obsoleted the (undocumented) child nodes that were previously necessary. However, it left some remainder which can be safely removed now. Also, this patch makes pxa_gpio_probe_dt() return the correct value in case irq_alloc_descs() fails. Signed-off-by: Daniel Mack Cc: Haojian Zhuang Cc: Linus Walleij Cc: Arnd Bergmann Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index df2199dd1499..cc13d1b74fad 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -524,8 +524,8 @@ const struct irq_domain_ops pxa_irq_domain_ops = { static int pxa_gpio_probe_dt(struct platform_device *pdev) { - int ret, nr_gpios; - struct device_node *prev, *next, *np = pdev->dev.of_node; + int ret = 0, nr_gpios; + struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(pxa_gpio_dt_ids, &pdev->dev); const struct pxa_gpio_id *gpio_id; @@ -537,20 +537,13 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev) gpio_id = of_id->data; gpio_type = gpio_id->type; - next = of_get_next_child(np, NULL); - prev = next; - if (!next) { - dev_err(&pdev->dev, "Failed to find child gpio node\n"); - ret = -EINVAL; - goto err; - } - of_node_put(prev); nr_gpios = gpio_id->gpio_nums; pxa_last_gpio = nr_gpios - 1; irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0); if (irq_base < 0) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); + ret = irq_base; goto err; } domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0, -- cgit v1.2.3 From 18f92b19b4101dbe9fef3923028cf66b27847778 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 22 Jul 2013 18:17:52 -0300 Subject: gpio: gpio-mxc: Include "" Commit 8cd73e4e (gpio: gpio-mxc: Use devm functions) causes the following build error on imx_v4_v7_defconfig: drivers/gpio/gpio-mxc.c:414:2: error: implicit declaration of function 'IS_ERR' [-Werror=implicit-function-declaration] drivers/gpio/gpio-mxc.c:415:3: error: implicit declaration of function 'PTR_ERR' [-Werror=implicit-function-declaration] Note: imx_v6_v7_defconfig does not give this build error, probably due to some indirect header file inclusion. Reported-by: Olof Johansson Signed-off-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 91f2ac35038a..875a7c539591 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include #include #include -- cgit v1.2.3 From 5763318f562fc0b30f729dce531b2982e29db463 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 23 Jul 2013 13:06:04 +0530 Subject: gpio: palmas: add dt support Add of_device_id table for Palma GPIO to be enable the driver from DT file. The driver can be registered from DT file as: palmas: tps65913@58 { ::::::::::: palmas_gpio: palmas_gpio { compatible = "ti,palmas-gpio"; gpio-controller; #gpio-cells = <2>; }; }; Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-palmas.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index e3a4e56f5a42..09360c4b6386 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -134,7 +134,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->gpio_chip.get = palmas_gpio_get; palmas_gpio->gpio_chip.dev = &pdev->dev; #ifdef CONFIG_OF_GPIO - palmas_gpio->gpio_chip.of_node = palmas->dev->of_node; + palmas_gpio->gpio_chip.of_node = pdev->dev.of_node; #endif palmas_pdata = dev_get_platdata(palmas->dev); if (palmas_pdata && palmas_pdata->gpio_base) @@ -159,9 +159,19 @@ static int palmas_gpio_remove(struct platform_device *pdev) return gpiochip_remove(&palmas_gpio->gpio_chip); } +static struct of_device_id of_palmas_gpio_match[] = { + { .compatible = "ti,palmas-gpio"}, + { .compatible = "ti,tps65913-gpio"}, + { .compatible = "ti,tps65914-gpio"}, + { .compatible = "ti,tps80036-gpio"}, + { }, +}; +MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); + static struct platform_driver palmas_gpio_driver = { .driver.name = "palmas-gpio", .driver.owner = THIS_MODULE, + .driver.of_match_table = of_palmas_gpio_match, .probe = palmas_gpio_probe, .remove = palmas_gpio_remove, }; -- cgit v1.2.3 From 8b628c659ce1e2a8714ebcfe55f80457a4ebe734 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Fri, 26 Jul 2013 13:39:53 -0700 Subject: gpio: palmas: Fix misreported GPIO out value It seems that the value read back from the PALMAS_GPIO_DATA_IN register isn't valid if the GPIO direction is out. When that's the case, we can read back the PALMAS_GPIO_DATA_OUT register to get the proper output value. Signed-off-by: Andrew Chew Acked-by: Laxman Dewangan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-palmas.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 09360c4b6386..8588af0f7661 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -43,9 +43,22 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) unsigned int val; int ret; - ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val); + ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret); + dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret); + return ret; + } + + if (val & (1 << offset)) { + ret = palmas_read(palmas, PALMAS_GPIO_BASE, + PALMAS_GPIO_DATA_OUT, &val); + } else { + ret = palmas_read(palmas, PALMAS_GPIO_BASE, + PALMAS_GPIO_DATA_IN, &val); + } + if (ret < 0) { + dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n", + ret); return ret; } return !!(val & BIT(offset)); -- cgit v1.2.3 From 8a564065825cb92d412f107812ef50fe9ef43668 Mon Sep 17 00:00:00 2001 From: "Daniel M. Weeks" Date: Fri, 19 Jul 2013 00:19:58 -0400 Subject: gpio-mcp23s08: i2c: auto-select base if no DT match or platform data The call to gpiochip_add made by this driver is capable of auto-selecting a base if one is not provided. However, it was not called unless there was already a DT entry or platform data. This patch calls it even if the base is not already known so that gpiochip_add can attempt to find a usable base. Signed-off-by: Daniel M. Weeks Acked-by: Lars Poeschel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mcp23s08.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 6a4470b84488..87ed6bf6528b 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -520,14 +520,13 @@ static int mcp230xx_probe(struct i2c_client *client, match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), &client->dev); - if (match) { + pdata = client->dev.platform_data; + if (match || !pdata) { base = -1; pullups = 0; } else { - pdata = client->dev.platform_data; - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&client->dev, - "invalid or missing platform data\n"); + if (!gpio_is_valid(pdata->base)) { + dev_dbg(&client->dev, "invalid platform data\n"); return -EINVAL; } base = pdata->base; -- cgit v1.2.3 From c0e811d9f5d1ee708f06c4f0a1009f8a1d22f364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 18 Jul 2013 14:58:06 +0200 Subject: gpio/mxc: add chained_irq_enter/exit() to mx2_gpio_irq_handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to commit 0e44b6e (gpio/mxc: add chained_irq_enter/exit() to mx3_gpio_irq_handler()) . It doesn't seem to be critical to make the irqs work, but still it is more correct. Signed-off-by: Uwe Kleine-König Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 875a7c539591..3307f6db3a92 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -292,6 +292,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_msk, irq_stat; struct mxc_gpio_port *port; + struct irq_chip *chip = irq_get_chip(irq); + + chained_irq_enter(chip, desc); /* walk through all interrupt status registers */ list_for_each_entry(port, &mxc_gpio_ports, node) { @@ -303,6 +306,7 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) if (irq_stat) mxc_gpio_irq_handler(port, irq_stat); } + chained_irq_exit(chip, desc); } /* -- cgit v1.2.3 From e56aee1897fd27631c1cb28e12b0fb8f8f9736f7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 30 Jul 2013 17:08:05 +0900 Subject: gpio: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-74x164.c | 2 +- drivers/gpio/gpio-adp5520.c | 2 +- drivers/gpio/gpio-adp5588.c | 9 ++++++--- drivers/gpio/gpio-arizona.c | 2 +- drivers/gpio/gpio-da9052.c | 2 +- drivers/gpio/gpio-da9055.c | 2 +- drivers/gpio/gpio-em.c | 2 +- drivers/gpio/gpio-ich.c | 2 +- drivers/gpio/gpio-janz-ttl.c | 2 +- drivers/gpio/gpio-kempld.c | 2 +- drivers/gpio/gpio-max730x.c | 2 +- drivers/gpio/gpio-max732x.c | 8 ++++---- drivers/gpio/gpio-mc33880.c | 2 +- drivers/gpio/gpio-mcp23s08.c | 4 ++-- drivers/gpio/gpio-msic.c | 2 +- drivers/gpio/gpio-omap.c | 2 +- drivers/gpio/gpio-pca953x.c | 4 ++-- drivers/gpio/gpio-pcf857x.c | 4 ++-- drivers/gpio/gpio-pl061.c | 2 +- drivers/gpio/gpio-rcar.c | 2 +- drivers/gpio/gpio-rdc321x.c | 2 +- drivers/gpio/gpio-sta2x11.c | 2 +- drivers/gpio/gpio-sx150x.c | 2 +- drivers/gpio/gpio-timberdale.c | 4 ++-- drivers/gpio/gpio-tps65912.c | 2 +- drivers/gpio/gpio-ts5500.c | 2 +- drivers/gpio/gpio-twl4030.c | 6 +++--- drivers/gpio/gpio-ucb1400.c | 2 +- drivers/gpio/gpio-wm831x.c | 2 +- drivers/gpio/gpio-wm8350.c | 2 +- drivers/gpio/gpio-wm8994.c | 2 +- 31 files changed, 45 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 721607904d0a..5d518d5db7a0 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -129,7 +129,7 @@ static int gen_74x164_probe(struct spi_device *spi) if (!chip) return -ENOMEM; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (pdata && pdata->base) chip->gpio_chip.base = pdata->base; else diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index f33f78dcadaa..084337d5514d 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -89,7 +89,7 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip, static int adp5520_gpio_probe(struct platform_device *pdev) { - struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data; + struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct adp5520_gpio *dev; struct gpio_chip *gc; int ret, i, gpios; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 2ba56987db04..90fc4c99c024 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -276,7 +276,8 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid) static int adp5588_irq_setup(struct adp5588_gpio *dev) { struct i2c_client *client = dev->client; - struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + struct adp5588_gpio_platform_data *pdata = + dev_get_platdata(&client->dev); unsigned gpio; int ret; @@ -349,7 +350,8 @@ static void adp5588_irq_teardown(struct adp5588_gpio *dev) static int adp5588_gpio_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + struct adp5588_gpio_platform_data *pdata = + dev_get_platdata(&client->dev); struct adp5588_gpio *dev; struct gpio_chip *gc; int ret, i, revid; @@ -440,7 +442,8 @@ err: static int adp5588_gpio_remove(struct i2c_client *client) { - struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + struct adp5588_gpio_platform_data *pdata = + dev_get_platdata(&client->dev); struct adp5588_gpio *dev = i2c_get_clientdata(client); int ret; diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 0ea853f68db2..fa8b6a762761 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -97,7 +97,7 @@ static struct gpio_chip template_chip = { static int arizona_gpio_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); - struct arizona_pdata *pdata = arizona->dev->platform_data; + struct arizona_pdata *pdata = dev_get_platdata(arizona->dev); struct arizona_gpio *arizona_gpio; int ret; diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 29b11e9b6a78..9b77dc05d4ad 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -216,7 +216,7 @@ static int da9052_gpio_probe(struct platform_device *pdev) return -ENOMEM; gpio->da9052 = dev_get_drvdata(pdev->dev.parent); - pdata = gpio->da9052->dev->platform_data; + pdata = dev_get_platdata(gpio->da9052->dev); gpio->gp = reference_gp; if (pdata && pdata->gpio_base) diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index fd6dfe382f13..7ef0820032bd 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -150,7 +150,7 @@ static int da9055_gpio_probe(struct platform_device *pdev) return -ENOMEM; gpio->da9055 = dev_get_drvdata(pdev->dev.parent); - pdata = gpio->da9055->dev->platform_data; + pdata = dev_get_platdata(gpio->da9055->dev); gpio->gp = reference_gp; if (pdata && pdata->gpio_base) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index eca119b58c21..c6e1f086efe8 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -253,7 +253,7 @@ static struct irq_domain_ops em_gio_irq_domain_ops = { static int em_gio_probe(struct platform_device *pdev) { struct gpio_em_config pdata_dt; - struct gpio_em_config *pdata = pdev->dev.platform_data; + struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev); struct em_gio_priv *p; struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 2729e3d2d5bb..814addb62d2c 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -354,7 +354,7 @@ static int ichx_gpio_probe(struct platform_device *pdev) { struct resource *res_base, *res_pm; int err; - struct lpc_ich_info *ich_info = pdev->dev.platform_data; + struct lpc_ich_info *ich_info = dev_get_platdata(&pdev->dev); if (!ich_info) return -ENODEV; diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index 7d0a04169a35..2ecd3a09c743 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -149,7 +149,7 @@ static int ttl_probe(struct platform_device *pdev) struct resource *res; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(dev, "no platform data\n"); ret = -ENXIO; diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 1bdc3a2e40dc..3f5b20038af1 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -150,7 +150,7 @@ static int kempld_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct kempld_device_data *pld = dev_get_drvdata(dev->parent); - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); struct kempld_gpio_data *gpio; struct gpio_chip *chip; int ret; diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 00092342b84c..f4f4ed19bdc1 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -166,7 +166,7 @@ int __max730x_probe(struct max7301 *ts) struct max7301_platform_data *pdata; int i, ret; - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); mutex_init(&ts->lock); dev_set_drvdata(dev, ts); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index d4b51b163b03..91ad74dea8ce 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -453,7 +453,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; - struct max732x_platform_data *pdata = client->dev.platform_data; + struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); int has_irq = max732x_features[id->driver_data] >> 32; int ret; @@ -512,7 +512,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; - struct max732x_platform_data *pdata = client->dev.platform_data; + 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) @@ -583,7 +583,7 @@ static int max732x_probe(struct i2c_client *client, uint16_t addr_a, addr_b; int ret, nr_port; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (pdata == NULL) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; @@ -653,7 +653,7 @@ out_failed: static int max732x_remove(struct i2c_client *client) { - struct max732x_platform_data *pdata = client->dev.platform_data; + struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); struct max732x_chip *chip = i2c_get_clientdata(client); int ret; diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 63a7a1bfb2d9..3fd2caa4a2e0 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -86,7 +86,7 @@ static int mc33880_probe(struct spi_device *spi) struct mc33880_platform_data *pdata; int ret; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (!pdata || !pdata->base) { dev_dbg(&spi->dev, "incorrect or missing platform data\n"); return -EINVAL; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 87ed6bf6528b..d96bf8a76f5c 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -520,7 +520,7 @@ static int mcp230xx_probe(struct i2c_client *client, match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), &client->dev); - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (match || !pdata) { base = -1; pullups = 0; @@ -634,7 +634,7 @@ static int mcp23s08_probe(struct spi_device *spi) pullups[addr] = 0; } else { type = spi_get_device_id(spi)->driver_data; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (!pdata || !gpio_is_valid(pdata->base)) { dev_dbg(&spi->dev, "invalid or missing platform data\n"); diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index 27ea7b9257ff..d75eaa3a1dcc 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -259,7 +259,7 @@ static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc) static int platform_msic_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct intel_msic_gpio_pdata *pdata = dev->platform_data; + struct intel_msic_gpio_pdata *pdata = dev_get_platdata(dev); struct msic_gpio *mg; int irq = platform_get_irq(pdev, 0); int retval; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index dfeb3a3a8f20..867efe57b038 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1100,7 +1100,7 @@ static int omap_gpio_probe(struct platform_device *pdev) match = of_match_device(of_match_ptr(omap_gpio_match), dev); - pdata = match ? match->data : dev->platform_data; + pdata = match ? match->data : dev_get_platdata(dev); if (!pdata) return -EINVAL; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 426c51dd420c..07651d30ba8b 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -731,7 +731,7 @@ static int pca953x_probe(struct i2c_client *client, if (chip == NULL) return -ENOMEM; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (pdata) { irq_base = pdata->irq_base; chip->gpio_start = pdata->gpio_base; @@ -785,7 +785,7 @@ static int pca953x_probe(struct i2c_client *client, static int pca953x_remove(struct i2c_client *client) { - struct pca953x_platform_data *pdata = client->dev.platform_data; + struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca953x_chip *chip = i2c_get_clientdata(client); int ret = 0; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index e8faf53f3875..e8835d64e921 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -262,7 +262,7 @@ static int pcf857x_probe(struct i2c_client *client, struct pcf857x *gpio; int status; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); } @@ -396,7 +396,7 @@ fail: static int pcf857x_remove(struct i2c_client *client) { - struct pcf857x_platform_data *pdata = client->dev.platform_data; + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); struct pcf857x *gpio = i2c_get_clientdata(client); int status = 0; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 6a4bd0dae0ce..4274e2e70ef8 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -259,7 +259,7 @@ static const struct irq_domain_ops pl061_domain_ops = { static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; - struct pl061_platform_data *pdata = dev->platform_data; + struct pl061_platform_data *pdata = dev_get_platdata(dev); struct pl061_gpio *chip; int ret, irq, i, irq_base; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index e8198dd68615..e3745eb07570 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -285,7 +285,7 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = { static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) { - struct gpio_rcar_config *pdata = p->pdev->dev.platform_data; + struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev); struct device_node *np = p->pdev->dev.of_node; struct of_phandle_args args; int ret; diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index 368c3c00fca5..88577c3272a5 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -135,7 +135,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) struct rdc321x_gpio *rdc321x_gpio_dev; struct rdc321x_gpio_pdata *pdata; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index f43ab6aea281..f2fb12c18da9 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -361,7 +361,7 @@ static int gsta_probe(struct platform_device *dev) struct gsta_gpio *chip; struct resource *res; - pdev = *(struct pci_dev **)(dev->dev.platform_data); + pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev); gpio_pdata = dev_get_platdata(&pdev->dev); if (gpio_pdata == NULL) diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index f371732591d2..d2983e9ad6af 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -583,7 +583,7 @@ static int sx150x_probe(struct i2c_client *client, struct sx150x_chip *chip; int rc; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) return -EINVAL; diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 4c65f8883204..7a0e956ef1ed 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -227,7 +227,7 @@ static int timbgpio_probe(struct platform_device *pdev) struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; - struct timbgpio_platform_data *pdata = pdev->dev.platform_data; + struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { @@ -318,7 +318,7 @@ err_mem: static int timbgpio_remove(struct platform_device *pdev) { int err; - struct timbgpio_platform_data *pdata = pdev->dev.platform_data; + struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct timbgpio *tgpio = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 30a5844a7dca..276a4229b032 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -87,7 +87,7 @@ static struct gpio_chip template_chip = { static int tps65912_gpio_probe(struct platform_device *pdev) { struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); - struct tps65912_board *pdata = tps65912->dev->platform_data; + struct tps65912_board *pdata = dev_get_platdata(tps65912->dev); struct tps65912_gpio_data *tps65912_gpio; int ret; diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index cc53cab8df2a..3df3ebdb3e52 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -322,7 +322,7 @@ static void ts5500_disable_irq(struct ts5500_priv *priv) static int ts5500_dio_probe(struct platform_device *pdev) { enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data; - struct ts5500_dio_platform_data *pdata = pdev->dev.platform_data; + struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; const char *name = dev_name(dev); struct ts5500_priv *priv; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 4d330e36da1d..d8e4f6efcb29 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -256,7 +256,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) /* optionally have the first two GPIOs switch vMMC1 * and vMMC2 power supplies based on card presence. */ - pdata = chip->dev->platform_data; + pdata = dev_get_platdata(chip->dev); if (pdata) value |= pdata->mmc_cd & 0x03; @@ -460,7 +460,7 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) static int gpio_twl4030_probe(struct platform_device *pdev) { - struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; + struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct gpio_twl4030_priv *priv; int ret, irq_base; @@ -556,7 +556,7 @@ out: /* Cannot use as gpio_twl4030_probe() calls us */ static int gpio_twl4030_remove(struct platform_device *pdev) { - struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; + struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); int status; diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 6d0feb234d3c..1a605f2a0f55 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -45,7 +45,7 @@ static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val) static int ucb1400_gpio_probe(struct platform_device *dev) { - struct ucb1400_gpio *ucb = dev->dev.platform_data; + struct ucb1400_gpio *ucb = dev_get_platdata(&dev->dev); int err = 0; if (!(ucb && ucb->gpio_offset)) { diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 2a743e10ecb6..456000c5c457 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -246,7 +246,7 @@ static struct gpio_chip template_chip = { static int wm831x_gpio_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); - struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct wm831x_gpio *wm831x_gpio; int ret; diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index 0b598cf3df9d..fc49154be7b1 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -112,7 +112,7 @@ static struct gpio_chip template_chip = { static int wm8350_gpio_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent); - struct wm8350_platform_data *pdata = wm8350->dev->platform_data; + struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev); struct wm8350_gpio_data *wm8350_gpio; int ret; diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index ae409fd94af7..a53dbdefc7ee 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -248,7 +248,7 @@ static struct gpio_chip template_chip = { static int wm8994_gpio_probe(struct platform_device *pdev) { struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); - struct wm8994_pdata *pdata = wm8994->dev->platform_data; + struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev); struct wm8994_gpio *wm8994_gpio; int ret; -- cgit v1.2.3 From eddf8176b57ddb8f960b188eb8796b9d13e4efc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Wed, 31 Jul 2013 16:12:54 +0200 Subject: gpio: gpiolib-of.c: make error message more meaningful by adding the node name and index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lothar Waßmann Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 665f9530c950..ba9876ffb017 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -76,7 +76,8 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, &gg_data.gpiospec); if (ret) { - pr_debug("%s: can't parse gpios property\n", __func__); + pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", + __func__, np->full_name, index); return ret; } -- cgit v1.2.3 From b3abebc777015a445a95548aafe2d3a4b116288e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 6 Aug 2013 18:43:18 +0900 Subject: gpio: msm: Staticize local variable 'msm_gpio' The local variable 'msm_gpio' is used only in this file. Fix the following sparse warning: drivers/gpio/gpio-msm-v2.c:109:21: warning: symbol 'msm_gpio' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-msm-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index f4491a497cc8..27fe8b11b67a 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -106,7 +106,7 @@ struct msm_gpio_dev { void __iomem *msm_tlmm_base; }; -struct msm_gpio_dev msm_gpio; +static struct msm_gpio_dev msm_gpio; #define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \ (0x04 * (gpio))) -- cgit v1.2.3 From 5b21533b767578f9a80f09082e3aae7429c331c3 Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Wed, 7 Aug 2013 17:23:58 +0200 Subject: gpio: adnp: Fix segfault if request_threaded_irq fails In case request_threaded_irq inside adnp_irq_setup fails, the driver segfaults. This is because irq_domain_remove is called twice with the same pointer. First time in adnp_irq_setup and then a second time after leaving adnp_irq_setup in the error path of adnp_i2c_probe inside adnp_teardown. This fixes this by removing the call to irq_domain_remove from adnp_irq_setup. Signed-off-by: Lars Poeschel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adnp.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index e60567fc5073..c0f3fc44ab0e 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -490,15 +490,11 @@ static int adnp_irq_setup(struct adnp *adnp) if (err != 0) { dev_err(chip->dev, "can't request IRQ#%d: %d\n", adnp->client->irq, err); - goto error; + return err; } chip->to_irq = adnp_gpio_to_irq; return 0; - -error: - irq_domain_remove(adnp->domain); - return err; } static void adnp_irq_teardown(struct adnp *adnp) -- cgit v1.2.3 From 81e9df2c946e49044877136789ecae61cbf65c81 Mon Sep 17 00:00:00 2001 From: Michael Brunner Date: Fri, 9 Aug 2013 17:33:06 +0200 Subject: gpio: Fix platform driver name in Kontron PLD GPIO driver This patch changes the driver name to be consistent with the name that is registered as cell name in the MFD driver. Otherwise the driver won't load. Reviewed-by: Guenter Roeck Acked-by: Kevin Strasser Signed-off-by: Michael Brunner --- drivers/gpio/gpio-kempld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 3f5b20038af1..3f0e13b05953 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -210,7 +210,7 @@ static int kempld_gpio_remove(struct platform_device *pdev) static struct platform_driver kempld_gpio_driver = { .driver = { - .name = "gpio-kempld", + .name = "kempld-gpio", .owner = THIS_MODULE, }, .probe = kempld_gpio_probe, -- cgit v1.2.3 From b168386eaf560bf13fcf2c166453714e779f763e Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 12 Aug 2013 14:05:41 +0300 Subject: gpio-lynxpoint: Fix warning about unbalanced pm_runtime_enable Missing pm_runtime_disable call in driver remove path caused an unbalanaced pm_runtime_enable warning when driver was reloaded Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-lynxpoint.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 761c4705dfbb..2d9ca6055e5e 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -444,6 +444,7 @@ static int lp_gpio_remove(struct platform_device *pdev) { struct lp_gpio *lg = platform_get_drvdata(pdev); int err; + pm_runtime_disable(&pdev->dev); err = gpiochip_remove(&lg->chip); if (err) dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); -- cgit v1.2.3 From 388f4308412574268d38010d877575f8caebad79 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 13 Aug 2013 09:16:56 +0200 Subject: drivers/gpio/gpio-omap.c: convert comma to semicolon Replace a comma between expression statements by a semicolon. This changes the semantics of the code, but given the current indentation appears to be what is intended. A simplified version of the semantic patch that performs this transformation is as follows: (http://coccinelle.lip6.fr/) // @r@ expression e1,e2,e; type T; identifier i; @@ e1 -, +; e2; // Signed-off-by: Julia Lawall Acked-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 867efe57b038..0ff43552d472 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1030,7 +1030,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, ct->chip.irq_set_type = gpio_irq_type; if (bank->regs->wkup_en) - ct->chip.irq_set_wake = gpio_wake_enable, + ct->chip.irq_set_wake = gpio_wake_enable; ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, -- cgit v1.2.3 From 08a67a58af3c361ae3e8d6fcf23a1489213309a9 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 14 Aug 2013 11:11:07 +0200 Subject: drivers/gpio: simplify use of devm_ioremap_resource Remove unneeded error handling on the result of a call to platform_get_resource when the value is passed to devm_ioremap_resource. Move the call to platform_get_resource adjacent to the call to devm_ioremap_resource to make the connection between them more clear. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression pdev,res,n,e,e1; expression ret != 0; identifier l; @@ - res = platform_get_resource(pdev, IORESOURCE_MEM, n); ... when != res - if (res == NULL) { ... \(goto l;\|return ret;\) } ... when != res + res = platform_get_resource(pdev, IORESOURCE_MEM, n); e = devm_ioremap_resource(e1, res); // Signed-off-by: Julia Lawall Acked-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 7 +------ drivers/gpio/gpio-spear-spics.c | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 80ad35e2a8cd..3c3321f94053 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -566,12 +566,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) else soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Cannot get memory resource\n"); - return -ENODEV; - } - mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); if (!mvchip) { dev_err(&pdev->dev, "Cannot allocate memory\n"); @@ -611,6 +605,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.dbg_show = mvebu_gpio_dbg_show; spin_lock_init(&mvchip->lock); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mvchip->membase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(mvchip->membase)) return PTR_ERR(mvchip->membase); diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index 7a4bf7c0d98f..e9a0415834ea 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -128,18 +128,13 @@ static int spics_gpio_probe(struct platform_device *pdev) struct resource *res; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); - return -EBUSY; - } - spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); if (!spics) { dev_err(&pdev->dev, "memory allocation fail\n"); return -ENOMEM; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spics->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(spics->base)) return PTR_ERR(spics->base); -- cgit v1.2.3 From 40a625daa88653d7942dc85483f6f289cd687cb7 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 7 Aug 2013 16:52:40 -0500 Subject: gpio: pca953x: fix gpio input on gpio offsets >= 8 This change fixes a regression introduced by commit f5f0b7aa8 (gpio: pca953x: make the register access by GPIO bank) When the pca953x driver was converted to using 8-bit reads/writes the bitmask in pca953x_gpio_get_value wasn't adjusted with a modulus BANK_SZ and consequently looks at the wrong bits in the input register. Signed-off-by: Andrew Ruder Reviewed-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 07651d30ba8b..91eb8d4492ef 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -308,7 +308,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) return 0; } - return (reg_val & (1u << off)) ? 1 : 0; + return (reg_val & (1u << (off % BANK_SZ))) ? 1 : 0; } static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) -- cgit v1.2.3 From 2e7f6122642773fa467ab80adc30ef20c80dbda6 Mon Sep 17 00:00:00 2001 From: Brunner Michael Date: Wed, 31 Jul 2013 20:55:39 +0200 Subject: gpio: Fix bit masking in Kontron PLD GPIO driver This patch fixes the bit masking within the GPIO driver. The masking is basically done twice which causes the wrong GPIOs to be addressed. Signed-off-by: Michael Brunner Signed-off-by: Guenter Roeck Signed-off-by: Linus Walleij --- drivers/gpio/gpio-kempld.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 3f0e13b05953..efdc3924d7df 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -46,9 +46,9 @@ static void kempld_gpio_bitop(struct kempld_device_data *pld, status = kempld_read8(pld, reg); if (val) - status |= (1 << bit); + status |= KEMPLD_GPIO_MASK(bit); else - status &= ~(1 << bit); + status &= ~KEMPLD_GPIO_MASK(bit); kempld_write8(pld, reg, status); } @@ -60,7 +60,7 @@ static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit) status = kempld_read8(pld, reg); kempld_release_mutex(pld); - return !!(status & (1 << bit)); + return !!(status & KEMPLD_GPIO_MASK(bit)); } static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -69,8 +69,7 @@ static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset) = container_of(chip, struct kempld_gpio_data, chip); struct kempld_device_data *pld = gpio->pld; - return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), - KEMPLD_GPIO_MASK(offset)); + return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset); } static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -80,8 +79,7 @@ static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) struct kempld_device_data *pld = gpio->pld; kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), - KEMPLD_GPIO_MASK(offset), value); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); kempld_release_mutex(pld); } @@ -92,8 +90,7 @@ static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset) struct kempld_device_data *pld = gpio->pld; kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), - KEMPLD_GPIO_MASK(offset), 0); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0); kempld_release_mutex(pld); return 0; @@ -107,10 +104,8 @@ static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset, struct kempld_device_data *pld = gpio->pld; kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), - KEMPLD_GPIO_MASK(offset), value); - kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), - KEMPLD_GPIO_MASK(offset), 1); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1); kempld_release_mutex(pld); return 0; @@ -122,8 +117,7 @@ static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) = container_of(chip, struct kempld_gpio_data, chip); struct kempld_device_data *pld = gpio->pld; - return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), - KEMPLD_GPIO_MASK(offset)); + return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); } static int kempld_gpio_pincount(struct kempld_device_data *pld) -- cgit v1.2.3 From 31eb4b554db7d1f75c3083cfeca1ec4c2874da7f Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 20 Aug 2013 08:29:23 +0200 Subject: gpio: max7301: Reverting "Do not force SPI speed when using OF Platform" This patch reverts commit 047b93a35961f7a6561e6f5dcb040738f822b892 which breaks MAX7301 GPIO driver because that commit was dependant on a rejected patch that was implementing selection of SPI speed from the Device Tree. Signed-off-by: Christophe Leroy Acked-by: Roland Stigge Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max7301.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 3b16ab701630..6e1c984a75d4 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -56,8 +56,7 @@ static int max7301_probe(struct spi_device *spi) int ret; /* bits_per_word cannot be configured in platform data */ - if (spi->dev.platform_data) - spi->bits_per_word = 16; + spi->bits_per_word = 16; ret = spi_setup(spi); if (ret < 0) return ret; -- cgit v1.2.3 From c990d6cb3bdb3132c7ceddfc94eb25096d95d58c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 20 Aug 2013 01:04:52 +0200 Subject: gpio: pcf857x: Sort headers alphabetically This makes checking for duplicates when adding a new #include easier. Signed-off-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcf857x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index e8835d64e921..5fe06949a49f 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -18,15 +18,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include #include #include #include #include #include +#include #include +#include #include #include -- cgit v1.2.3 From 655c4e79370d1731c293c47aaf85d4c990a33052 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 20 Aug 2013 01:04:53 +0200 Subject: gpio: pcf857x: Remove pdata argument to pcf857x_irq_domain_init() The argument is not used, remove it. No board registers a pcf857x device with an IRQ without specifying platform data, IRQ domain registration behaviour is thus not affected by this change. Signed-off-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcf857x.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 5fe06949a49f..9e61bb0719d0 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -223,7 +223,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) } static int pcf857x_irq_domain_init(struct pcf857x *gpio, - struct pcf857x_platform_data *pdata, struct i2c_client *client) { int status; @@ -286,8 +285,8 @@ static int pcf857x_probe(struct i2c_client *client, gpio->chip.ngpio = id->driver_data; /* enable gpio_to_irq() if platform has settings */ - if (pdata && client->irq) { - status = pcf857x_irq_domain_init(gpio, pdata, client); + if (client->irq) { + status = pcf857x_irq_domain_init(gpio, client); if (status < 0) { dev_err(&client->dev, "irq_domain init failed\n"); goto fail; @@ -388,7 +387,7 @@ fail: dev_dbg(&client->dev, "probe error %d for '%s'\n", status, client->name); - if (pdata && client->irq) + if (client->irq) pcf857x_irq_domain_cleanup(gpio); return status; @@ -411,7 +410,7 @@ static int pcf857x_remove(struct i2c_client *client) } } - if (pdata && client->irq) + if (client->irq) pcf857x_irq_domain_cleanup(gpio); status = gpiochip_remove(&gpio->chip); -- cgit v1.2.3 From 6c56c6cd8031e01719e5a5392571c3be08737434 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 26 Aug 2013 19:35:55 +0200 Subject: gpio: samsung: Drop support for Exynos SoCs GPIO support on Exynos SoCs is provided by pinctrl-samsung driver, leaving all the support code in gpio-samsung driver unused. This dead code can be safely removed and so it is done by this patch. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Linus Walleij --- drivers/gpio/gpio-samsung.c | 871 -------------------------------------------- 1 file changed, 871 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a1392f47bbda..358a21c2d811 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -161,28 +161,6 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); } -static int exynos_gpio_setpull(struct samsung_gpio_chip *chip, - unsigned int off, samsung_gpio_pull_t pull) -{ - if (pull == S3C_GPIO_PULL_UP) - pull = 3; - - return samsung_gpio_setpull_updown(chip, off, pull); -} - -static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip, - unsigned int off) -{ - samsung_gpio_pull_t pull; - - pull = samsung_gpio_getpull_updown(chip, off); - - if (pull == 3) - pull = S3C_GPIO_PULL_UP; - - return pull; -} - /* * samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration. * @chip: The gpio chip that is being configured. @@ -444,15 +422,6 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { }; #endif -#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250) -static struct samsung_gpio_cfg exynos_gpio_cfg = { - .set_pull = exynos_gpio_setpull, - .get_pull = exynos_gpio_getpull, - .set_config = samsung_gpio_setcfg_4bit, - .get_config = samsung_gpio_getcfg_4bit, -}; -#endif - #if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = { .cfg_eint = 0x3, @@ -495,15 +464,6 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { .set_config = samsung_gpio_setcfg_2bit, .get_config = samsung_gpio_getcfg_2bit, }, - [8] = { - .set_pull = exynos_gpio_setpull, - .get_pull = exynos_gpio_getpull, - }, - [9] = { - .cfg_eint = 0x3, - .set_pull = exynos_gpio_setpull, - .get_pull = exynos_gpio_getpull, - } }; /* @@ -2115,833 +2075,6 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { #endif }; -/* - * Followings are the gpio banks in EXYNOS SoCs - * - * The 'config' member when left to NULL, is initialized to the default - * structure exynos_gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of samsung_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ - -#ifdef CONFIG_ARCH_EXYNOS4 -static struct samsung_gpio_chip exynos4_gpios_1[] = { - { - .chip = { - .base = EXYNOS4_GPA0(0), - .ngpio = EXYNOS4_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = EXYNOS4_GPA1(0), - .ngpio = EXYNOS4_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = EXYNOS4_GPB(0), - .ngpio = EXYNOS4_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = EXYNOS4_GPC0(0), - .ngpio = EXYNOS4_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = EXYNOS4_GPC1(0), - .ngpio = EXYNOS4_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = EXYNOS4_GPD0(0), - .ngpio = EXYNOS4_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = EXYNOS4_GPD1(0), - .ngpio = EXYNOS4_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE0(0), - .ngpio = EXYNOS4_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = EXYNOS4_GPE1(0), - .ngpio = EXYNOS4_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE2(0), - .ngpio = EXYNOS4_GPIO_E2_NR, - .label = "GPE2", - }, - }, { - .chip = { - .base = EXYNOS4_GPE3(0), - .ngpio = EXYNOS4_GPIO_E3_NR, - .label = "GPE3", - }, - }, { - .chip = { - .base = EXYNOS4_GPE4(0), - .ngpio = EXYNOS4_GPIO_E4_NR, - .label = "GPE4", - }, - }, { - .chip = { - .base = EXYNOS4_GPF0(0), - .ngpio = EXYNOS4_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = EXYNOS4_GPF1(0), - .ngpio = EXYNOS4_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = EXYNOS4_GPF2(0), - .ngpio = EXYNOS4_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = EXYNOS4_GPF3(0), - .ngpio = EXYNOS4_GPIO_F3_NR, - .label = "GPF3", - }, - }, -}; -#endif - -#ifdef CONFIG_ARCH_EXYNOS4 -static struct samsung_gpio_chip exynos4_gpios_2[] = { - { - .chip = { - .base = EXYNOS4_GPJ0(0), - .ngpio = EXYNOS4_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = EXYNOS4_GPJ1(0), - .ngpio = EXYNOS4_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK0(0), - .ngpio = EXYNOS4_GPIO_K0_NR, - .label = "GPK0", - }, - }, { - .chip = { - .base = EXYNOS4_GPK1(0), - .ngpio = EXYNOS4_GPIO_K1_NR, - .label = "GPK1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK2(0), - .ngpio = EXYNOS4_GPIO_K2_NR, - .label = "GPK2", - }, - }, { - .chip = { - .base = EXYNOS4_GPK3(0), - .ngpio = EXYNOS4_GPIO_K3_NR, - .label = "GPK3", - }, - }, { - .chip = { - .base = EXYNOS4_GPL0(0), - .ngpio = EXYNOS4_GPIO_L0_NR, - .label = "GPL0", - }, - }, { - .chip = { - .base = EXYNOS4_GPL1(0), - .ngpio = EXYNOS4_GPIO_L1_NR, - .label = "GPL1", - }, - }, { - .chip = { - .base = EXYNOS4_GPL2(0), - .ngpio = EXYNOS4_GPIO_L2_NR, - .label = "GPL2", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY0(0), - .ngpio = EXYNOS4_GPIO_Y0_NR, - .label = "GPY0", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY1(0), - .ngpio = EXYNOS4_GPIO_Y1_NR, - .label = "GPY1", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY2(0), - .ngpio = EXYNOS4_GPIO_Y2_NR, - .label = "GPY2", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY3(0), - .ngpio = EXYNOS4_GPIO_Y3_NR, - .label = "GPY3", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY4(0), - .ngpio = EXYNOS4_GPIO_Y4_NR, - .label = "GPY4", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY5(0), - .ngpio = EXYNOS4_GPIO_Y5_NR, - .label = "GPY5", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY6(0), - .ngpio = EXYNOS4_GPIO_Y6_NR, - .label = "GPY6", - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(0), - .chip = { - .base = EXYNOS4_GPX0(0), - .ngpio = EXYNOS4_GPIO_X0_NR, - .label = "GPX0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(8), - .chip = { - .base = EXYNOS4_GPX1(0), - .ngpio = EXYNOS4_GPIO_X1_NR, - .label = "GPX1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(16), - .chip = { - .base = EXYNOS4_GPX2(0), - .ngpio = EXYNOS4_GPIO_X2_NR, - .label = "GPX2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(24), - .chip = { - .base = EXYNOS4_GPX3(0), - .ngpio = EXYNOS4_GPIO_X3_NR, - .label = "GPX3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; -#endif - -#ifdef CONFIG_ARCH_EXYNOS4 -static struct samsung_gpio_chip exynos4_gpios_3[] = { - { - .chip = { - .base = EXYNOS4_GPZ(0), - .ngpio = EXYNOS4_GPIO_Z_NR, - .label = "GPZ", - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_1[] = { - { - .chip = { - .base = EXYNOS5_GPA0(0), - .ngpio = EXYNOS5_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = EXYNOS5_GPA1(0), - .ngpio = EXYNOS5_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = EXYNOS5_GPA2(0), - .ngpio = EXYNOS5_GPIO_A2_NR, - .label = "GPA2", - }, - }, { - .chip = { - .base = EXYNOS5_GPB0(0), - .ngpio = EXYNOS5_GPIO_B0_NR, - .label = "GPB0", - }, - }, { - .chip = { - .base = EXYNOS5_GPB1(0), - .ngpio = EXYNOS5_GPIO_B1_NR, - .label = "GPB1", - }, - }, { - .chip = { - .base = EXYNOS5_GPB2(0), - .ngpio = EXYNOS5_GPIO_B2_NR, - .label = "GPB2", - }, - }, { - .chip = { - .base = EXYNOS5_GPB3(0), - .ngpio = EXYNOS5_GPIO_B3_NR, - .label = "GPB3", - }, - }, { - .chip = { - .base = EXYNOS5_GPC0(0), - .ngpio = EXYNOS5_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = EXYNOS5_GPC1(0), - .ngpio = EXYNOS5_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = EXYNOS5_GPC2(0), - .ngpio = EXYNOS5_GPIO_C2_NR, - .label = "GPC2", - }, - }, { - .chip = { - .base = EXYNOS5_GPC3(0), - .ngpio = EXYNOS5_GPIO_C3_NR, - .label = "GPC3", - }, - }, { - .chip = { - .base = EXYNOS5_GPD0(0), - .ngpio = EXYNOS5_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = EXYNOS5_GPD1(0), - .ngpio = EXYNOS5_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = EXYNOS5_GPY0(0), - .ngpio = EXYNOS5_GPIO_Y0_NR, - .label = "GPY0", - }, - }, { - .chip = { - .base = EXYNOS5_GPY1(0), - .ngpio = EXYNOS5_GPIO_Y1_NR, - .label = "GPY1", - }, - }, { - .chip = { - .base = EXYNOS5_GPY2(0), - .ngpio = EXYNOS5_GPIO_Y2_NR, - .label = "GPY2", - }, - }, { - .chip = { - .base = EXYNOS5_GPY3(0), - .ngpio = EXYNOS5_GPIO_Y3_NR, - .label = "GPY3", - }, - }, { - .chip = { - .base = EXYNOS5_GPY4(0), - .ngpio = EXYNOS5_GPIO_Y4_NR, - .label = "GPY4", - }, - }, { - .chip = { - .base = EXYNOS5_GPY5(0), - .ngpio = EXYNOS5_GPIO_Y5_NR, - .label = "GPY5", - }, - }, { - .chip = { - .base = EXYNOS5_GPY6(0), - .ngpio = EXYNOS5_GPIO_Y6_NR, - .label = "GPY6", - }, - }, { - .chip = { - .base = EXYNOS5_GPC4(0), - .ngpio = EXYNOS5_GPIO_C4_NR, - .label = "GPC4", - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(0), - .chip = { - .base = EXYNOS5_GPX0(0), - .ngpio = EXYNOS5_GPIO_X0_NR, - .label = "GPX0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(8), - .chip = { - .base = EXYNOS5_GPX1(0), - .ngpio = EXYNOS5_GPIO_X1_NR, - .label = "GPX1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(16), - .chip = { - .base = EXYNOS5_GPX2(0), - .ngpio = EXYNOS5_GPIO_X2_NR, - .label = "GPX2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(24), - .chip = { - .base = EXYNOS5_GPX3(0), - .ngpio = EXYNOS5_GPIO_X3_NR, - .label = "GPX3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_2[] = { - { - .chip = { - .base = EXYNOS5_GPE0(0), - .ngpio = EXYNOS5_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = EXYNOS5_GPE1(0), - .ngpio = EXYNOS5_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = EXYNOS5_GPF0(0), - .ngpio = EXYNOS5_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = EXYNOS5_GPF1(0), - .ngpio = EXYNOS5_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = EXYNOS5_GPG0(0), - .ngpio = EXYNOS5_GPIO_G0_NR, - .label = "GPG0", - }, - }, { - .chip = { - .base = EXYNOS5_GPG1(0), - .ngpio = EXYNOS5_GPIO_G1_NR, - .label = "GPG1", - }, - }, { - .chip = { - .base = EXYNOS5_GPG2(0), - .ngpio = EXYNOS5_GPIO_G2_NR, - .label = "GPG2", - }, - }, { - .chip = { - .base = EXYNOS5_GPH0(0), - .ngpio = EXYNOS5_GPIO_H0_NR, - .label = "GPH0", - }, - }, { - .chip = { - .base = EXYNOS5_GPH1(0), - .ngpio = EXYNOS5_GPIO_H1_NR, - .label = "GPH1", - - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_3[] = { - { - .chip = { - .base = EXYNOS5_GPV0(0), - .ngpio = EXYNOS5_GPIO_V0_NR, - .label = "GPV0", - }, - }, { - .chip = { - .base = EXYNOS5_GPV1(0), - .ngpio = EXYNOS5_GPIO_V1_NR, - .label = "GPV1", - }, - }, { - .chip = { - .base = EXYNOS5_GPV2(0), - .ngpio = EXYNOS5_GPIO_V2_NR, - .label = "GPV2", - }, - }, { - .chip = { - .base = EXYNOS5_GPV3(0), - .ngpio = EXYNOS5_GPIO_V3_NR, - .label = "GPV3", - }, - }, { - .chip = { - .base = EXYNOS5_GPV4(0), - .ngpio = EXYNOS5_GPIO_V4_NR, - .label = "GPV4", - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_4[] = { - { - .chip = { - .base = EXYNOS5_GPZ(0), - .ngpio = EXYNOS5_GPIO_Z_NR, - .label = "GPZ", - }, - }, -}; -#endif - - -#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) -static int exynos_gpio_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, u32 *flags) -{ - unsigned int pin; - - if (WARN_ON(gc->of_gpio_n_cells < 4)) - return -EINVAL; - - if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) - return -EINVAL; - - if (gpiospec->args[0] > gc->ngpio) - return -EINVAL; - - pin = gc->base + gpiospec->args[0]; - - if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) - pr_warn("gpio_xlate: failed to set pin function\n"); - if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) - pr_warn("gpio_xlate: failed to set pin pull up/down\n"); - if (s5p_gpio_set_drvstr(pin, gpiospec->args[3])) - pr_warn("gpio_xlate: failed to set pin drive strength\n"); - - if (flags) - *flags = gpiospec->args[2] >> 16; - - return gpiospec->args[0]; -} - -static const struct of_device_id exynos_gpio_dt_match[] __initdata = { - { .compatible = "samsung,exynos4-gpio", }, - {} -}; - -static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) -{ - struct gpio_chip *gc = &chip->chip; - u64 address; - - if (!of_have_populated_dt()) - return; - - address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; - gc->of_node = of_find_matching_node_by_address(NULL, - exynos_gpio_dt_match, address); - if (!gc->of_node) { - pr_info("gpio: device tree node not found for gpio controller" - " with base address %08llx\n", address); - return; - } - gc->of_gpio_n_cells = 4; - gc->of_xlate = exynos_gpio_xlate; -} -#elif defined(CONFIG_ARCH_EXYNOS) -static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) -{ - return; -} -#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */ - -static __init void exynos4_gpiolib_init(void) -{ -#ifdef CONFIG_CPU_EXYNOS4210 - struct samsung_gpio_chip *chip; - int i, nr_chips; - void __iomem *gpio_base1, *gpio_base2, *gpio_base3; - int group = 0; - void __iomem *gpx_base; - - /* gpio part1 */ - gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); - if (gpio_base1 == NULL) { - pr_err("unable to ioremap for gpio_base1\n"); - goto err_ioremap1; - } - - chip = exynos4_gpios_1; - nr_chips = ARRAY_SIZE(exynos4_gpios_1); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO1, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, - nr_chips, gpio_base1); - - /* gpio part2 */ - gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); - if (gpio_base2 == NULL) { - pr_err("unable to ioremap for gpio_base2\n"); - goto err_ioremap2; - } - - /* need to set base address for gpx */ - chip = &exynos4_gpios_2[16]; - gpx_base = gpio_base2 + 0xC00; - for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) - chip->base = gpx_base; - - chip = exynos4_gpios_2; - nr_chips = ARRAY_SIZE(exynos4_gpios_2); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO2, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, - nr_chips, gpio_base2); - - /* gpio part3 */ - gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256); - if (gpio_base3 == NULL) { - pr_err("unable to ioremap for gpio_base3\n"); - goto err_ioremap3; - } - - chip = exynos4_gpios_3; - nr_chips = ARRAY_SIZE(exynos4_gpios_3); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO3, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, - nr_chips, gpio_base3); - -#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT) - s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); - s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); -#endif - - return; - -err_ioremap3: - iounmap(gpio_base2); -err_ioremap2: - iounmap(gpio_base1); -err_ioremap1: - return; -#endif /* CONFIG_CPU_EXYNOS4210 */ -} - -static __init void exynos5_gpiolib_init(void) -{ -#ifdef CONFIG_SOC_EXYNOS5250 - struct samsung_gpio_chip *chip; - int i, nr_chips; - void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; - int group = 0; - void __iomem *gpx_base; - - /* gpio part1 */ - gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); - if (gpio_base1 == NULL) { - pr_err("unable to ioremap for gpio_base1\n"); - goto err_ioremap1; - } - - /* need to set base address for gpc4 */ - exynos5_gpios_1[20].base = gpio_base1 + 0x2E0; - - /* need to set base address for gpx */ - chip = &exynos5_gpios_1[21]; - gpx_base = gpio_base1 + 0xC00; - for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) - chip->base = gpx_base; - - chip = exynos5_gpios_1; - nr_chips = ARRAY_SIZE(exynos5_gpios_1); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO1, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_1, - nr_chips, gpio_base1); - - /* gpio part2 */ - gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K); - if (gpio_base2 == NULL) { - pr_err("unable to ioremap for gpio_base2\n"); - goto err_ioremap2; - } - - chip = exynos5_gpios_2; - nr_chips = ARRAY_SIZE(exynos5_gpios_2); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO2, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_2, - nr_chips, gpio_base2); - - /* gpio part3 */ - gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K); - if (gpio_base3 == NULL) { - pr_err("unable to ioremap for gpio_base3\n"); - goto err_ioremap3; - } - - /* need to set base address for gpv */ - exynos5_gpios_3[0].base = gpio_base3; - exynos5_gpios_3[1].base = gpio_base3 + 0x20; - exynos5_gpios_3[2].base = gpio_base3 + 0x60; - exynos5_gpios_3[3].base = gpio_base3 + 0x80; - exynos5_gpios_3[4].base = gpio_base3 + 0xC0; - - chip = exynos5_gpios_3; - nr_chips = ARRAY_SIZE(exynos5_gpios_3); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO3, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_3, - nr_chips, gpio_base3); - - /* gpio part4 */ - gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K); - if (gpio_base4 == NULL) { - pr_err("unable to ioremap for gpio_base4\n"); - goto err_ioremap4; - } - - chip = exynos5_gpios_4; - nr_chips = ARRAY_SIZE(exynos5_gpios_4); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO4, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_4, - nr_chips, gpio_base4); - return; - -err_ioremap4: - iounmap(gpio_base3); -err_ioremap3: - iounmap(gpio_base2); -err_ioremap2: - iounmap(gpio_base1); -err_ioremap1: - return; - -#endif /* CONFIG_SOC_EXYNOS5250 */ -} - /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { @@ -3040,10 +2173,6 @@ static __init int samsung_gpiolib_init(void) #if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT) s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); #endif - } else if (soc_is_exynos4210()) { - exynos4_gpiolib_init(); - } else if (soc_is_exynos5250()) { - exynos5_gpiolib_init(); } else { WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); return -ENODEV; -- cgit v1.2.3 From 45971686967e252e800992bb23f3f9809ceece38 Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Wed, 28 Aug 2013 10:38:50 +0200 Subject: gpio: mcp23s08: rename the device tree property The device tree property should be more descriptive. microchip seems more reasonable than mcp. The old mcp prefix is still supported but marked as deprecated. Users of mcp have to switch to the microchip prefix. Acked-by: Mark Rutland Signed-off-by: Lars Poeschel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mcp23s08.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index d96bf8a76f5c..2deb0c5e54a4 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -483,10 +483,21 @@ fail: #ifdef CONFIG_SPI_MASTER static struct of_device_id mcp23s08_spi_of_match[] = { { - .compatible = "mcp,mcp23s08", .data = (void *) MCP_TYPE_S08, + .compatible = "microchip,mcp23s08", + .data = (void *) MCP_TYPE_S08, }, { - .compatible = "mcp,mcp23s17", .data = (void *) MCP_TYPE_S17, + .compatible = "microchip,mcp23s17", + .data = (void *) MCP_TYPE_S17, + }, +/* NOTE: The use of the mcp prefix is deprecated and will be removed. */ + { + .compatible = "mcp,mcp23s08", + .data = (void *) MCP_TYPE_S08, + }, + { + .compatible = "mcp,mcp23s17", + .data = (void *) MCP_TYPE_S17, }, { }, }; @@ -496,10 +507,21 @@ MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match); #if IS_ENABLED(CONFIG_I2C) static struct of_device_id mcp23s08_i2c_of_match[] = { { - .compatible = "mcp,mcp23008", .data = (void *) MCP_TYPE_008, + .compatible = "microchip,mcp23008", + .data = (void *) MCP_TYPE_008, + }, + { + .compatible = "microchip,mcp23017", + .data = (void *) MCP_TYPE_017, }, +/* NOTE: The use of the mcp prefix is deprecated and will be removed. */ { - .compatible = "mcp,mcp23017", .data = (void *) MCP_TYPE_017, + .compatible = "mcp,mcp23008", + .data = (void *) MCP_TYPE_008, + }, + { + .compatible = "mcp,mcp23017", + .data = (void *) MCP_TYPE_017, }, { }, }; @@ -620,10 +642,15 @@ static int mcp23s08_probe(struct spi_device *spi) if (match) { type = (int)match->data; status = of_property_read_u32(spi->dev.of_node, - "mcp,spi-present-mask", &spi_present_mask); + "microchip,spi-present-mask", &spi_present_mask); if (status) { - dev_err(&spi->dev, "DT has no spi-present-mask\n"); - return -ENODEV; + status = of_property_read_u32(spi->dev.of_node, + "mcp,spi-present-mask", &spi_present_mask); + if (status) { + dev_err(&spi->dev, + "DT has no spi-present-mask\n"); + return -ENODEV; + } } if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) { dev_err(&spi->dev, "invalid spi-present-mask\n"); -- cgit v1.2.3 From 6c17aa0138a6c55364936bbaa35846e09a4db53b Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Thu, 29 Aug 2013 22:56:56 +0200 Subject: gpio: add GPIO support for F71882FG and F71889F This patch adds support for the GPIOs found on the Fintek super-I/O chips F71882FG and F71889F. A super-I/O is a legacy I/O controller embedded on x86 motherboards. It is used to connect the low-bandwidth devices. Among others functions the F71882FG/F71889F provides: a parallel port, two serial ports, a keyboard controller, an hardware monitoring controller and some GPIO pins. Note that this super-I/Os are embedded on some Atom-based LaCie NASes. The GPIOs are used to control the LEDs and the hard drive power. Changes since v3: - Use request_muxed_region to protect the I/O ports against concurrent accesses. Changes since v2: - Remove useless NULL setters for driver data. Changes since v1: - Enhance the commit message by describing what is a Super-I/O. - Use self-explanatory names for the GPIO register macros. - Add a comment to explain the platform device and driver registration. - Fix gpio_get when GPIO is configured in input mode. I only had the hardware to check this mode recently... Signed-off-by: Simon Guinot Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f7188x.c | 469 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 480 insertions(+) create mode 100644 drivers/gpio/gpio-f7188x.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4b7ba53e96db..349b16160ac9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -146,6 +146,16 @@ config GPIO_MM_LANTIQ (EBU) found on Lantiq SoCs. The gpios are output only as they are created by attaching a 16bit latch to the bus. +config GPIO_F7188X + tristate "F71882FG and F71889F GPIO support" + depends on X86 + help + This option enables support for GPIOs found on Fintek Super-I/O + chips F71882FG and F71889F. + + To compile this driver as a module, choose M here: the module will + be called f7188x-gpio. + config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 156fd283945c..97438bf8434a 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c new file mode 100644 index 000000000000..9cb8320e1181 --- /dev/null +++ b/drivers/gpio/gpio-f7188x.c @@ -0,0 +1,469 @@ +/* + * GPIO driver for Fintek Super-I/O F71882 and F71889 + * + * Copyright (C) 2010-2013 LaCie + * + * Author: Simon Guinot + * + * 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. + */ + +#include +#include +#include +#include +#include + +#define DRVNAME "gpio-f7188x" + +/* + * Super-I/O registers + */ +#define SIO_LDSEL 0x07 /* Logical device select */ +#define SIO_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_DEVREV 0x22 /* Device revision */ +#define SIO_MANID 0x23 /* Fintek ID (2 bytes) */ + +#define SIO_LD_GPIO 0x06 /* GPIO logical device */ +#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ +#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ + +#define SIO_FINTEK_ID 0x1934 /* Manufacturer ID */ +#define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ +#define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ + +enum chips { f71882fg, f71889f }; + +static const char * const f7188x_names[] = { + "f71882fg", + "f71889f", +}; + +struct f7188x_sio { + int addr; + enum chips type; +}; + +struct f7188x_gpio_bank { + struct gpio_chip chip; + unsigned int regbase; + struct f7188x_gpio_data *data; +}; + +struct f7188x_gpio_data { + struct f7188x_sio *sio; + int nr_bank; + struct f7188x_gpio_bank *bank; +}; + +/* + * Super-I/O functions. + */ + +static inline int superio_inb(int base, int reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static int superio_inw(int base, int reg) +{ + int val; + + outb(reg++, base); + val = inb(base + 1) << 8; + outb(reg, base); + val |= inb(base + 1); + + return val; +} + +static inline void superio_outb(int base, int reg, int val) +{ + outb(reg, base); + outb(val, base + 1); +} + +static inline int superio_enter(int base) +{ + /* Don't step on other drivers' I/O space by accident. */ + if (!request_muxed_region(base, 2, DRVNAME)) { + pr_err(DRVNAME "I/O address 0x%04x already in use\n", base); + return -EBUSY; + } + + /* According to the datasheet the key must be send twice. */ + outb(SIO_UNLOCK_KEY, base); + outb(SIO_UNLOCK_KEY, base); + + return 0; +} + +static inline void superio_select(int base, int ld) +{ + outb(SIO_LDSEL, base); + outb(ld, base + 1); +} + +static inline void superio_exit(int base) +{ + outb(SIO_LOCK_KEY, base); + release_region(base, 2); +} + +/* + * GPIO chip. + */ + +static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset); +static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset); +static int f7188x_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value); +static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); + +#define F7188X_GPIO_BANK(_base, _ngpio, _regbase) \ + { \ + .chip = { \ + .label = DRVNAME, \ + .owner = THIS_MODULE, \ + .direction_input = f7188x_gpio_direction_in, \ + .get = f7188x_gpio_get, \ + .direction_output = f7188x_gpio_direction_out, \ + .set = f7188x_gpio_set, \ + .base = _base, \ + .ngpio = _ngpio, \ + }, \ + .regbase = _regbase, \ + } + +#define gpio_dir(base) (base + 0) +#define gpio_data_out(base) (base + 1) +#define gpio_data_in(base) (base + 2) +/* Output mode register (0:open drain 1:push-pull). */ +#define gpio_out_mode(base) (base + 3) + +static struct f7188x_gpio_bank f71882_gpio_bank[] = { + F7188X_GPIO_BANK(0 , 8, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 4, 0xC0), + F7188X_GPIO_BANK(40, 4, 0xB0), +}; + +static struct f7188x_gpio_bank f71889_gpio_bank[] = { + F7188X_GPIO_BANK(0 , 7, 0xF0), + F7188X_GPIO_BANK(10, 7, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 5, 0xA0), + F7188X_GPIO_BANK(60, 8, 0x90), + F7188X_GPIO_BANK(70, 8, 0x80), +}; + +static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 dir; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + dir &= ~(1 << offset); + superio_outb(sio->addr, gpio_dir(bank->regbase), dir); + + superio_exit(sio->addr); + + return 0; +} + +static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 dir, data; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + dir = !!(dir & (1 << offset)); + if (dir) + data = superio_inb(sio->addr, gpio_data_out(bank->regbase)); + else + data = superio_inb(sio->addr, gpio_data_in(bank->regbase)); + + superio_exit(sio->addr); + + return !!(data & 1 << offset); +} + +static int f7188x_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 dir, data_out; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); + if (value) + data_out |= (1 << offset); + else + data_out &= ~(1 << offset); + superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); + + dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + dir |= (1 << offset); + superio_outb(sio->addr, gpio_dir(bank->regbase), dir); + + superio_exit(sio->addr); + + return 0; +} + +static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 data_out; + + err = superio_enter(sio->addr); + if (err) + return; + superio_select(sio->addr, SIO_LD_GPIO); + + data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); + if (value) + data_out |= (1 << offset); + else + data_out &= ~(1 << offset); + superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); + + superio_exit(sio->addr); +} + +/* + * Platform device and driver. + */ + +static int f7188x_gpio_probe(struct platform_device *pdev) +{ + int err; + int i; + struct f7188x_sio *sio = pdev->dev.platform_data; + struct f7188x_gpio_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + switch (sio->type) { + case f71882fg: + data->nr_bank = ARRAY_SIZE(f71882_gpio_bank); + data->bank = f71882_gpio_bank; + break; + case f71889f: + data->nr_bank = ARRAY_SIZE(f71889_gpio_bank); + data->bank = f71889_gpio_bank; + break; + default: + return -ENODEV; + } + data->sio = sio; + + platform_set_drvdata(pdev, data); + + /* For each GPIO bank, register a GPIO chip. */ + for (i = 0; i < data->nr_bank; i++) { + struct f7188x_gpio_bank *bank = &data->bank[i]; + + bank->chip.dev = &pdev->dev; + bank->data = data; + + err = gpiochip_add(&bank->chip); + if (err) { + dev_err(&pdev->dev, + "Failed to register gpiochip %d: %d\n", + i, err); + goto err_gpiochip; + } + } + + return 0; + +err_gpiochip: + for (i = i - 1; i >= 0; i--) { + struct f7188x_gpio_bank *bank = &data->bank[i]; + int tmp; + + tmp = gpiochip_remove(&bank->chip); + if (tmp < 0) + dev_err(&pdev->dev, + "Failed to remove gpiochip %d: %d\n", + i, tmp); + } + + return err; +} + +static int f7188x_gpio_remove(struct platform_device *pdev) +{ + int err; + int i; + struct f7188x_gpio_data *data = platform_get_drvdata(pdev); + + for (i = 0; i < data->nr_bank; i++) { + struct f7188x_gpio_bank *bank = &data->bank[i]; + + err = gpiochip_remove(&bank->chip); + if (err) { + dev_err(&pdev->dev, + "Failed to remove GPIO gpiochip %d: %d\n", + i, err); + return err; + } + } + + return 0; +} + +static int __init f7188x_find(int addr, struct f7188x_sio *sio) +{ + int err; + u16 devid; + + err = superio_enter(addr); + if (err) + return err; + + err = -ENODEV; + devid = superio_inw(addr, SIO_MANID); + if (devid != SIO_FINTEK_ID) { + pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr); + goto err; + } + + devid = superio_inw(addr, SIO_DEVID); + switch (devid) { + case SIO_F71882_ID: + sio->type = f71882fg; + break; + case SIO_F71889_ID: + sio->type = f71889f; + break; + default: + pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid); + goto err; + } + sio->addr = addr; + err = 0; + + pr_info(DRVNAME ": Found %s at %#x, revision %d\n", + f7188x_names[sio->type], + (unsigned int) addr, + (int) superio_inb(addr, SIO_DEVREV)); + +err: + superio_exit(addr); + return err; +} + +static struct platform_device *f7188x_gpio_pdev; + +static int __init +f7188x_gpio_device_add(const struct f7188x_sio *sio) +{ + int err; + + f7188x_gpio_pdev = platform_device_alloc(DRVNAME, -1); + if (!f7188x_gpio_pdev) + return -ENOMEM; + + err = platform_device_add_data(f7188x_gpio_pdev, + sio, sizeof(*sio)); + if (err) { + pr_err(DRVNAME "Platform data allocation failed\n"); + goto err; + } + + err = platform_device_add(f7188x_gpio_pdev); + if (err) { + pr_err(DRVNAME "Device addition failed\n"); + goto err; + } + + return 0; + +err: + platform_device_put(f7188x_gpio_pdev); + + return err; +} + +/* + * Try to match a supported Fintech device by reading the (hard-wired) + * configuration I/O ports. If available, then register both the platform + * device and driver to support the GPIOs. + */ + +static struct platform_driver f7188x_gpio_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = f7188x_gpio_probe, + .remove = f7188x_gpio_remove, +}; + +static int __init f7188x_gpio_init(void) +{ + int err; + struct f7188x_sio sio; + + if (f7188x_find(0x2e, &sio) && + f7188x_find(0x4e, &sio)) + return -ENODEV; + + err = platform_driver_register(&f7188x_gpio_driver); + if (!err) { + err = f7188x_gpio_device_add(&sio); + if (err) + platform_driver_unregister(&f7188x_gpio_driver); + } + + return err; +} +subsys_initcall(f7188x_gpio_init); + +static void __exit f7188x_gpio_exit(void) +{ + platform_device_unregister(f7188x_gpio_pdev); + platform_driver_unregister(&f7188x_gpio_driver); +} +module_exit(f7188x_gpio_exit); + +MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71882FG and F71889F"); +MODULE_AUTHOR("Simon Guinot "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From be1a4b13089b1e18da83a549d49163ccad3c19ba Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 30 Aug 2013 09:41:45 +0200 Subject: gpio: improve error path in gpiolib At several places the gpiolib will proceed to handle a GPIO descriptor even if it's ->chip member is NULL and no gpiochip is associated. Fix this by checking that both the descriptor cookie *and* the chip pointer are valid. Also bail out earlier with more specific diagnostic messages on missing operations for setting as input/output or debounce. ChangeLog v1->v2: - Also return -EIO on gpiod_set_debounce() with missing operations in the vtable - Fix indentations. Suggested-by: Alexandre Courbot Acked-by: Alexandre Courbot Reviewed-by: Frank Rowand Cc: Tim Bird Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d6413b2e0844..0cbdddab4ff2 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1398,7 +1398,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) int status = -EPROBE_DEFER; unsigned long flags; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } @@ -1406,8 +1406,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); chip = desc->chip; - if (chip == NULL) - goto done; if (!try_module_get(chip->owner)) goto done; @@ -1630,16 +1628,20 @@ static int gpiod_direction_input(struct gpio_desc *desc) int status = -EINVAL; int offset; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } + chip = desc->chip; + if (!chip->get || !chip->direction_input) { + pr_warn("%s: missing get() or direction_input() operations\n", + __func__); + return -EIO; + } + spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (!chip || !chip->get || !chip->direction_input) - goto fail; status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1691,7 +1693,7 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) int status = -EINVAL; int offset; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } @@ -1704,11 +1706,15 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) return gpiod_direction_input(desc); + chip = desc->chip; + if (!chip->set || !chip->direction_output) { + pr_warn("%s: missing set() or direction_output() operations\n", + __func__); + return -EIO; + } + spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (!chip || !chip->set || !chip->direction_output) - goto fail; status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1765,16 +1771,19 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) int status = -EINVAL; int offset; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } - spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (!chip || !chip->set || !chip->set_debounce) - goto fail; + if (!chip->set || !chip->set_debounce) { + pr_warn("%s: missing set() or set_debounce() operations\n", + __func__); + return -EIO; + } + + spin_lock_irqsave(&gpio_lock, flags); status = gpio_ensure_requested(desc); if (status < 0) -- cgit v1.2.3 From 65d876564e989b63b0f769e0e06b9830db97b2d9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 4 Sep 2013 14:17:08 +0200 Subject: gpio: return -ENOTSUPP if debounce cannot be set It appears some drivers are using gpio_set_debounce() opportunistically, i.e. without knowing whether it works or not. (Example: input/keyboard/gpio_keys.c) to account for this use case, return -ENOTSUPP and do not print any warnings in this case. Took a round over the other gpio_set_debounce() consumers to make sure that none of them are relying on the returned error code to be something specific. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0cbdddab4ff2..86ef3461ec06 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1763,6 +1763,9 @@ EXPORT_SYMBOL_GPL(gpio_direction_output); * gpio_set_debounce - sets @debounce time for a @gpio * @gpio: the gpio to set debounce time * @debounce: debounce time is microseconds + * + * returns -ENOTSUPP if the controller does not support setting + * debounce. */ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { @@ -1778,9 +1781,9 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) chip = desc->chip; if (!chip->set || !chip->set_debounce) { - pr_warn("%s: missing set() or set_debounce() operations\n", + pr_debug("%s: missing set() or set_debounce() operations\n", __func__); - return -EIO; + return -ENOTSUPP; } spin_lock_irqsave(&gpio_lock, flags); -- cgit v1.2.3