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