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