diff options
Diffstat (limited to 'drivers/staging/mt7621-gpio/gpio-mt7621.c')
-rw-r--r-- | drivers/staging/mt7621-gpio/gpio-mt7621.c | 200 |
1 files changed, 109 insertions, 91 deletions
diff --git a/drivers/staging/mt7621-gpio/gpio-mt7621.c b/drivers/staging/mt7621-gpio/gpio-mt7621.c index 51235687ddb6..0c4fb4a1b4a9 100644 --- a/drivers/staging/mt7621-gpio/gpio-mt7621.c +++ b/drivers/staging/mt7621-gpio/gpio-mt7621.c @@ -1,24 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * 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. - * * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2013 John Crispin <blogic@openwrt.org> */ -#include <linux/io.h> #include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of_irq.h> -#include <linux/spinlock.h> -#include <linux/irqdomain.h> -#include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/spinlock.h> -#define MTK_MAX_BANK 3 +#define MTK_BANK_CNT 3 #define MTK_BANK_WIDTH 32 +#define PIN_MASK(nr) (1UL << ((nr % MTK_BANK_WIDTH))) enum mediatek_gpio_reg { GPIO_REG_CTRL = 0, @@ -34,42 +33,47 @@ enum mediatek_gpio_reg { GPIO_REG_EDGE, }; -static void __iomem *mediatek_gpio_membase; -static int mediatek_gpio_irq; -static struct irq_domain *mediatek_gpio_irq_domain; - -static struct mtk_gc { +struct mtk_gc { struct gpio_chip chip; spinlock_t lock; int bank; u32 rising; u32 falling; -} *gc_map[MTK_MAX_BANK]; - -static inline struct mtk_gc -*to_mediatek_gpio(struct gpio_chip *chip) -{ - struct mtk_gc *mgc; +}; - mgc = container_of(chip, struct mtk_gc, chip); +struct mtk_data { + void __iomem *gpio_membase; + int gpio_irq; + struct irq_domain *gpio_irq_domain; + struct mtk_gc gc_map[MTK_BANK_CNT]; +}; - return mgc; +static inline struct mtk_gc * +to_mediatek_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct mtk_gc, chip); } static inline void mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val) { - iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); + struct mtk_data *gpio_data = gpiochip_get_data(&rg->chip); + u32 offset = (reg * 0x10) + (rg->bank * 0x4); + + iowrite32(val, gpio_data->gpio_membase + offset); } static inline u32 mtk_gpio_r32(struct mtk_gc *rg, u8 reg) { - return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); + struct mtk_data *gpio_data = gpiochip_get_data(&rg->chip); + u32 offset = (reg * 0x10) + (rg->bank * 0x4); + + return ioread32(gpio_data->gpio_membase + offset); } static void -mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +mediatek_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct mtk_gc *rg = to_mediatek_gpio(chip); @@ -77,7 +81,7 @@ mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value) } static int -mediatek_gpio_get(struct gpio_chip *chip, unsigned offset) +mediatek_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct mtk_gc *rg = to_mediatek_gpio(chip); @@ -85,7 +89,7 @@ mediatek_gpio_get(struct gpio_chip *chip, unsigned offset) } static int -mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct mtk_gc *rg = to_mediatek_gpio(chip); unsigned long flags; @@ -102,7 +106,7 @@ mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int mediatek_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { struct mtk_gc *rg = to_mediatek_gpio(chip); unsigned long flags; @@ -119,43 +123,37 @@ mediatek_gpio_direction_output(struct gpio_chip *chip, } static int -mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct mtk_gc *rg = to_mediatek_gpio(chip); - unsigned long flags; - u32 t; + u32 t = mtk_gpio_r32(rg, GPIO_REG_CTRL); - spin_lock_irqsave(&rg->lock, flags); - t = mtk_gpio_r32(rg, GPIO_REG_CTRL); - spin_unlock_irqrestore(&rg->lock, flags); - - if (t & BIT(offset)) - return 0; - - return 1; + return (t & BIT(offset)) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; } static int -mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) { + struct mtk_data *gpio_data = gpiochip_get_data(chip); struct mtk_gc *rg = to_mediatek_gpio(chip); - return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH)); + return irq_create_mapping(gpio_data->gpio_irq_domain, + pin + (rg->bank * MTK_BANK_WIDTH)); } static int mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank) { + struct mtk_data *gpio_data = dev_get_drvdata(&pdev->dev); const __be32 *id = of_get_property(bank, "reg", NULL); - struct mtk_gc *rg = devm_kzalloc(&pdev->dev, - sizeof(struct mtk_gc), GFP_KERNEL); + struct mtk_gc *rg; + int ret; - if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK) - return -ENOMEM; + if (!id || be32_to_cpu(*id) >= MTK_BANK_CNT) + return -EINVAL; - gc_map[be32_to_cpu(*id)] = rg; - - memset(rg, 0, sizeof(struct mtk_gc)); + rg = &gpio_data->gc_map[be32_to_cpu(*id)]; + memset(rg, 0, sizeof(*rg)); spin_lock_init(&rg->lock); @@ -169,25 +167,33 @@ mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank) rg->chip.get_direction = mediatek_gpio_get_direction; rg->chip.get = mediatek_gpio_get; rg->chip.set = mediatek_gpio_set; - if (mediatek_gpio_irq_domain) + if (gpio_data->gpio_irq_domain) rg->chip.to_irq = mediatek_gpio_to_irq; rg->bank = be32_to_cpu(*id); + ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio_data); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", + rg->chip.ngpio, ret); + return ret; + } + /* set polarity to low for all gpios */ mtk_gpio_w32(rg, GPIO_REG_POL, 0); dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); - return gpiochip_add(&rg->chip); + return 0; } static void mediatek_gpio_irq_handler(struct irq_desc *desc) { + struct mtk_data *gpio_data = irq_desc_get_handler_data(desc); int i; - for (i = 0; i < MTK_MAX_BANK; i++) { - struct mtk_gc *rg = gc_map[i]; + for (i = 0; i < MTK_BANK_CNT; i++) { + struct mtk_gc *rg = &gpio_data->gc_map[i]; unsigned long pending; int bit; @@ -197,7 +203,8 @@ mediatek_gpio_irq_handler(struct irq_desc *desc) pending = mtk_gpio_r32(rg, GPIO_REG_STAT); for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { - u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit); + u32 map = irq_find_mapping(gpio_data->gpio_irq_domain, + (MTK_BANK_WIDTH * i) + bit); generic_handle_irq(map); mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); @@ -208,52 +215,53 @@ mediatek_gpio_irq_handler(struct irq_desc *desc) static void mediatek_gpio_irq_unmask(struct irq_data *d) { + struct mtk_data *gpio_data = irq_data_get_irq_chip_data(d); int pin = d->hwirq; - int bank = pin / 32; - struct mtk_gc *rg = gc_map[bank]; + int bank = pin / MTK_BANK_WIDTH; + struct mtk_gc *rg = &gpio_data->gc_map[bank]; unsigned long flags; u32 rise, fall; if (!rg) return; + spin_lock_irqsave(&rg->lock, flags); rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); - - spin_lock_irqsave(&rg->lock, flags); - mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising)); - mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (PIN_MASK(pin) & rg->rising)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (PIN_MASK(pin) & rg->falling)); spin_unlock_irqrestore(&rg->lock, flags); } static void mediatek_gpio_irq_mask(struct irq_data *d) { + struct mtk_data *gpio_data = irq_data_get_irq_chip_data(d); int pin = d->hwirq; - int bank = pin / 32; - struct mtk_gc *rg = gc_map[bank]; + int bank = pin / MTK_BANK_WIDTH; + struct mtk_gc *rg = &gpio_data->gc_map[bank]; unsigned long flags; u32 rise, fall; if (!rg) return; + spin_lock_irqsave(&rg->lock, flags); rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); - - spin_lock_irqsave(&rg->lock, flags); - mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq)); - mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~PIN_MASK(pin)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~PIN_MASK(pin)); spin_unlock_irqrestore(&rg->lock, flags); } static int mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) { + struct mtk_data *gpio_data = irq_data_get_irq_chip_data(d); int pin = d->hwirq; - int bank = pin / 32; - struct mtk_gc *rg = gc_map[bank]; - u32 mask = BIT(d->hwirq); + int bank = pin / MTK_BANK_WIDTH; + struct mtk_gc *rg = &gpio_data->gc_map[bank]; + u32 mask = PIN_MASK(pin); if (!rg) return -1; @@ -287,16 +295,23 @@ static struct irq_chip mediatek_gpio_irq_chip = { }; static int -mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) { - irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq); + int ret; + + ret = irq_set_chip_data(irq, d->host_data); + if (ret < 0) + return ret; + irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, + handle_level_irq); irq_set_handler_data(irq, d); return 0; } static const struct irq_domain_ops irq_domain_ops = { - .xlate = irq_domain_xlate_onecell, + .xlate = irq_domain_xlate_twocell, .map = mediatek_gpio_gpio_map, }; @@ -305,32 +320,41 @@ mediatek_gpio_probe(struct platform_device *pdev) { struct device_node *bank, *np = pdev->dev.of_node; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct mtk_data *gpio_data; + + gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL); + if (!gpio_data) + return -ENOMEM; - mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mediatek_gpio_membase)) - return PTR_ERR(mediatek_gpio_membase); + gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio_data->gpio_membase)) + return PTR_ERR(gpio_data->gpio_membase); - mediatek_gpio_irq = irq_of_parse_and_map(np, 0); - if (mediatek_gpio_irq) { - mediatek_gpio_irq_domain = irq_domain_add_linear(np, - MTK_MAX_BANK * MTK_BANK_WIDTH, - &irq_domain_ops, NULL); - if (!mediatek_gpio_irq_domain) + gpio_data->gpio_irq = irq_of_parse_and_map(np, 0); + if (gpio_data->gpio_irq) { + gpio_data->gpio_irq_domain = irq_domain_add_linear(np, + MTK_BANK_CNT * MTK_BANK_WIDTH, + &irq_domain_ops, gpio_data); + if (!gpio_data->gpio_irq_domain) dev_err(&pdev->dev, "irq_domain_add_linear failed\n"); } + platform_set_drvdata(pdev, gpio_data); + for_each_child_of_node(np, bank) - if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank")) + if (of_device_is_compatible(bank, "mediatek,mt7621-gpio-bank")) mediatek_gpio_bank_probe(pdev, bank); - if (mediatek_gpio_irq_domain) - irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler); + if (gpio_data->gpio_irq_domain) + irq_set_chained_handler_and_data(gpio_data->gpio_irq, + mediatek_gpio_irq_handler, + gpio_data); return 0; } static const struct of_device_id mediatek_gpio_match[] = { - { .compatible = "mtk,mt7621-gpio" }, + { .compatible = "mediatek,mt7621-gpio" }, {}, }; MODULE_DEVICE_TABLE(of, mediatek_gpio_match); @@ -343,10 +367,4 @@ static struct platform_driver mediatek_gpio_driver = { }, }; -static int __init -mediatek_gpio_init(void) -{ - return platform_driver_register(&mediatek_gpio_driver); -} - -subsys_initcall(mediatek_gpio_init); +module_platform_driver(mediatek_gpio_driver); |