Message ID | 1530276212-18376-2-git-send-email-sergio.paracuellos@gmail.com |
---|---|
State | New |
Headers | show |
Series | gpio: mediatek: driver for gpio chip in MT7621 SoC | expand |
Looks pretty clean to me. Sorry for not reviewing v1. Smatch (private devel version) points out a little bit of dead code. drivers/staging/mt7621-gpio/gpio-mt7621.c:200 mediatek_gpio_irq_handler() warn: address of 'gpio_data->gc_map[i]' is non-NULL drivers/staging/mt7621-gpio/gpio-mt7621.c:225 mediatek_gpio_irq_unmask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL drivers/staging/mt7621-gpio/gpio-mt7621.c:246 mediatek_gpio_irq_mask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL drivers/staging/mt7621-gpio/gpio-mt7621.c:266 mediatek_gpio_irq_type() warn: address of 'gpio_data->gc_map[bank]' is non-NULL But that's harmless and very minor. regards, dan carpenter -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Jun 29, 2018 at 04:31:35PM +0300, Dan Carpenter wrote: > Looks pretty clean to me. Sorry for not reviewing v1. Smatch (private > devel version) points out a little bit of dead code. > > drivers/staging/mt7621-gpio/gpio-mt7621.c:200 mediatek_gpio_irq_handler() warn: address of 'gpio_data->gc_map[i]' is non-NULL > drivers/staging/mt7621-gpio/gpio-mt7621.c:225 mediatek_gpio_irq_unmask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL > drivers/staging/mt7621-gpio/gpio-mt7621.c:246 mediatek_gpio_irq_mask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL > drivers/staging/mt7621-gpio/gpio-mt7621.c:266 mediatek_gpio_irq_type() warn: address of 'gpio_data->gc_map[bank]' is non-NULL > > But that's harmless and very minor. I think you fixed all these in the non-staging version... That's fine then. regards, dan carpenter -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Jun 29, 2018 at 3:31 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote: > Looks pretty clean to me. Sorry for not reviewing v1. Smatch (private > devel version) points out a little bit of dead code. > > drivers/staging/mt7621-gpio/gpio-mt7621.c:200 mediatek_gpio_irq_handler() warn: address of 'gpio_data->gc_map[i]' is non-NULL > drivers/staging/mt7621-gpio/gpio-mt7621.c:225 mediatek_gpio_irq_unmask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL > drivers/staging/mt7621-gpio/gpio-mt7621.c:246 mediatek_gpio_irq_mask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL > drivers/staging/mt7621-gpio/gpio-mt7621.c:266 mediatek_gpio_irq_type() warn: address of 'gpio_data->gc_map[bank]' is non-NULL > > But that's harmless and very minor. That warnings should not being in the staging version. Last patch series was applied yesterday... Maybe you have not run against the updated tree? This patch fix them: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/commit/?h=staging-testing&id=bfb623c5b0935a2e4b5fe86eab79a37a37b67209 > > regards, > dan carpenter Thanks. Best regards, Sergio Paracuellos > -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Sergio, Thank you for the patch! Yet something to improve: [auto build test ERROR on gpio/for-next] [also build test ERROR on v4.18-rc2 next-20180629] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Sergio-Paracuellos/gpio-mediatek-driver-for-gpio-chip-in-MT7621-SoC/20180629-225420 base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next config: x86_64-randconfig-s0-06292230 (attached as .config) compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 All errors (new ones prefixed by >>): drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe': >> drivers/gpio/gpio-mt7621.c:221:10: error: 'struct gpio_chip' has no member named 'of_node' rg->chip.of_node = node; ^ vim +221 drivers/gpio/gpio-mt7621.c 207 208 static int 209 mediatek_gpio_bank_probe(struct platform_device *pdev, 210 struct device_node *node, int bank) 211 { 212 struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); 213 struct mtk_gc *rg; 214 void __iomem *dat, *set, *ctrl, *diro; 215 int ret; 216 217 rg = &gpio->gc_map[bank]; 218 memset(rg, 0, sizeof(*rg)); 219 220 spin_lock_init(&rg->lock); > 221 rg->chip.of_node = node; 222 rg->bank = bank; 223 rg->chip.label = mediatek_gpio_bank_name(rg->bank); 224 225 dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE); 226 set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE); 227 ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE); 228 diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE); 229 230 ret = bgpio_init(&rg->chip, &pdev->dev, 4, 231 dat, set, ctrl, diro, NULL, 0); 232 if (ret) { 233 dev_err(&pdev->dev, "bgpio_init() failed\n"); 234 return ret; 235 } 236 237 ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); 238 if (ret < 0) { 239 dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", 240 rg->chip.ngpio, ret); 241 return ret; 242 } 243 244 if (gpio->gpio_irq) { 245 /* 246 * Manually request the irq here instead of passing 247 * a flow-handler to gpiochip_set_chained_irqchip, 248 * because the irq is shared. 249 */ 250 ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, 251 mediatek_gpio_irq_handler, IRQF_SHARED, 252 rg->chip.label, &rg->chip); 253 254 if (ret) { 255 dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", 256 gpio->gpio_irq, ret); 257 return ret; 258 } 259 260 mediatek_gpio_irq_chip.name = rg->chip.label; 261 ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, 262 0, handle_simple_irq, IRQ_TYPE_NONE); 263 if (ret) { 264 dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); 265 return ret; 266 } 267 268 gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, 269 gpio->gpio_irq, NULL); 270 } 271 272 /* set polarity to low for all gpios */ 273 mtk_gpio_w32(rg, GPIO_REG_POL, 0); 274 275 dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); 276 277 return 0; 278 } 279 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
On Fri, Jun 29, 2018 at 6:43 PM, kbuild test robot <lkp@intel.com> wrote: > Hi Sergio, > > Thank you for the patch! Yet something to improve: > > [auto build test ERROR on gpio/for-next] > [also build test ERROR on v4.18-rc2 next-20180629] > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] > > url: https://github.com/0day-ci/linux/commits/Sergio-Paracuellos/gpio-mediatek-driver-for-gpio-chip-in-MT7621-SoC/20180629-225420 > base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next > config: x86_64-randconfig-s0-06292230 (attached as .config) > compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026 > reproduce: > # save the attached .config to linux build tree > make ARCH=x86_64 > > All errors (new ones prefixed by >>): > > drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe': >>> drivers/gpio/gpio-mt7621.c:221:10: error: 'struct gpio_chip' has no member named 'of_node' > rg->chip.of_node = node; > ^ Should I have to add #ifdef CONFIG_OF_GPIO for this line? Is kind of ugly hack... Does exist another way to fix this? Thanks, Sergio Paracuellos > > vim +221 drivers/gpio/gpio-mt7621.c > > 207 > 208 static int > 209 mediatek_gpio_bank_probe(struct platform_device *pdev, > 210 struct device_node *node, int bank) > 211 { > 212 struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); > 213 struct mtk_gc *rg; > 214 void __iomem *dat, *set, *ctrl, *diro; > 215 int ret; > 216 > 217 rg = &gpio->gc_map[bank]; > 218 memset(rg, 0, sizeof(*rg)); > 219 > 220 spin_lock_init(&rg->lock); > > 221 rg->chip.of_node = node; > 222 rg->bank = bank; > 223 rg->chip.label = mediatek_gpio_bank_name(rg->bank); > 224 > 225 dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE); > 226 set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE); > 227 ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE); > 228 diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE); > 229 > 230 ret = bgpio_init(&rg->chip, &pdev->dev, 4, > 231 dat, set, ctrl, diro, NULL, 0); > 232 if (ret) { > 233 dev_err(&pdev->dev, "bgpio_init() failed\n"); > 234 return ret; > 235 } > 236 > 237 ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); > 238 if (ret < 0) { > 239 dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", > 240 rg->chip.ngpio, ret); > 241 return ret; > 242 } > 243 > 244 if (gpio->gpio_irq) { > 245 /* > 246 * Manually request the irq here instead of passing > 247 * a flow-handler to gpiochip_set_chained_irqchip, > 248 * because the irq is shared. > 249 */ > 250 ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, > 251 mediatek_gpio_irq_handler, IRQF_SHARED, > 252 rg->chip.label, &rg->chip); > 253 > 254 if (ret) { > 255 dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", > 256 gpio->gpio_irq, ret); > 257 return ret; > 258 } > 259 > 260 mediatek_gpio_irq_chip.name = rg->chip.label; > 261 ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, > 262 0, handle_simple_irq, IRQ_TYPE_NONE); > 263 if (ret) { > 264 dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); > 265 return ret; > 266 } > 267 > 268 gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, > 269 gpio->gpio_irq, NULL); > 270 } > 271 > 272 /* set polarity to low for all gpios */ > 273 mtk_gpio_w32(rg, GPIO_REG_POL, 0); > 274 > 275 dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); > 276 > 277 return 0; > 278 } > 279 > > --- > 0-DAY kernel test infrastructure Open Source Technology Center > https://lists.01.org/pipermail/kbuild-all Intel Corporation -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Jun 29, 2018 at 6:52 PM, Sergio Paracuellos <sergio.paracuellos@gmail.com> wrote: > On Fri, Jun 29, 2018 at 6:43 PM, kbuild test robot <lkp@intel.com> wrote: >> Hi Sergio, >> >> Thank you for the patch! Yet something to improve: >> >> [auto build test ERROR on gpio/for-next] >> [also build test ERROR on v4.18-rc2 next-20180629] >> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] >> >> url: https://github.com/0day-ci/linux/commits/Sergio-Paracuellos/gpio-mediatek-driver-for-gpio-chip-in-MT7621-SoC/20180629-225420 >> base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next >> config: x86_64-randconfig-s0-06292230 (attached as .config) >> compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026 >> reproduce: >> # save the attached .config to linux build tree >> make ARCH=x86_64 >> >> All errors (new ones prefixed by >>): >> >> drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe': >>>> drivers/gpio/gpio-mt7621.c:221:10: error: 'struct gpio_chip' has no member named 'of_node' >> rg->chip.of_node = node; >> ^ > > Should I have to add #ifdef CONFIG_OF_GPIO for this line? Is kind of > ugly hack... Does exist another way to fix this? > Ah, this is v2 where the Makefile was wrong... I though it was v3. I think we can ignore this and see what happen with likely correct v3. Best regards, Sergio Paracuellos > Thanks, > Sergio Paracuellos > >> >> vim +221 drivers/gpio/gpio-mt7621.c >> >> 207 >> 208 static int >> 209 mediatek_gpio_bank_probe(struct platform_device *pdev, >> 210 struct device_node *node, int bank) >> 211 { >> 212 struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); >> 213 struct mtk_gc *rg; >> 214 void __iomem *dat, *set, *ctrl, *diro; >> 215 int ret; >> 216 >> 217 rg = &gpio->gc_map[bank]; >> 218 memset(rg, 0, sizeof(*rg)); >> 219 >> 220 spin_lock_init(&rg->lock); >> > 221 rg->chip.of_node = node; >> 222 rg->bank = bank; >> 223 rg->chip.label = mediatek_gpio_bank_name(rg->bank); >> 224 >> 225 dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE); >> 226 set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE); >> 227 ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE); >> 228 diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE); >> 229 >> 230 ret = bgpio_init(&rg->chip, &pdev->dev, 4, >> 231 dat, set, ctrl, diro, NULL, 0); >> 232 if (ret) { >> 233 dev_err(&pdev->dev, "bgpio_init() failed\n"); >> 234 return ret; >> 235 } >> 236 >> 237 ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); >> 238 if (ret < 0) { >> 239 dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", >> 240 rg->chip.ngpio, ret); >> 241 return ret; >> 242 } >> 243 >> 244 if (gpio->gpio_irq) { >> 245 /* >> 246 * Manually request the irq here instead of passing >> 247 * a flow-handler to gpiochip_set_chained_irqchip, >> 248 * because the irq is shared. >> 249 */ >> 250 ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, >> 251 mediatek_gpio_irq_handler, IRQF_SHARED, >> 252 rg->chip.label, &rg->chip); >> 253 >> 254 if (ret) { >> 255 dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", >> 256 gpio->gpio_irq, ret); >> 257 return ret; >> 258 } >> 259 >> 260 mediatek_gpio_irq_chip.name = rg->chip.label; >> 261 ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, >> 262 0, handle_simple_irq, IRQ_TYPE_NONE); >> 263 if (ret) { >> 264 dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); >> 265 return ret; >> 266 } >> 267 >> 268 gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, >> 269 gpio->gpio_irq, NULL); >> 270 } >> 271 >> 272 /* set polarity to low for all gpios */ >> 273 mtk_gpio_w32(rg, GPIO_REG_POL, 0); >> 274 >> 275 dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); >> 276 >> 277 return 0; >> 278 } >> 279 >> >> --- >> 0-DAY kernel test infrastructure Open Source Technology Center >> https://lists.01.org/pipermail/kbuild-all Intel Corporation -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Jun 29, 2018 at 2:43 PM, Sergio Paracuellos <sergio.paracuellos@gmail.com> wrote: > Add driver support for gpio of MT7621 SoC. > > Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com> > --- > drivers/gpio/Kconfig | 8 ++ > drivers/gpio/Makefile | 1 + > drivers/gpio/gpio-mt7621.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 329 insertions(+) > create mode 100644 drivers/gpio/gpio-mt7621.c Hi all, Sorry for the noise. Ignore this and v3 for now. It seems the "only one node" approach for the gpio in the device tree is not working properly. I thought it was but Neil points out here it was not: http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2018-June/122621.html We'll send v4 with all properly working. Thanks in advance and sorry again. Best regards, Sergio Paracuellos > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 71c0ab4..836aa21 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -359,6 +359,14 @@ config GPIO_MPC8XXX > Say Y here if you're going to use hardware that connects to the > MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs. > > +config GPIO_MT7621 > + bool "Mediatek MT7621 GPIO Support" > + depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST > + select GPIO_GENERIC > + select GPIOLIB_IRQCHIP > + help > + Say yes here to support the Mediatek MT7621 SoC GPIO device > + > config GPIO_MVEBU > def_bool y > depends on PLAT_ORION || ARCH_MVEBU > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index 1324c8f..b264426 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -88,6 +88,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o > obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o > obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o > obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o > +obj-$(CONFIG_GPIO_MSIC) += gpio-mt7621.o > obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o > obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o > obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o > diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c > new file mode 100644 > index 0000000..281e621 > --- /dev/null > +++ b/drivers/gpio/gpio-mt7621.c > @@ -0,0 +1,320 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> > + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> > + */ > + > +#include <linux/err.h> > +#include <linux/gpio/driver.h> > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/of_irq.h> > +#include <linux/platform_device.h> > +#include <linux/spinlock.h> > + > +#define MTK_BANK_CNT 3 > +#define MTK_BANK_WIDTH 32 > + > +#define GPIO_BANK_WIDE 0x04 > +#define GPIO_REG_CTRL 0x00 > +#define GPIO_REG_POL 0x10 > +#define GPIO_REG_DATA 0x20 > +#define GPIO_REG_DSET 0x30 > +#define GPIO_REG_DCLR 0x40 > +#define GPIO_REG_REDGE 0x50 > +#define GPIO_REG_FEDGE 0x60 > +#define GPIO_REG_HLVL 0x70 > +#define GPIO_REG_LLVL 0x80 > +#define GPIO_REG_STAT 0x90 > +#define GPIO_REG_EDGE 0xA0 > + > +struct mtk_gc { > + struct gpio_chip chip; > + spinlock_t lock; > + int bank; > + u32 rising; > + u32 falling; > + u32 hlevel; > + u32 llevel; > +}; > + > +/** > + * struct mtk_data - state container for > + * data of the platform driver. It is 3 > + * separate gpio-chip each one with its > + * own irq_chip. > + * @dev: device instance > + * @gpio_membase: memory base address > + * @gpio_irq: irq number from the device tree > + * @gc_map: array of the gpio chips > + */ > +struct mtk_data { > + struct device *dev; > + void __iomem *gpio_membase; > + int gpio_irq; > + struct mtk_gc gc_map[MTK_BANK_CNT]; > +}; > + > +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, u32 offset, u32 val) > +{ > + struct gpio_chip *gc = &rg->chip; > + struct mtk_data *gpio_data = gpiochip_get_data(gc); > + > + offset = (rg->bank * GPIO_BANK_WIDE) + offset; > + gc->write_reg(gpio_data->gpio_membase + offset, val); > +} > + > +static inline u32 > +mtk_gpio_r32(struct mtk_gc *rg, u32 offset) > +{ > + struct gpio_chip *gc = &rg->chip; > + struct mtk_data *gpio_data = gpiochip_get_data(gc); > + > + offset = (rg->bank * GPIO_BANK_WIDE) + offset; > + return gc->read_reg(gpio_data->gpio_membase + offset); > +} > + > +static irqreturn_t > +mediatek_gpio_irq_handler(int irq, void *data) > +{ > + struct gpio_chip *gc = data; > + struct mtk_gc *rg = to_mediatek_gpio(gc); > + irqreturn_t ret = IRQ_NONE; > + unsigned long pending; > + int bit; > + > + pending = mtk_gpio_r32(rg, GPIO_REG_STAT); > + > + for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { > + u32 map = irq_find_mapping(gc->irq.domain, bit); > + > + generic_handle_irq(map); > + mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); > + ret |= IRQ_HANDLED; > + } > + > + return ret; > +} > + > +static void > +mediatek_gpio_irq_unmask(struct irq_data *d) > +{ > + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); > + struct mtk_gc *rg = to_mediatek_gpio(gc); > + int pin = d->hwirq; > + unsigned long flags; > + u32 rise, fall, high, low; > + > + spin_lock_irqsave(&rg->lock, flags); > + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); > + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); > + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); > + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); > + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising)); > + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling)); > + mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel)); > + mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel)); > + spin_unlock_irqrestore(&rg->lock, flags); > +} > + > +static void > +mediatek_gpio_irq_mask(struct irq_data *d) > +{ > + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); > + struct mtk_gc *rg = to_mediatek_gpio(gc); > + int pin = d->hwirq; > + unsigned long flags; > + u32 rise, fall, high, low; > + > + spin_lock_irqsave(&rg->lock, flags); > + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); > + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); > + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); > + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); > + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin)); > + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin)); > + mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin)); > + mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin)); > + spin_unlock_irqrestore(&rg->lock, flags); > +} > + > +static int > +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) > +{ > + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); > + struct mtk_gc *rg = to_mediatek_gpio(gc); > + int pin = d->hwirq; > + u32 mask = BIT(pin); > + > + if (type == IRQ_TYPE_PROBE) { > + if ((rg->rising | rg->falling | > + rg->hlevel | rg->llevel) & mask) > + return 0; > + > + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; > + } > + > + rg->rising &= ~mask; > + rg->falling &= ~mask; > + rg->hlevel &= ~mask; > + rg->llevel &= ~mask; > + > + switch (type & IRQ_TYPE_SENSE_MASK) { > + case IRQ_TYPE_EDGE_BOTH: > + rg->rising |= mask; > + rg->falling |= mask; > + break; > + case IRQ_TYPE_EDGE_RISING: > + rg->rising |= mask; > + break; > + case IRQ_TYPE_EDGE_FALLING: > + rg->falling |= mask; > + break; > + case IRQ_TYPE_LEVEL_HIGH: > + rg->hlevel |= mask; > + break; > + case IRQ_TYPE_LEVEL_LOW: > + rg->llevel |= mask; > + break; > + } > + > + return 0; > +} > + > +static struct irq_chip mediatek_gpio_irq_chip = { > + .irq_unmask = mediatek_gpio_irq_unmask, > + .irq_mask = mediatek_gpio_irq_mask, > + .irq_mask_ack = mediatek_gpio_irq_mask, > + .irq_set_type = mediatek_gpio_irq_type, > +}; > + > +static inline const char * const mediatek_gpio_bank_name(int bank) > +{ > + static const char * const bank_names[] = { > + "mt7621-bank0", "mt7621-bank1", "mt7621-bank2", > + }; > + > + return bank_names[bank]; > +} > + > +static int > +mediatek_gpio_bank_probe(struct platform_device *pdev, > + struct device_node *node, int bank) > +{ > + struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); > + struct mtk_gc *rg; > + void __iomem *dat, *set, *ctrl, *diro; > + int ret; > + > + rg = &gpio->gc_map[bank]; > + memset(rg, 0, sizeof(*rg)); > + > + spin_lock_init(&rg->lock); > + rg->chip.of_node = node; > + rg->bank = bank; > + rg->chip.label = mediatek_gpio_bank_name(rg->bank); > + > + dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE); > + set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE); > + ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE); > + diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE); > + > + ret = bgpio_init(&rg->chip, &pdev->dev, 4, > + dat, set, ctrl, diro, NULL, 0); > + if (ret) { > + dev_err(&pdev->dev, "bgpio_init() failed\n"); > + return ret; > + } > + > + ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); > + if (ret < 0) { > + dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", > + rg->chip.ngpio, ret); > + return ret; > + } > + > + if (gpio->gpio_irq) { > + /* > + * Manually request the irq here instead of passing > + * a flow-handler to gpiochip_set_chained_irqchip, > + * because the irq is shared. > + */ > + ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, > + mediatek_gpio_irq_handler, IRQF_SHARED, > + rg->chip.label, &rg->chip); > + > + if (ret) { > + dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", > + gpio->gpio_irq, ret); > + return ret; > + } > + > + mediatek_gpio_irq_chip.name = rg->chip.label; > + ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, > + 0, handle_simple_irq, IRQ_TYPE_NONE); > + if (ret) { > + dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); > + return ret; > + } > + > + gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, > + gpio->gpio_irq, NULL); > + } > + > + /* 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 0; > +} > + > +static int > +mediatek_gpio_probe(struct platform_device *pdev) > +{ > + struct device_node *np = pdev->dev.of_node; > + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + struct mtk_data *gpio_data; > + int i; > + > + gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL); > + if (!gpio_data) > + return -ENOMEM; > + > + gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(gpio_data->gpio_membase)) > + return PTR_ERR(gpio_data->gpio_membase); > + > + gpio_data->gpio_irq = irq_of_parse_and_map(np, 0); > + gpio_data->dev = &pdev->dev; > + platform_set_drvdata(pdev, gpio_data); > + > + for (i = 0; i < MTK_BANK_CNT; i++) > + mediatek_gpio_bank_probe(pdev, np, i); > + > + return 0; > +} > + > +static const struct of_device_id mediatek_gpio_match[] = { > + { .compatible = "mediatek,mt7621-gpio" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, mediatek_gpio_match); > + > +static struct platform_driver mediatek_gpio_driver = { > + .probe = mediatek_gpio_probe, > + .driver = { > + .name = "mt7621_gpio", > + .of_match_table = mediatek_gpio_match, > + }, > +}; > + > +builtin_platform_driver(mediatek_gpio_driver); > -- > 2.7.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 71c0ab4..836aa21 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -359,6 +359,14 @@ config GPIO_MPC8XXX Say Y here if you're going to use hardware that connects to the MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs. +config GPIO_MT7621 + bool "Mediatek MT7621 GPIO Support" + depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say yes here to support the Mediatek MT7621 SoC GPIO device + config GPIO_MVEBU def_bool y depends on PLAT_ORION || ARCH_MVEBU diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1324c8f..b264426 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o +obj-$(CONFIG_GPIO_MSIC) += gpio-mt7621.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c new file mode 100644 index 0000000..281e621 --- /dev/null +++ b/drivers/gpio/gpio-mt7621.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#define MTK_BANK_CNT 3 +#define MTK_BANK_WIDTH 32 + +#define GPIO_BANK_WIDE 0x04 +#define GPIO_REG_CTRL 0x00 +#define GPIO_REG_POL 0x10 +#define GPIO_REG_DATA 0x20 +#define GPIO_REG_DSET 0x30 +#define GPIO_REG_DCLR 0x40 +#define GPIO_REG_REDGE 0x50 +#define GPIO_REG_FEDGE 0x60 +#define GPIO_REG_HLVL 0x70 +#define GPIO_REG_LLVL 0x80 +#define GPIO_REG_STAT 0x90 +#define GPIO_REG_EDGE 0xA0 + +struct mtk_gc { + struct gpio_chip chip; + spinlock_t lock; + int bank; + u32 rising; + u32 falling; + u32 hlevel; + u32 llevel; +}; + +/** + * struct mtk_data - state container for + * data of the platform driver. It is 3 + * separate gpio-chip each one with its + * own irq_chip. + * @dev: device instance + * @gpio_membase: memory base address + * @gpio_irq: irq number from the device tree + * @gc_map: array of the gpio chips + */ +struct mtk_data { + struct device *dev; + void __iomem *gpio_membase; + int gpio_irq; + struct mtk_gc gc_map[MTK_BANK_CNT]; +}; + +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, u32 offset, u32 val) +{ + struct gpio_chip *gc = &rg->chip; + struct mtk_data *gpio_data = gpiochip_get_data(gc); + + offset = (rg->bank * GPIO_BANK_WIDE) + offset; + gc->write_reg(gpio_data->gpio_membase + offset, val); +} + +static inline u32 +mtk_gpio_r32(struct mtk_gc *rg, u32 offset) +{ + struct gpio_chip *gc = &rg->chip; + struct mtk_data *gpio_data = gpiochip_get_data(gc); + + offset = (rg->bank * GPIO_BANK_WIDE) + offset; + return gc->read_reg(gpio_data->gpio_membase + offset); +} + +static irqreturn_t +mediatek_gpio_irq_handler(int irq, void *data) +{ + struct gpio_chip *gc = data; + struct mtk_gc *rg = to_mediatek_gpio(gc); + irqreturn_t ret = IRQ_NONE; + unsigned long pending; + int bit; + + pending = mtk_gpio_r32(rg, GPIO_REG_STAT); + + for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { + u32 map = irq_find_mapping(gc->irq.domain, bit); + + generic_handle_irq(map); + mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); + ret |= IRQ_HANDLED; + } + + return ret; +} + +static void +mediatek_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 rise, fall, high, low; + + spin_lock_irqsave(&rg->lock, flags); + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static void +mediatek_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 rise, fall, high, low; + + spin_lock_irqsave(&rg->lock, flags); + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static int +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + u32 mask = BIT(pin); + + if (type == IRQ_TYPE_PROBE) { + if ((rg->rising | rg->falling | + rg->hlevel | rg->llevel) & mask) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + rg->rising &= ~mask; + rg->falling &= ~mask; + rg->hlevel &= ~mask; + rg->llevel &= ~mask; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + rg->rising |= mask; + rg->falling |= mask; + break; + case IRQ_TYPE_EDGE_RISING: + rg->rising |= mask; + break; + case IRQ_TYPE_EDGE_FALLING: + rg->falling |= mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + rg->hlevel |= mask; + break; + case IRQ_TYPE_LEVEL_LOW: + rg->llevel |= mask; + break; + } + + return 0; +} + +static struct irq_chip mediatek_gpio_irq_chip = { + .irq_unmask = mediatek_gpio_irq_unmask, + .irq_mask = mediatek_gpio_irq_mask, + .irq_mask_ack = mediatek_gpio_irq_mask, + .irq_set_type = mediatek_gpio_irq_type, +}; + +static inline const char * const mediatek_gpio_bank_name(int bank) +{ + static const char * const bank_names[] = { + "mt7621-bank0", "mt7621-bank1", "mt7621-bank2", + }; + + return bank_names[bank]; +} + +static int +mediatek_gpio_bank_probe(struct platform_device *pdev, + struct device_node *node, int bank) +{ + struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); + struct mtk_gc *rg; + void __iomem *dat, *set, *ctrl, *diro; + int ret; + + rg = &gpio->gc_map[bank]; + memset(rg, 0, sizeof(*rg)); + + spin_lock_init(&rg->lock); + rg->chip.of_node = node; + rg->bank = bank; + rg->chip.label = mediatek_gpio_bank_name(rg->bank); + + dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE); + set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE); + ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE); + diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE); + + ret = bgpio_init(&rg->chip, &pdev->dev, 4, + dat, set, ctrl, diro, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "bgpio_init() failed\n"); + return ret; + } + + ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", + rg->chip.ngpio, ret); + return ret; + } + + if (gpio->gpio_irq) { + /* + * Manually request the irq here instead of passing + * a flow-handler to gpiochip_set_chained_irqchip, + * because the irq is shared. + */ + ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, + mediatek_gpio_irq_handler, IRQF_SHARED, + rg->chip.label, &rg->chip); + + if (ret) { + dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", + gpio->gpio_irq, ret); + return ret; + } + + mediatek_gpio_irq_chip.name = rg->chip.label; + ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, + 0, handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); + return ret; + } + + gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, + gpio->gpio_irq, NULL); + } + + /* 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 0; +} + +static int +mediatek_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct mtk_data *gpio_data; + int i; + + gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL); + if (!gpio_data) + return -ENOMEM; + + gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio_data->gpio_membase)) + return PTR_ERR(gpio_data->gpio_membase); + + gpio_data->gpio_irq = irq_of_parse_and_map(np, 0); + gpio_data->dev = &pdev->dev; + platform_set_drvdata(pdev, gpio_data); + + for (i = 0; i < MTK_BANK_CNT; i++) + mediatek_gpio_bank_probe(pdev, np, i); + + return 0; +} + +static const struct of_device_id mediatek_gpio_match[] = { + { .compatible = "mediatek,mt7621-gpio" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mediatek_gpio_match); + +static struct platform_driver mediatek_gpio_driver = { + .probe = mediatek_gpio_probe, + .driver = { + .name = "mt7621_gpio", + .of_match_table = mediatek_gpio_match, + }, +}; + +builtin_platform_driver(mediatek_gpio_driver);
Add driver support for gpio of MT7621 SoC. Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com> --- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-mt7621.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 drivers/gpio/gpio-mt7621.c