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 * const part_probe_types[] = {
161 "cmdlinepart", "RedBoot", NULL };
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
190
191static int gpio_flash_probe(struct platform_device *pdev)
192{
193 size_t i, arr_size;
194 struct physmap_flash_data *pdata;
195 struct resource *memory;
196 struct resource *gpios;
197 struct async_state *state;
198
199 pdata = pdev->dev.platform_data;
200 memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
201 gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
202
203 if (!memory || !gpios || !gpios->end)
204 return -EINVAL;
205
206 arr_size = sizeof(int) * gpios->end;
207 state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL);
208 if (!state)
209 return -ENOMEM;
210
211
212
213
214
215 state->gpio_count = gpios->end;
216 state->gpio_addrs = (void *)(unsigned long)gpios->start;
217 state->gpio_values = (void *)(state + 1);
218 state->win_size = resource_size(memory);
219 memset(state->gpio_values, 0xff, arr_size);
220
221 state->map.name = DRIVER_NAME;
222 state->map.read = gf_read;
223 state->map.copy_from = gf_copy_from;
224 state->map.write = gf_write;
225 state->map.copy_to = gf_copy_to;
226 state->map.bankwidth = pdata->width;
227 state->map.size = state->win_size * (1 << state->gpio_count);
228 state->map.virt = ioremap_nocache(memory->start, state->map.size);
229 state->map.phys = NO_XIP;
230 state->map.map_priv_1 = (unsigned long)state;
231
232 platform_set_drvdata(pdev, state);
233
234 i = 0;
235 do {
236 if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) {
237 pr_devinit(KERN_ERR PFX "failed to request gpio %d\n",
238 state->gpio_addrs[i]);
239 while (i--)
240 gpio_free(state->gpio_addrs[i]);
241 kfree(state);
242 return -EBUSY;
243 }
244 gpio_direction_output(state->gpio_addrs[i], 0);
245 } while (++i < state->gpio_count);
246
247 pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n",
248 state->map.bankwidth * 8);
249 state->mtd = do_map_probe(memory->name, &state->map);
250 if (!state->mtd) {
251 for (i = 0; i < state->gpio_count; ++i)
252 gpio_free(state->gpio_addrs[i]);
253 kfree(state);
254 return -ENXIO;
255 }
256
257
258 mtd_device_parse_register(state->mtd, part_probe_types, NULL,
259 pdata->parts, pdata->nr_parts);
260
261 return 0;
262}
263
264static int gpio_flash_remove(struct platform_device *pdev)
265{
266 struct async_state *state = platform_get_drvdata(pdev);
267 size_t i = 0;
268 do {
269 gpio_free(state->gpio_addrs[i]);
270 } while (++i < state->gpio_count);
271 mtd_device_unregister(state->mtd);
272 map_destroy(state->mtd);
273 kfree(state);
274 return 0;
275}
276
277static struct platform_driver gpio_flash_driver = {
278 .probe = gpio_flash_probe,
279 .remove = gpio_flash_remove,
280 .driver = {
281 .name = DRIVER_NAME,
282 },
283};
284
285module_platform_driver(gpio_flash_driver);
286
287MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
288MODULE_DESCRIPTION("MTD map driver for flashes addressed physically and with gpios");
289MODULE_LICENSE("GPL");
290