]>
Commit | Line | Data |
---|---|---|
aeec56e3 AV |
1 | /* |
2 | * Driver for basic memory-mapped GPIO controllers. | |
3 | * | |
4 | * Copyright 2008 MontaVista Software, Inc. | |
5 | * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. | |
11 | * | |
12 | * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... | |
13 | * ...`` ```````.. | |
14 | * ..The simplest form of a GPIO controller that the driver supports is`` | |
15 | * `.just a single "data" register, where GPIO state can be read and/or ` | |
16 | * `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.``````` | |
17 | * ````````` | |
18 | ___ | |
19 | _/~~|___/~| . ```~~~~~~ ___/___\___ ,~.`.`.`.`````.~~...,,,,... | |
20 | __________|~$@~~~ %~ /o*o*o*o*o*o\ .. Implementing such a GPIO . | |
21 | o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` | |
22 | `....trivial..'~`.```.``` | |
23 | * ``````` | |
24 | * .```````~~~~`..`.``.``. | |
25 | * . The driver supports `... ,..```.`~~~```````````````....````.``,, | |
26 | * . big-endian notation, just`. .. A bit more sophisticated controllers , | |
27 | * . register the device with -be`. .with a pair of set/clear-bit registers , | |
28 | * `.. suffix. ```~~`````....`.` . affecting the data register and the .` | |
29 | * ``.`.``...``` ```.. output pins are also supported.` | |
30 | * ^^ `````.`````````.,``~``~``~~`````` | |
31 | * . ^^ | |
32 | * ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`.. | |
33 | * .. The expectation is that in at least some cases . ,-~~~-, | |
34 | * .this will be used with roll-your-own ASIC/FPGA .` \ / | |
35 | * .logic in Verilog or VHDL. ~~~`````````..`````~~` \ / | |
36 | * ..````````......``````````` \o_ | |
37 | * | | |
38 | * ^^ / \ | |
39 | * | |
40 | * ...`````~~`.....``.`..........``````.`.``.```........``. | |
41 | * ` 8, 16, 32 and 64 bits registers are supported, and``. | |
42 | * . the number of GPIOs is determined by the width of ~ | |
43 | * .. the registers. ,............```.`.`..`.`.~~~.`.`.`~ | |
44 | * `.......````.``` | |
45 | */ | |
46 | ||
47 | #include <linux/init.h> | |
48 | #include <linux/bug.h> | |
49 | #include <linux/kernel.h> | |
50 | #include <linux/module.h> | |
51 | #include <linux/spinlock.h> | |
52 | #include <linux/compiler.h> | |
53 | #include <linux/types.h> | |
54 | #include <linux/errno.h> | |
55 | #include <linux/log2.h> | |
56 | #include <linux/ioport.h> | |
57 | #include <linux/io.h> | |
58 | #include <linux/gpio.h> | |
59 | #include <linux/slab.h> | |
60 | #include <linux/platform_device.h> | |
61 | #include <linux/mod_devicetable.h> | |
62 | #include <linux/basic_mmio_gpio.h> | |
63 | ||
64 | struct bgpio_chip { | |
65 | struct gpio_chip gc; | |
66 | void __iomem *reg_dat; | |
67 | void __iomem *reg_set; | |
68 | void __iomem *reg_clr; | |
69 | ||
70 | /* Number of bits (GPIOs): <register width> * 8. */ | |
71 | int bits; | |
72 | ||
73 | /* | |
74 | * Some GPIO controllers work with the big-endian bits notation, | |
75 | * e.g. in a 8-bits register, GPIO7 is the least significant bit. | |
76 | */ | |
77 | int big_endian_bits; | |
78 | ||
79 | /* | |
80 | * Used to lock bgpio_chip->data. Also, this is needed to keep | |
81 | * shadowed and real data registers writes together. | |
82 | */ | |
83 | spinlock_t lock; | |
84 | ||
85 | /* Shadowed data register to clear/set bits safely. */ | |
86 | unsigned long data; | |
87 | }; | |
88 | ||
89 | static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc) | |
90 | { | |
91 | return container_of(gc, struct bgpio_chip, gc); | |
92 | } | |
93 | ||
94 | static unsigned long bgpio_in(struct bgpio_chip *bgc) | |
95 | { | |
96 | switch (bgc->bits) { | |
97 | case 8: | |
98 | return __raw_readb(bgc->reg_dat); | |
99 | case 16: | |
100 | return __raw_readw(bgc->reg_dat); | |
101 | case 32: | |
102 | return __raw_readl(bgc->reg_dat); | |
103 | #if BITS_PER_LONG >= 64 | |
104 | case 64: | |
105 | return __raw_readq(bgc->reg_dat); | |
106 | #endif | |
107 | } | |
108 | return -EINVAL; | |
109 | } | |
110 | ||
111 | static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg, | |
112 | unsigned long data) | |
113 | { | |
114 | switch (bgc->bits) { | |
115 | case 8: | |
116 | __raw_writeb(data, reg); | |
117 | return; | |
118 | case 16: | |
119 | __raw_writew(data, reg); | |
120 | return; | |
121 | case 32: | |
122 | __raw_writel(data, reg); | |
123 | return; | |
124 | #if BITS_PER_LONG >= 64 | |
125 | case 64: | |
126 | __raw_writeq(data, reg); | |
127 | return; | |
128 | #endif | |
129 | } | |
130 | } | |
131 | ||
132 | static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin) | |
133 | { | |
134 | if (bgc->big_endian_bits) | |
135 | return 1 << (bgc->bits - 1 - pin); | |
136 | else | |
137 | return 1 << pin; | |
138 | } | |
139 | ||
140 | static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) | |
141 | { | |
142 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | |
143 | ||
144 | return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio); | |
145 | } | |
146 | ||
147 | static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) | |
148 | { | |
149 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | |
150 | unsigned long mask = bgpio_pin2mask(bgc, gpio); | |
151 | unsigned long flags; | |
152 | ||
153 | if (bgc->reg_set) { | |
154 | if (val) | |
155 | bgpio_out(bgc, bgc->reg_set, mask); | |
156 | else | |
157 | bgpio_out(bgc, bgc->reg_clr, mask); | |
158 | return; | |
159 | } | |
160 | ||
161 | spin_lock_irqsave(&bgc->lock, flags); | |
162 | ||
163 | if (val) | |
164 | bgc->data |= mask; | |
165 | else | |
166 | bgc->data &= ~mask; | |
167 | ||
168 | bgpio_out(bgc, bgc->reg_dat, bgc->data); | |
169 | ||
170 | spin_unlock_irqrestore(&bgc->lock, flags); | |
171 | } | |
172 | ||
173 | static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) | |
174 | { | |
175 | return 0; | |
176 | } | |
177 | ||
178 | static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |
179 | { | |
180 | bgpio_set(gc, gpio, val); | |
181 | return 0; | |
182 | } | |
183 | ||
184 | static int __devinit bgpio_probe(struct platform_device *pdev) | |
185 | { | |
186 | const struct platform_device_id *platid = platform_get_device_id(pdev); | |
187 | struct device *dev = &pdev->dev; | |
188 | struct bgpio_pdata *pdata = dev_get_platdata(dev); | |
189 | struct bgpio_chip *bgc; | |
190 | struct resource *res_dat; | |
191 | struct resource *res_set; | |
192 | struct resource *res_clr; | |
193 | resource_size_t dat_sz; | |
194 | int bits; | |
195 | int ret; | |
196 | ||
197 | res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); | |
198 | if (!res_dat) | |
199 | return -EINVAL; | |
200 | ||
201 | dat_sz = resource_size(res_dat); | |
202 | if (!is_power_of_2(dat_sz)) | |
203 | return -EINVAL; | |
204 | ||
205 | bits = dat_sz * 8; | |
206 | if (bits > BITS_PER_LONG) | |
207 | return -EINVAL; | |
208 | ||
209 | bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); | |
210 | if (!bgc) | |
211 | return -ENOMEM; | |
212 | ||
213 | bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz); | |
214 | if (!bgc->reg_dat) | |
215 | return -ENOMEM; | |
216 | ||
217 | res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set"); | |
218 | res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr"); | |
219 | if (res_set && res_clr) { | |
220 | if (resource_size(res_set) != resource_size(res_clr) || | |
221 | resource_size(res_set) != dat_sz) | |
222 | return -EINVAL; | |
223 | ||
224 | bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz); | |
225 | bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz); | |
226 | if (!bgc->reg_set || !bgc->reg_clr) | |
227 | return -ENOMEM; | |
228 | } else if (res_set || res_clr) { | |
229 | return -EINVAL; | |
230 | } | |
231 | ||
232 | spin_lock_init(&bgc->lock); | |
233 | ||
234 | bgc->bits = bits; | |
235 | bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be"); | |
236 | bgc->data = bgpio_in(bgc); | |
237 | ||
238 | bgc->gc.ngpio = bits; | |
239 | bgc->gc.direction_input = bgpio_dir_in; | |
240 | bgc->gc.direction_output = bgpio_dir_out; | |
241 | bgc->gc.get = bgpio_get; | |
242 | bgc->gc.set = bgpio_set; | |
243 | bgc->gc.dev = dev; | |
244 | bgc->gc.label = dev_name(dev); | |
245 | ||
246 | if (pdata) | |
247 | bgc->gc.base = pdata->base; | |
248 | else | |
249 | bgc->gc.base = -1; | |
250 | ||
251 | dev_set_drvdata(dev, bgc); | |
252 | ||
253 | ret = gpiochip_add(&bgc->gc); | |
254 | if (ret) | |
255 | dev_err(dev, "gpiochip_add() failed: %d\n", ret); | |
256 | ||
257 | return ret; | |
258 | } | |
259 | ||
260 | static int __devexit bgpio_remove(struct platform_device *pdev) | |
261 | { | |
262 | struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev); | |
263 | ||
264 | return gpiochip_remove(&bgc->gc); | |
265 | } | |
266 | ||
267 | static const struct platform_device_id bgpio_id_table[] = { | |
268 | { "basic-mmio-gpio", }, | |
269 | { "basic-mmio-gpio-be", }, | |
270 | {}, | |
271 | }; | |
272 | MODULE_DEVICE_TABLE(platform, bgpio_id_table); | |
273 | ||
274 | static struct platform_driver bgpio_driver = { | |
275 | .driver = { | |
276 | .name = "basic-mmio-gpio", | |
277 | }, | |
278 | .id_table = bgpio_id_table, | |
279 | .probe = bgpio_probe, | |
280 | .remove = __devexit_p(bgpio_remove), | |
281 | }; | |
282 | ||
283 | static int __init bgpio_init(void) | |
284 | { | |
285 | return platform_driver_register(&bgpio_driver); | |
286 | } | |
287 | module_init(bgpio_init); | |
288 | ||
289 | static void __exit bgpio_exit(void) | |
290 | { | |
291 | platform_driver_unregister(&bgpio_driver); | |
292 | } | |
293 | module_exit(bgpio_exit); | |
294 | ||
295 | MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); | |
296 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); | |
297 | MODULE_LICENSE("GPL"); |