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