Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  linux/drivers/gpio/gpio-mb86s7x.c
0004  *
0005  *  Copyright (C) 2015 Fujitsu Semiconductor Limited
0006  *  Copyright (C) 2015 Linaro Ltd.
0007  */
0008 
0009 #include <linux/acpi.h>
0010 #include <linux/io.h>
0011 #include <linux/init.h>
0012 #include <linux/clk.h>
0013 #include <linux/module.h>
0014 #include <linux/err.h>
0015 #include <linux/errno.h>
0016 #include <linux/ioport.h>
0017 #include <linux/of_device.h>
0018 #include <linux/gpio/driver.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/spinlock.h>
0021 #include <linux/slab.h>
0022 
0023 #include "gpiolib.h"
0024 #include "gpiolib-acpi.h"
0025 
0026 /*
0027  * Only first 8bits of a register correspond to each pin,
0028  * so there are 4 registers for 32 pins.
0029  */
0030 #define PDR(x)  (0x0 + x / 8 * 4)
0031 #define DDR(x)  (0x10 + x / 8 * 4)
0032 #define PFR(x)  (0x20 + x / 8 * 4)
0033 
0034 #define OFFSET(x)   BIT((x) % 8)
0035 
0036 struct mb86s70_gpio_chip {
0037     struct gpio_chip gc;
0038     void __iomem *base;
0039     struct clk *clk;
0040     spinlock_t lock;
0041 };
0042 
0043 static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
0044 {
0045     struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
0046     unsigned long flags;
0047     u32 val;
0048 
0049     spin_lock_irqsave(&gchip->lock, flags);
0050 
0051     val = readl(gchip->base + PFR(gpio));
0052     val &= ~OFFSET(gpio);
0053     writel(val, gchip->base + PFR(gpio));
0054 
0055     spin_unlock_irqrestore(&gchip->lock, flags);
0056 
0057     return 0;
0058 }
0059 
0060 static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
0061 {
0062     struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
0063     unsigned long flags;
0064     u32 val;
0065 
0066     spin_lock_irqsave(&gchip->lock, flags);
0067 
0068     val = readl(gchip->base + PFR(gpio));
0069     val |= OFFSET(gpio);
0070     writel(val, gchip->base + PFR(gpio));
0071 
0072     spin_unlock_irqrestore(&gchip->lock, flags);
0073 }
0074 
0075 static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
0076 {
0077     struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
0078     unsigned long flags;
0079     unsigned char val;
0080 
0081     spin_lock_irqsave(&gchip->lock, flags);
0082 
0083     val = readl(gchip->base + DDR(gpio));
0084     val &= ~OFFSET(gpio);
0085     writel(val, gchip->base + DDR(gpio));
0086 
0087     spin_unlock_irqrestore(&gchip->lock, flags);
0088 
0089     return 0;
0090 }
0091 
0092 static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
0093                      unsigned gpio, int value)
0094 {
0095     struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
0096     unsigned long flags;
0097     unsigned char val;
0098 
0099     spin_lock_irqsave(&gchip->lock, flags);
0100 
0101     val = readl(gchip->base + PDR(gpio));
0102     if (value)
0103         val |= OFFSET(gpio);
0104     else
0105         val &= ~OFFSET(gpio);
0106     writel(val, gchip->base + PDR(gpio));
0107 
0108     val = readl(gchip->base + DDR(gpio));
0109     val |= OFFSET(gpio);
0110     writel(val, gchip->base + DDR(gpio));
0111 
0112     spin_unlock_irqrestore(&gchip->lock, flags);
0113 
0114     return 0;
0115 }
0116 
0117 static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
0118 {
0119     struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
0120 
0121     return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
0122 }
0123 
0124 static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
0125 {
0126     struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
0127     unsigned long flags;
0128     unsigned char val;
0129 
0130     spin_lock_irqsave(&gchip->lock, flags);
0131 
0132     val = readl(gchip->base + PDR(gpio));
0133     if (value)
0134         val |= OFFSET(gpio);
0135     else
0136         val &= ~OFFSET(gpio);
0137     writel(val, gchip->base + PDR(gpio));
0138 
0139     spin_unlock_irqrestore(&gchip->lock, flags);
0140 }
0141 
0142 static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
0143 {
0144     int irq, index;
0145 
0146     for (index = 0;; index++) {
0147         irq = platform_get_irq(to_platform_device(gc->parent), index);
0148         if (irq < 0)
0149             return irq;
0150         if (irq == 0)
0151             break;
0152         if (irq_get_irq_data(irq)->hwirq == offset)
0153             return irq;
0154     }
0155     return -EINVAL;
0156 }
0157 
0158 static int mb86s70_gpio_probe(struct platform_device *pdev)
0159 {
0160     struct mb86s70_gpio_chip *gchip;
0161     int ret;
0162 
0163     gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
0164     if (gchip == NULL)
0165         return -ENOMEM;
0166 
0167     platform_set_drvdata(pdev, gchip);
0168 
0169     gchip->base = devm_platform_ioremap_resource(pdev, 0);
0170     if (IS_ERR(gchip->base))
0171         return PTR_ERR(gchip->base);
0172 
0173     gchip->clk = devm_clk_get_optional(&pdev->dev, NULL);
0174     if (IS_ERR(gchip->clk))
0175         return PTR_ERR(gchip->clk);
0176 
0177     ret = clk_prepare_enable(gchip->clk);
0178     if (ret)
0179         return ret;
0180 
0181     spin_lock_init(&gchip->lock);
0182 
0183     gchip->gc.direction_output = mb86s70_gpio_direction_output;
0184     gchip->gc.direction_input = mb86s70_gpio_direction_input;
0185     gchip->gc.request = mb86s70_gpio_request;
0186     gchip->gc.free = mb86s70_gpio_free;
0187     gchip->gc.get = mb86s70_gpio_get;
0188     gchip->gc.set = mb86s70_gpio_set;
0189     gchip->gc.to_irq = mb86s70_gpio_to_irq;
0190     gchip->gc.label = dev_name(&pdev->dev);
0191     gchip->gc.ngpio = 32;
0192     gchip->gc.owner = THIS_MODULE;
0193     gchip->gc.parent = &pdev->dev;
0194     gchip->gc.base = -1;
0195 
0196     ret = gpiochip_add_data(&gchip->gc, gchip);
0197     if (ret) {
0198         dev_err(&pdev->dev, "couldn't register gpio driver\n");
0199         clk_disable_unprepare(gchip->clk);
0200         return ret;
0201     }
0202 
0203     acpi_gpiochip_request_interrupts(&gchip->gc);
0204 
0205     return 0;
0206 }
0207 
0208 static int mb86s70_gpio_remove(struct platform_device *pdev)
0209 {
0210     struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
0211 
0212     acpi_gpiochip_free_interrupts(&gchip->gc);
0213     gpiochip_remove(&gchip->gc);
0214     clk_disable_unprepare(gchip->clk);
0215 
0216     return 0;
0217 }
0218 
0219 static const struct of_device_id mb86s70_gpio_dt_ids[] = {
0220     { .compatible = "fujitsu,mb86s70-gpio" },
0221     { /* sentinel */ }
0222 };
0223 MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
0224 
0225 #ifdef CONFIG_ACPI
0226 static const struct acpi_device_id mb86s70_gpio_acpi_ids[] = {
0227     { "SCX0007" },
0228     { /* sentinel */ }
0229 };
0230 MODULE_DEVICE_TABLE(acpi, mb86s70_gpio_acpi_ids);
0231 #endif
0232 
0233 static struct platform_driver mb86s70_gpio_driver = {
0234     .driver = {
0235         .name = "mb86s70-gpio",
0236         .of_match_table = mb86s70_gpio_dt_ids,
0237         .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids),
0238     },
0239     .probe = mb86s70_gpio_probe,
0240     .remove = mb86s70_gpio_remove,
0241 };
0242 module_platform_driver(mb86s70_gpio_driver);
0243 
0244 MODULE_DESCRIPTION("MB86S7x GPIO Driver");
0245 MODULE_ALIAS("platform:mb86s70-gpio");
0246 MODULE_LICENSE("GPL");