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