1 /* 2 * linux/drivers/gpio/gpio-mb86s7x.c 3 * 4 * Copyright (C) 2015 Fujitsu Semiconductor Limited 5 * Copyright (C) 2015 Linaro Ltd. 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <linux/io.h> 18 #include <linux/init.h> 19 #include <linux/clk.h> 20 #include <linux/module.h> 21 #include <linux/err.h> 22 #include <linux/errno.h> 23 #include <linux/ioport.h> 24 #include <linux/of_device.h> 25 #include <linux/gpio/driver.h> 26 #include <linux/platform_device.h> 27 #include <linux/spinlock.h> 28 #include <linux/slab.h> 29 30 /* 31 * Only first 8bits of a register correspond to each pin, 32 * so there are 4 registers for 32 pins. 33 */ 34 #define PDR(x) (0x0 + x / 8 * 4) 35 #define DDR(x) (0x10 + x / 8 * 4) 36 #define PFR(x) (0x20 + x / 8 * 4) 37 38 #define OFFSET(x) BIT((x) % 8) 39 40 struct mb86s70_gpio_chip { 41 struct gpio_chip gc; 42 void __iomem *base; 43 struct clk *clk; 44 spinlock_t lock; 45 }; 46 47 static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) 48 { 49 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 50 unsigned long flags; 51 u32 val; 52 53 spin_lock_irqsave(&gchip->lock, flags); 54 55 val = readl(gchip->base + PFR(gpio)); 56 val &= ~OFFSET(gpio); 57 writel(val, gchip->base + PFR(gpio)); 58 59 spin_unlock_irqrestore(&gchip->lock, flags); 60 61 return 0; 62 } 63 64 static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio) 65 { 66 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 67 unsigned long flags; 68 u32 val; 69 70 spin_lock_irqsave(&gchip->lock, flags); 71 72 val = readl(gchip->base + PFR(gpio)); 73 val |= OFFSET(gpio); 74 writel(val, gchip->base + PFR(gpio)); 75 76 spin_unlock_irqrestore(&gchip->lock, flags); 77 } 78 79 static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) 80 { 81 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 82 unsigned long flags; 83 unsigned char val; 84 85 spin_lock_irqsave(&gchip->lock, flags); 86 87 val = readl(gchip->base + DDR(gpio)); 88 val &= ~OFFSET(gpio); 89 writel(val, gchip->base + DDR(gpio)); 90 91 spin_unlock_irqrestore(&gchip->lock, flags); 92 93 return 0; 94 } 95 96 static int mb86s70_gpio_direction_output(struct gpio_chip *gc, 97 unsigned gpio, int value) 98 { 99 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 100 unsigned long flags; 101 unsigned char val; 102 103 spin_lock_irqsave(&gchip->lock, flags); 104 105 val = readl(gchip->base + PDR(gpio)); 106 if (value) 107 val |= OFFSET(gpio); 108 else 109 val &= ~OFFSET(gpio); 110 writel(val, gchip->base + PDR(gpio)); 111 112 val = readl(gchip->base + DDR(gpio)); 113 val |= OFFSET(gpio); 114 writel(val, gchip->base + DDR(gpio)); 115 116 spin_unlock_irqrestore(&gchip->lock, flags); 117 118 return 0; 119 } 120 121 static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio) 122 { 123 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 124 125 return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio)); 126 } 127 128 static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) 129 { 130 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 131 unsigned long flags; 132 unsigned char val; 133 134 spin_lock_irqsave(&gchip->lock, flags); 135 136 val = readl(gchip->base + PDR(gpio)); 137 if (value) 138 val |= OFFSET(gpio); 139 else 140 val &= ~OFFSET(gpio); 141 writel(val, gchip->base + PDR(gpio)); 142 143 spin_unlock_irqrestore(&gchip->lock, flags); 144 } 145 146 static int mb86s70_gpio_probe(struct platform_device *pdev) 147 { 148 struct mb86s70_gpio_chip *gchip; 149 struct resource *res; 150 int ret; 151 152 gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); 153 if (gchip == NULL) 154 return -ENOMEM; 155 156 platform_set_drvdata(pdev, gchip); 157 158 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 159 gchip->base = devm_ioremap_resource(&pdev->dev, res); 160 if (IS_ERR(gchip->base)) 161 return PTR_ERR(gchip->base); 162 163 gchip->clk = devm_clk_get(&pdev->dev, NULL); 164 if (IS_ERR(gchip->clk)) 165 return PTR_ERR(gchip->clk); 166 167 ret = clk_prepare_enable(gchip->clk); 168 if (ret) 169 return ret; 170 171 spin_lock_init(&gchip->lock); 172 173 gchip->gc.direction_output = mb86s70_gpio_direction_output; 174 gchip->gc.direction_input = mb86s70_gpio_direction_input; 175 gchip->gc.request = mb86s70_gpio_request; 176 gchip->gc.free = mb86s70_gpio_free; 177 gchip->gc.get = mb86s70_gpio_get; 178 gchip->gc.set = mb86s70_gpio_set; 179 gchip->gc.label = dev_name(&pdev->dev); 180 gchip->gc.ngpio = 32; 181 gchip->gc.owner = THIS_MODULE; 182 gchip->gc.parent = &pdev->dev; 183 gchip->gc.base = -1; 184 185 ret = gpiochip_add_data(&gchip->gc, gchip); 186 if (ret) { 187 dev_err(&pdev->dev, "couldn't register gpio driver\n"); 188 clk_disable_unprepare(gchip->clk); 189 } 190 191 return ret; 192 } 193 194 static int mb86s70_gpio_remove(struct platform_device *pdev) 195 { 196 struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); 197 198 gpiochip_remove(&gchip->gc); 199 clk_disable_unprepare(gchip->clk); 200 201 return 0; 202 } 203 204 static const struct of_device_id mb86s70_gpio_dt_ids[] = { 205 { .compatible = "fujitsu,mb86s70-gpio" }, 206 { /* sentinel */ } 207 }; 208 MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); 209 210 static struct platform_driver mb86s70_gpio_driver = { 211 .driver = { 212 .name = "mb86s70-gpio", 213 .of_match_table = mb86s70_gpio_dt_ids, 214 }, 215 .probe = mb86s70_gpio_probe, 216 .remove = mb86s70_gpio_remove, 217 }; 218 module_platform_driver(mb86s70_gpio_driver); 219 220 MODULE_DESCRIPTION("MB86S7x GPIO Driver"); 221 MODULE_ALIAS("platform:mb86s70-gpio"); 222 MODULE_LICENSE("GPL"); 223