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 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 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 91 static 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 133 static 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 147 static 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 158 static 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, ®ion); 193 break; 194 case 3: 195 /* static RAM */ 196 pismo_add_sram(pismo, i, ®ion); 197 break; 198 } 199 } 200 201 static 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 214 static 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 259 static const struct i2c_device_id pismo_id[] = { 260 { "pismo" }, 261 { }, 262 }; 263 MODULE_DEVICE_TABLE(i2c, pismo_id); 264 265 static struct i2c_driver pismo_driver = { 266 .driver = { 267 .name = "pismo", 268 }, 269 .probe = pismo_probe, 270 .remove = 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