diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 13:25:35 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 13:25:35 -0700 |
commit | d2033f2c1d1de2239ded15e478ddb4028f192a15 (patch) | |
tree | d60e4f447134ca008ef212c04f0e75256681ed04 /drivers/gpio | |
parent | 22237d5a588cfad92525d2998ff14d3666399dce (diff) | |
parent | 0ee8090c1d059eca4d60e8e473bee91fb5d1996b (diff) |
Merge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC cleanups from Arnd Bergmann:
"This contains cleanups as preparation for other branches adding new
features, we pulled 16 branches for 9 platforms into this one.
Most notable here is the removal of support for ATAGS based OMAP4
systems. Since all OMAP4 machines are fully functional with DT based
booting in 3.10, we can remove a lot of code here.
Also noteworthy is Maxime Ripard's cleanup of the machine descriptors,
which means we need no machine descriptors in a lot more cases and can
boot additional machines by just having the respective device drivers
enabled."
* tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (76 commits)
ARM: picoxcell: remove .nr_irqs reference
ARM: s5p64x0: avoid build warning for uncompress.h
ARM: SAMSUNG: Remove unused plat/regs-watchdog.h header
ARM: SAMSUNG: Remove legacy watchdog reset code
ARM: SAMSUNG: Let platforms use the new watchdog reset driver
ARM: SAMSUNG: Add watchdog reset driver
ARM: SAMSUNG: Use local definitions of watchdog registers
watchdog: s3c2410_wdt: Use local register definitions
ARM: S5P64X0: Use common uncompress.h part for plat-samsung
ARM: SAMSUNG: Consolidate uncompress subroutine
ARM: at91: drop rm9200dk board support
ARM: dts: msm: Fix merge resolution
ARM: OMAP1: Remove dma.h
ARM: OMAP1: Remove legacy irda.h and irda setup from board files
ARM: OMAP1: Remove duplicated DMA channel definitions
ARM: OMAP1: Remove McBSP DMA channel definitions
ARM: OMAP2+: Remove dma.h
ARM: OMAP2+: hwmod: Remove remaining DMA channel definitions
ARM: OMAP2+: Remove duplicated DMA channel definitions
ARM: OMAP2+: Remove AES crypto device DMA channel definitions
...
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-msm-v2.c | 195 |
2 files changed, 116 insertions, 81 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 573c449c49b9..847a6dc15a54 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -165,7 +165,7 @@ config GPIO_MSM_V1 config GPIO_MSM_V2 tristate "Qualcomm MSM GPIO v2" - depends on GPIOLIB && ARCH_MSM + depends on GPIOLIB && OF && ARCH_MSM help Say yes here to support the GPIO interface on ARM v7 based Qualcomm MSM chips. Most of the pins on the MSM can be diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index dd2eddeb1e0c..f4491a497cc8 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -19,18 +19,21 @@ #include <linux/bitmap.h> #include <linux/bitops.h> +#include <linux/err.h> #include <linux/gpio.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irqchip/chained_irq.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/module.h> +#include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/spinlock.h> +#include <linux/slab.h> -#include <mach/msm_gpiomux.h> -#include <mach/msm_iomap.h> +#define MAX_NR_GPIO 300 /* Bits of interest in the GPIO_IN_OUT register. */ @@ -77,13 +80,6 @@ enum { TARGET_PROC_NONE = 7, }; - -#define GPIO_INTR_CFG_SU(gpio) (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio))) -#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio))) -#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio))) -#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio))) -#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio))) - /** * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure * @@ -102,11 +98,27 @@ enum { */ struct msm_gpio_dev { struct gpio_chip gpio_chip; - DECLARE_BITMAP(enabled_irqs, NR_GPIO_IRQS); - DECLARE_BITMAP(wake_irqs, NR_GPIO_IRQS); - DECLARE_BITMAP(dual_edge_irqs, NR_GPIO_IRQS); + DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); + DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO); + DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); + struct irq_domain *domain; + unsigned int summary_irq; + void __iomem *msm_tlmm_base; }; +struct msm_gpio_dev msm_gpio; + +#define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \ + (0x04 * (gpio))) +#define GPIO_CONFIG(gpio) (msm_gpio.msm_tlmm_base + 0x1000 + \ + (0x10 * (gpio))) +#define GPIO_IN_OUT(gpio) (msm_gpio.msm_tlmm_base + 0x1004 + \ + (0x10 * (gpio))) +#define GPIO_INTR_CFG(gpio) (msm_gpio.msm_tlmm_base + 0x1008 + \ + (0x10 * (gpio))) +#define GPIO_INTR_STATUS(gpio) (msm_gpio.msm_tlmm_base + 0x100c + \ + (0x10 * (gpio))) + static DEFINE_SPINLOCK(tlmm_lock); static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip) @@ -159,37 +171,29 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, static int msm_gpio_request(struct gpio_chip *chip, unsigned offset) { - return msm_gpiomux_get(chip->base + offset); + return 0; } static void msm_gpio_free(struct gpio_chip *chip, unsigned offset) { - msm_gpiomux_put(chip->base + offset); + return; } static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return MSM_GPIO_TO_INT(chip->base + offset); + struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip); + struct irq_domain *domain = g_dev->domain; + + return irq_create_mapping(domain, offset); } static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq) { - return irq - MSM_GPIO_TO_INT(chip->base); + struct irq_data *irq_data = irq_get_irq_data(irq); + + return irq_data->hwirq; } -static struct msm_gpio_dev msm_gpio = { - .gpio_chip = { - .base = 0, - .ngpio = NR_GPIO_IRQS, - .direction_input = msm_gpio_direction_input, - .direction_output = msm_gpio_direction_output, - .get = msm_gpio_get, - .set = msm_gpio_set, - .to_irq = msm_gpio_to_irq, - .request = msm_gpio_request, - .free = msm_gpio_free, - }, -}; /* For dual-edge interrupts in software, since the hardware has no * such support: @@ -227,9 +231,9 @@ static void msm_gpio_update_dual_edge_pos(unsigned gpio) if (intstat || val == val2) return; } while (loop_limit-- > 0); - pr_err("dual-edge irq failed to stabilize, " + pr_err("%s: dual-edge irq failed to stabilize, " "interrupts dropped. %#08x != %#08x\n", - val, val2); + __func__, val, val2); } static void msm_gpio_irq_ack(struct irq_data *d) @@ -316,10 +320,10 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_enter(chip, desc); - for_each_set_bit(i, msm_gpio.enabled_irqs, NR_GPIO_IRQS) { + for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) { if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS)) - generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip, - i)); + generic_handle_irq(irq_find_mapping(msm_gpio.domain, + i)); } chained_irq_exit(chip, desc); @@ -330,13 +334,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); if (on) { - if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS)) - irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 1); + if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) + irq_set_irq_wake(msm_gpio.summary_irq, 1); set_bit(gpio, msm_gpio.wake_irqs); } else { clear_bit(gpio, msm_gpio.wake_irqs); - if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS)) - irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 0); + if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) + irq_set_irq_wake(msm_gpio.summary_irq, 0); } return 0; @@ -351,30 +355,86 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_set_wake = msm_gpio_irq_set_wake, }; -static int msm_gpio_probe(struct platform_device *dev) +static struct lock_class_key msm_gpio_lock_class; + +static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { - int i, irq, ret; + irq_set_lockdep_class(irq, &msm_gpio_lock_class); + irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, + handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static const struct irq_domain_ops msm_gpio_irq_domain_ops = { + .xlate = irq_domain_xlate_twocell, + .map = msm_gpio_irq_domain_map, +}; + +static int msm_gpio_probe(struct platform_device *pdev) +{ + int ret, ngpio; + struct resource *res; + + if (!of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) { + dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__); + return -EINVAL; + } + + if (ngpio > MAX_NR_GPIO) + WARN(1, "ngpio exceeds the MAX_NR_GPIO. Increase MAX_NR_GPIO\n"); + + bitmap_zero(msm_gpio.enabled_irqs, MAX_NR_GPIO); + bitmap_zero(msm_gpio.wake_irqs, MAX_NR_GPIO); + bitmap_zero(msm_gpio.dual_edge_irqs, MAX_NR_GPIO); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + msm_gpio.msm_tlmm_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(msm_gpio.msm_tlmm_base)) + return PTR_ERR(msm_gpio.msm_tlmm_base); + + msm_gpio.gpio_chip.ngpio = ngpio; + msm_gpio.gpio_chip.label = pdev->name; + msm_gpio.gpio_chip.dev = &pdev->dev; + msm_gpio.gpio_chip.base = 0; + msm_gpio.gpio_chip.direction_input = msm_gpio_direction_input; + msm_gpio.gpio_chip.direction_output = msm_gpio_direction_output; + msm_gpio.gpio_chip.get = msm_gpio_get; + msm_gpio.gpio_chip.set = msm_gpio_set; + msm_gpio.gpio_chip.to_irq = msm_gpio_to_irq; + msm_gpio.gpio_chip.request = msm_gpio_request; + msm_gpio.gpio_chip.free = msm_gpio_free; - bitmap_zero(msm_gpio.enabled_irqs, NR_GPIO_IRQS); - bitmap_zero(msm_gpio.wake_irqs, NR_GPIO_IRQS); - bitmap_zero(msm_gpio.dual_edge_irqs, NR_GPIO_IRQS); - msm_gpio.gpio_chip.label = dev->name; ret = gpiochip_add(&msm_gpio.gpio_chip); - if (ret < 0) + if (ret < 0) { + dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret); return ret; + } - for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) { - irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i); - irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, - handle_level_irq); - set_irq_flags(irq, IRQF_VALID); + msm_gpio.summary_irq = platform_get_irq(pdev, 0); + if (msm_gpio.summary_irq < 0) { + dev_err(&pdev->dev, "No Summary irq defined for msmgpio\n"); + return msm_gpio.summary_irq; } - irq_set_chained_handler(TLMM_SCSS_SUMMARY_IRQ, - msm_summary_irq_handler); + msm_gpio.domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, + &msm_gpio_irq_domain_ops, + &msm_gpio); + if (!msm_gpio.domain) + return -ENODEV; + + irq_set_chained_handler(msm_gpio.summary_irq, msm_summary_irq_handler); + return 0; } +static struct of_device_id msm_gpio_of_match[] = { + { .compatible = "qcom,msm-gpio", }, + { }, +}; + static int msm_gpio_remove(struct platform_device *dev) { int ret = gpiochip_remove(&msm_gpio.gpio_chip); @@ -382,7 +442,7 @@ static int msm_gpio_remove(struct platform_device *dev) if (ret < 0) return ret; - irq_set_handler(TLMM_SCSS_SUMMARY_IRQ, NULL); + irq_set_handler(msm_gpio.summary_irq, NULL); return 0; } @@ -393,36 +453,11 @@ static struct platform_driver msm_gpio_driver = { .driver = { .name = "msmgpio", .owner = THIS_MODULE, + .of_match_table = msm_gpio_of_match, }, }; -static struct platform_device msm_device_gpio = { - .name = "msmgpio", - .id = -1, -}; - -static int __init msm_gpio_init(void) -{ - int rc; - - rc = platform_driver_register(&msm_gpio_driver); - if (!rc) { - rc = platform_device_register(&msm_device_gpio); - if (rc) - platform_driver_unregister(&msm_gpio_driver); - } - - return rc; -} - -static void __exit msm_gpio_exit(void) -{ - platform_device_unregister(&msm_device_gpio); - platform_driver_unregister(&msm_gpio_driver); -} - -postcore_initcall(msm_gpio_init); -module_exit(msm_gpio_exit); +module_platform_driver(msm_gpio_driver) MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>"); MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs"); |