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 int ret; 150 151 gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); 152 if (gchip == NULL) 153 return -ENOMEM; 154 155 platform_set_drvdata(pdev, gchip); 156 157 gchip->base = devm_platform_ioremap_resource(pdev, 0); 158 if (IS_ERR(gchip->base)) 159 return PTR_ERR(gchip->base); 160 161 gchip->clk = devm_clk_get(&pdev->dev, NULL); 162 if (IS_ERR(gchip->clk)) 163 return PTR_ERR(gchip->clk); 164 165 ret = clk_prepare_enable(gchip->clk); 166 if (ret) 167 return ret; 168 169 spin_lock_init(&gchip->lock); 170 171 gchip->gc.direction_output = mb86s70_gpio_direction_output; 172 gchip->gc.direction_input = mb86s70_gpio_direction_input; 173 gchip->gc.request = mb86s70_gpio_request; 174 gchip->gc.free = mb86s70_gpio_free; 175 gchip->gc.get = mb86s70_gpio_get; 176 gchip->gc.set = mb86s70_gpio_set; 177 gchip->gc.label = dev_name(&pdev->dev); 178 gchip->gc.ngpio = 32; 179 gchip->gc.owner = THIS_MODULE; 180 gchip->gc.parent = &pdev->dev; 181 gchip->gc.base = -1; 182 183 ret = gpiochip_add_data(&gchip->gc, gchip); 184 if (ret) { 185 dev_err(&pdev->dev, "couldn't register gpio driver\n"); 186 clk_disable_unprepare(gchip->clk); 187 } 188 189 return ret; 190 } 191 192 static int mb86s70_gpio_remove(struct platform_device *pdev) 193 { 194 struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); 195 196 gpiochip_remove(&gchip->gc); 197 clk_disable_unprepare(gchip->clk); 198 199 return 0; 200 } 201 202 static const struct of_device_id mb86s70_gpio_dt_ids[] = { 203 { .compatible = "fujitsu,mb86s70-gpio" }, 204 { /* sentinel */ } 205 }; 206 MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); 207 208 static struct platform_driver mb86s70_gpio_driver = { 209 .driver = { 210 .name = "mb86s70-gpio", 211 .of_match_table = mb86s70_gpio_dt_ids, 212 }, 213 .probe = mb86s70_gpio_probe, 214 .remove = mb86s70_gpio_remove, 215 }; 216 module_platform_driver(mb86s70_gpio_driver); 217 218 MODULE_DESCRIPTION("MB86S7x GPIO Driver"); 219 MODULE_ALIAS("platform:mb86s70-gpio"); 220 MODULE_LICENSE("GPL"); 221