1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/gpio.h>
17#include <linux/io.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/map.h>
22#include <linux/mtd/partitions.h>
23#include <linux/mtd/physmap.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26#include <linux/types.h>
27
28#define pr_devinit(fmt, args...) \
29 ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
30
31#define DRIVER_NAME "gpio-addr-flash"
32#define PFX DRIVER_NAME ": "
33
34
35
36
37
38
39
40
41
42
43struct async_state {
44 struct mtd_info *mtd;
45 struct map_info map;
46 size_t gpio_count;
47 unsigned *gpio_addrs;
48 int *gpio_values;
49 unsigned long win_size;
50};
51#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
52
53
54
55
56
57
58
59
60
61
62
63static void gf_set_gpios(struct async_state *state, unsigned long ofs)
64{
65 size_t i = 0;
66 int value;
67 ofs /= state->win_size;
68 do {
69 value = ofs & (1 << i);
70 if (state->gpio_values[i] != value) {
71 gpio_set_value(state->gpio_addrs[i], value);
72 state->gpio_values[i] = value;
73 }
74 } while (++i < state->gpio_count);
75}
76
77
78
79
80
81
82static map_word gf_read(struct map_info *map, unsigned long ofs)
83{
84 struct async_state *state = gf_map_info_to_state(map);
85 uint16_t word;
86 map_word test;
87
88 gf_set_gpios(state, ofs);
89
90 word = readw(map->virt + (ofs % state->win_size));
91 test.x[0] = word;
92 return test;
93}
94
95
96
97
98
99
100
101
102
103
104
105static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
106{
107 struct async_state *state = gf_map_info_to_state(map);
108
109 int this_len;
110
111 while (len) {
112 if ((from % state->win_size) + len > state->win_size)
113 this_len = state->win_size - (from % state->win_size);
114 else
115 this_len = len;
116
117 gf_set_gpios(state, from);
118 memcpy_fromio(to, map->virt + (from % state->win_size),
119 this_len);
120 len -= this_len;
121 from += this_len;
122 to += this_len;
123 }
124}
125
126
127
128
129
130
131static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
132{
133 struct async_state *state = gf_map_info_to_state(map);
134 uint16_t d;
135
136 gf_set_gpios(state, ofs);
137
138 d = d1.x[0];
139 writew(d, map->virt + (ofs % state->win_size));
140}
141
142
143
144
145
146
147
148
149
150
151static void gf_copy_to(struct map_info *map, unsigned long to,
152 const void *from, ssize_t len)
153{
154 struct async_state *state = gf_map_info_to_state(map);
155
156 int this_len;
157
158 while (len) {
159 if ((to % state->win_size) + len > state->win_size)
160 this_len = state->win_size - (to % state->win_size);
161 else
162 this_len = len;
163
164 gf_set_gpios(state, to);
165 memcpy_toio(map->virt + (to % state->win_size), from, len);
166
167 len -= this_len;
168 to += this_len;
169 from += this_len;
170 }
171}
172
173static const char * const part_probe_types[] = {
174 "cmdlinepart", "RedBoot", NULL };
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204static int gpio_flash_probe(struct platform_device *pdev)
205{
206 size_t i, arr_size;
207 struct physmap_flash_data *pdata;
208 struct resource *memory;
209 struct resource *gpios;
210 struct async_state *state;
211
212 pdata = dev_get_platdata(&pdev->dev);
213 memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
214 gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
215
216 if (!memory || !gpios || !gpios->end)
217 return -EINVAL;
218
219 arr_size = sizeof(int) * gpios->end;
220 state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL);
221 if (!state)
222 return -ENOMEM;
223
224
225
226
227
228 state->gpio_count = gpios->end;
229 state->gpio_addrs = (void *)(unsigned long)gpios->start;
230 state->gpio_values = (void *)(state + 1);
231 state->win_size = resource_size(memory);
232 memset(state->gpio_values, 0xff, arr_size);
233
234 state->map.name = DRIVER_NAME;
235 state->map.read = gf_read;
236 state->map.copy_from = gf_copy_from;
237 state->map.write = gf_write;
238 state->map.copy_to = gf_copy_to;
239 state->map.bankwidth = pdata->width;
240 state->map.size = state->win_size * (1 << state->gpio_count);
241 state->map.virt = ioremap_nocache(memory->start, state->map.size);
242 state->map.phys = NO_XIP;
243 state->map.map_priv_1 = (unsigned long)state;
244
245 platform_set_drvdata(pdev, state);
246
247 i = 0;
248 do {
249 if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) {
250 pr_devinit(KERN_ERR PFX "failed to request gpio %d\n",
251 state->gpio_addrs[i]);
252 while (i--)
253 gpio_free(state->gpio_addrs[i]);
254 kfree(state);
255 return -EBUSY;
256 }
257 gpio_direction_output(state->gpio_addrs[i], 0);
258 } while (++i < state->gpio_count);
259
260 pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n",
261 state->map.bankwidth * 8);
262 state->mtd = do_map_probe(memory->name, &state->map);
263 if (!state->mtd) {
264 for (i = 0; i < state->gpio_count; ++i)
265 gpio_free(state->gpio_addrs[i]);
266 kfree(state);
267 return -ENXIO;
268 }
269 state->mtd->dev.parent = &pdev->dev;
270
271 mtd_device_parse_register(state->mtd, part_probe_types, NULL,
272 pdata->parts, pdata->nr_parts);
273
274 return 0;
275}
276
277static int gpio_flash_remove(struct platform_device *pdev)
278{
279 struct async_state *state = platform_get_drvdata(pdev);
280 size_t i = 0;
281 do {
282 gpio_free(state->gpio_addrs[i]);
283 } while (++i < state->gpio_count);
284 mtd_device_unregister(state->mtd);
285 map_destroy(state->mtd);
286 kfree(state);
287 return 0;
288}
289
290static struct platform_driver gpio_flash_driver = {
291 .probe = gpio_flash_probe,
292 .remove = gpio_flash_remove,
293 .driver = {
294 .name = DRIVER_NAME,
295 },
296};
297
298module_platform_driver(gpio_flash_driver);
299
300MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
301MODULE_DESCRIPTION("MTD map driver for flashes addressed physically and with gpios");
302MODULE_LICENSE("GPL");
303