Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / drivers / mtd / maps / pismo.c
1 /*
2  * PISMO memory driver - http://www.pismoworld.org/
3  *
4  * For ARM Realview and Versatile platforms
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  */
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/i2c.h>
13 #include <linux/platform_device.h>
14 #include <linux/spinlock.h>
15 #include <linux/mutex.h>
16 #include <linux/mtd/physmap.h>
17 #include <linux/mtd/plat-ram.h>
18 #include <linux/mtd/pismo.h>
19
20 #define PISMO_NUM_CS    5
21
22 struct pismo_cs_block {
23         u8      type;
24         u8      width;
25         __le16  access;
26         __le32  size;
27         u32     reserved[2];
28         char    device[32];
29 } __packed;
30
31 struct pismo_eeprom {
32         struct pismo_cs_block cs[PISMO_NUM_CS];
33         char    board[15];
34         u8      sum;
35 } __packed;
36
37 struct pismo_mem {
38         phys_addr_t base;
39         u32     size;
40         u16     access;
41         u8      width;
42         u8      type;
43 };
44
45 struct pismo_data {
46         struct i2c_client       *client;
47         void                    (*vpp)(void *, int);
48         void                    *vpp_data;
49         struct platform_device  *dev[PISMO_NUM_CS];
50 };
51
52 /* FIXME: set_vpp could do with a better calling convention */
53 static struct pismo_data *vpp_pismo;
54 static DEFINE_MUTEX(pismo_mutex);
55
56 static int pismo_setvpp_probe_fix(struct pismo_data *pismo)
57 {
58         mutex_lock(&pismo_mutex);
59         if (vpp_pismo) {
60                 mutex_unlock(&pismo_mutex);
61                 kfree(pismo);
62                 return -EBUSY;
63         }
64         vpp_pismo = pismo;
65         mutex_unlock(&pismo_mutex);
66         return 0;
67 }
68
69 static void pismo_setvpp_remove_fix(struct pismo_data *pismo)
70 {
71         mutex_lock(&pismo_mutex);
72         if (vpp_pismo == pismo)
73                 vpp_pismo = NULL;
74         mutex_unlock(&pismo_mutex);
75 }
76
77 static void pismo_set_vpp(struct map_info *map, int on)
78 {
79         struct pismo_data *pismo = vpp_pismo;
80
81         pismo->vpp(pismo->vpp_data, on);
82 }
83 /* end of hack */
84
85
86 static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
87 {
88         width &= 15;
89         if (width > 2)
90                 return 0;
91         return 1 << width;
92 }
93
94 static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
95         u8 addr, size_t size)
96 {
97         int ret;
98         struct i2c_msg msg[] = {
99                 {
100                         .addr = client->addr,
101                         .len = sizeof(addr),
102                         .buf = &addr,
103                 }, {
104                         .addr = client->addr,
105                         .flags = I2C_M_RD,
106                         .len = size,
107                         .buf = buf,
108                 },
109         };
110
111         ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
112
113         return ret == ARRAY_SIZE(msg) ? size : -EIO;
114 }
115
116 static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
117         struct pismo_mem *region, const char *name, void *pdata, size_t psize)
118 {
119         struct platform_device *dev;
120         struct resource res = { };
121         phys_addr_t base = region->base;
122         int ret;
123
124         if (base == ~0)
125                 return -ENXIO;
126
127         res.start = base;
128         res.end = base + region->size - 1;
129         res.flags = IORESOURCE_MEM;
130
131         dev = platform_device_alloc(name, i);
132         if (!dev)
133                 return -ENOMEM;
134         dev->dev.parent = &pismo->client->dev;
135
136         do {
137                 ret = platform_device_add_resources(dev, &res, 1);
138                 if (ret)
139                         break;
140
141                 ret = platform_device_add_data(dev, pdata, psize);
142                 if (ret)
143                         break;
144
145                 ret = platform_device_add(dev);
146                 if (ret)
147                         break;
148
149                 pismo->dev[i] = dev;
150                 return 0;
151         } while (0);
152
153         platform_device_put(dev);
154         return ret;
155 }
156
157 static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
158         struct pismo_mem *region)
159 {
160         struct physmap_flash_data data = {
161                 .width = region->width,
162         };
163
164         if (pismo->vpp)
165                 data.set_vpp = pismo_set_vpp;
166
167         return pismo_add_device(pismo, i, region, "physmap-flash",
168                 &data, sizeof(data));
169 }
170
171 static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
172         struct pismo_mem *region)
173 {
174         struct platdata_mtd_ram data = {
175                 .bankwidth = region->width,
176         };
177
178         return pismo_add_device(pismo, i, region, "mtd-ram",
179                 &data, sizeof(data));
180 }
181
182 static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
183         const struct pismo_cs_block *cs, phys_addr_t base)
184 {
185         struct device *dev = &pismo->client->dev;
186         struct pismo_mem region;
187
188         region.base = base;
189         region.type = cs->type;
190         region.width = pismo_width_to_bytes(cs->width);
191         region.access = le16_to_cpu(cs->access);
192         region.size = le32_to_cpu(cs->size);
193
194         if (region.width == 0) {
195                 dev_err(dev, "cs%u: bad width: %02x, ignoring\n", i, cs->width);
196                 return;
197         }
198
199         /*
200          * FIXME: may need to the platforms memory controller here, but at
201          * the moment we assume that it has already been correctly setup.
202          * The memory controller can also tell us the base address as well.
203          */
204
205         dev_info(dev, "cs%u: %.32s: type %02x access %u00ps size %uK\n",
206                 i, cs->device, region.type, region.access, region.size / 1024);
207
208         switch (region.type) {
209         case 0:
210                 break;
211         case 1:
212                 /* static DOC */
213                 break;
214         case 2:
215                 /* static NOR */
216                 pismo_add_nor(pismo, i, &region);
217                 break;
218         case 3:
219                 /* static RAM */
220                 pismo_add_sram(pismo, i, &region);
221                 break;
222         }
223 }
224
225 static int __devexit pismo_remove(struct i2c_client *client)
226 {
227         struct pismo_data *pismo = i2c_get_clientdata(client);
228         int i;
229
230         for (i = 0; i < ARRAY_SIZE(pismo->dev); i++)
231                 platform_device_unregister(pismo->dev[i]);
232
233         /* FIXME: set_vpp needs saner arguments */
234         pismo_setvpp_remove_fix(pismo);
235
236         i2c_set_clientdata(client, NULL);
237         kfree(pismo);
238
239         return 0;
240 }
241
242 static int __devinit pismo_probe(struct i2c_client *client,
243                                  const struct i2c_device_id *id)
244 {
245         struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
246         struct pismo_pdata *pdata = client->dev.platform_data;
247         struct pismo_eeprom eeprom;
248         struct pismo_data *pismo;
249         int ret, i;
250
251         if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
252                 dev_err(&client->dev, "functionality mismatch\n");
253                 return -EIO;
254         }
255
256         pismo = kzalloc(sizeof(*pismo), GFP_KERNEL);
257         if (!pismo)
258                 return -ENOMEM;
259
260         /* FIXME: set_vpp needs saner arguments */
261         ret = pismo_setvpp_probe_fix(pismo);
262         if (ret)
263                 return ret;
264
265         pismo->client = client;
266         if (pdata) {
267                 pismo->vpp = pdata->set_vpp;
268                 pismo->vpp_data = pdata->vpp_data;
269         }
270         i2c_set_clientdata(client, pismo);
271
272         ret = pismo_eeprom_read(client, &eeprom, 0, sizeof(eeprom));
273         if (ret < 0) {
274                 dev_err(&client->dev, "error reading EEPROM: %d\n", ret);
275                 goto exit_free;
276         }
277
278         dev_info(&client->dev, "%.15s board found\n", eeprom.board);
279
280         for (i = 0; i < ARRAY_SIZE(eeprom.cs); i++)
281                 if (eeprom.cs[i].type != 0xff)
282                         pismo_add_one(pismo, i, &eeprom.cs[i],
283                                       pdata->cs_addrs[i]);
284
285         return 0;
286
287  exit_free:
288         i2c_set_clientdata(client, NULL);
289         kfree(pismo);
290         return ret;
291 }
292
293 static const struct i2c_device_id pismo_id[] = {
294         { "pismo" },
295         { },
296 };
297 MODULE_DEVICE_TABLE(i2c, pismo_id);
298
299 static struct i2c_driver pismo_driver = {
300         .driver = {
301                 .name   = "pismo",
302                 .owner  = THIS_MODULE,
303         },
304         .probe          = pismo_probe,
305         .remove         = __devexit_p(pismo_remove),
306         .id_table       = pismo_id,
307 };
308
309 static int __init pismo_init(void)
310 {
311         BUILD_BUG_ON(sizeof(struct pismo_cs_block) != 48);
312         BUILD_BUG_ON(sizeof(struct pismo_eeprom) != 256);
313
314         return i2c_add_driver(&pismo_driver);
315 }
316 module_init(pismo_init);
317
318 static void __exit pismo_exit(void)
319 {
320         i2c_del_driver(&pismo_driver);
321 }
322 module_exit(pismo_exit);
323
324 MODULE_AUTHOR("Russell King <linux@arm.linux.org.uk>");
325 MODULE_DESCRIPTION("PISMO memory driver");
326 MODULE_LICENSE("GPL");