Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: SST25L (non JEDEC) SPI Flash driver

Add support for the non JEDEC SST25L SPI Flash devices.

[dwmw2: Some cleanups]

Signed-off-by: Andre Renaud <andre@bluewatersys.com>
Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Cc: Anton Vorontsov <avorontsov@ru.mvista.com>
Cc: "H Hartley Sweeten" <hartleys@visionengravers.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Ryan Mallon and committed by
David Woodhouse
ec77e21b 91e0955b

+521
+10
drivers/mtd/devices/Kconfig
··· 104 104 help 105 105 This option enables FAST_READ access supported by ST M25Pxx. 106 106 107 + config MTD_SST25L 108 + tristate "Support SST25L (non JEDEC) SPI Flash chips" 109 + depends on SPI_MASTER 110 + help 111 + This enables access to the non JEDEC SST25L SPI flash chips, used 112 + for program and data storage. 113 + 114 + Set up your spi devices with the right board-specific platform data, 115 + if you want to specify device partitioning. 116 + 107 117 config MTD_SLRAM 108 118 tristate "Uncached system RAM" 109 119 help
+1
drivers/mtd/devices/Makefile
··· 16 16 obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o 17 17 obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o 18 18 obj-$(CONFIG_MTD_M25P80) += m25p80.o 19 + obj-$(CONFIG_MTD_SST25L) += sst25l.o
+510
drivers/mtd/devices/sst25l.c
··· 1 + /* 2 + * sst25l.c 3 + * 4 + * Driver for SST25L SPI Flash chips 5 + * 6 + * Copyright © 2009 Bluewater Systems Ltd 7 + * Author: Andre Renaud <andre@bluewatersys.com> 8 + * Author: Ryan Mallon <ryan@bluewatersys.com> 9 + * 10 + * Based on m25p80.c 11 + * 12 + * This code is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + */ 17 + 18 + #include <linux/init.h> 19 + #include <linux/module.h> 20 + #include <linux/device.h> 21 + #include <linux/mutex.h> 22 + #include <linux/interrupt.h> 23 + 24 + #include <linux/mtd/mtd.h> 25 + #include <linux/mtd/partitions.h> 26 + 27 + #include <linux/spi/spi.h> 28 + #include <linux/spi/flash.h> 29 + 30 + /* Erases can take up to 3 seconds! */ 31 + #define MAX_READY_WAIT_JIFFIES msecs_to_jiffies(3000) 32 + 33 + #define SST25L_CMD_WRSR 0x01 /* Write status register */ 34 + #define SST25L_CMD_WRDI 0x04 /* Write disable */ 35 + #define SST25L_CMD_RDSR 0x05 /* Read status register */ 36 + #define SST25L_CMD_WREN 0x06 /* Write enable */ 37 + #define SST25L_CMD_READ 0x03 /* High speed read */ 38 + 39 + #define SST25L_CMD_EWSR 0x50 /* Enable write status register */ 40 + #define SST25L_CMD_SECTOR_ERASE 0x20 /* Erase sector */ 41 + #define SST25L_CMD_READ_ID 0x90 /* Read device ID */ 42 + #define SST25L_CMD_AAI_PROGRAM 0xaf /* Auto address increment */ 43 + 44 + #define SST25L_STATUS_BUSY (1 << 0) /* Chip is busy */ 45 + #define SST25L_STATUS_WREN (1 << 1) /* Write enabled */ 46 + #define SST25L_STATUS_BP0 (1 << 2) /* Block protection 0 */ 47 + #define SST25L_STATUS_BP1 (1 << 3) /* Block protection 1 */ 48 + 49 + struct sst25l_flash { 50 + struct spi_device *spi; 51 + struct mutex lock; 52 + struct mtd_info mtd; 53 + 54 + int partitioned; 55 + }; 56 + 57 + struct flash_info { 58 + const char *name; 59 + uint16_t device_id; 60 + unsigned page_size; 61 + unsigned nr_pages; 62 + unsigned erase_size; 63 + }; 64 + 65 + #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd) 66 + 67 + static struct flash_info __initdata sst25l_flash_info[] = { 68 + {"sst25lf020a", 0xbf43, 256, 1024, 4096}, 69 + {"sst25lf040a", 0xbf44, 256, 2048, 4096}, 70 + }; 71 + 72 + static int sst25l_status(struct sst25l_flash *flash, int *status) 73 + { 74 + unsigned char command, response; 75 + int err; 76 + 77 + command = SST25L_CMD_RDSR; 78 + err = spi_write_then_read(flash->spi, &command, 1, &response, 1); 79 + if (err < 0) 80 + return err; 81 + 82 + *status = response; 83 + return 0; 84 + } 85 + 86 + static int sst25l_write_enable(struct sst25l_flash *flash, int enable) 87 + { 88 + unsigned char command[2]; 89 + int status, err; 90 + 91 + command[0] = enable ? SST25L_CMD_WREN : SST25L_CMD_WRDI; 92 + err = spi_write(flash->spi, command, 1); 93 + if (err) 94 + return err; 95 + 96 + command[0] = SST25L_CMD_EWSR; 97 + err = spi_write(flash->spi, command, 1); 98 + if (err) 99 + return err; 100 + 101 + command[0] = SST25L_CMD_WRSR; 102 + command[1] = enable ? 0 : SST25L_STATUS_BP0 | SST25L_STATUS_BP1; 103 + err = spi_write(flash->spi, command, 2); 104 + if (err) 105 + return err; 106 + 107 + if (enable) { 108 + err = sst25l_status(flash, &status); 109 + if (err) 110 + return err; 111 + if (!(status & SST25L_STATUS_WREN)) 112 + return -EROFS; 113 + } 114 + 115 + return 0; 116 + } 117 + 118 + static int sst25l_wait_till_ready(struct sst25l_flash *flash) 119 + { 120 + unsigned long deadline; 121 + int status, err; 122 + 123 + deadline = jiffies + MAX_READY_WAIT_JIFFIES; 124 + do { 125 + err = sst25l_status(flash, &status); 126 + if (err) 127 + return err; 128 + if (!(status & SST25L_STATUS_BUSY)) 129 + return 0; 130 + 131 + cond_resched(); 132 + } while (!time_after_eq(jiffies, deadline)); 133 + 134 + return -ETIMEDOUT; 135 + } 136 + 137 + static int sst25l_erase_sector(struct sst25l_flash *flash, uint32_t offset) 138 + { 139 + unsigned char command[4]; 140 + int err; 141 + 142 + err = sst25l_write_enable(flash, 1); 143 + if (err) 144 + return err; 145 + 146 + command[0] = SST25L_CMD_SECTOR_ERASE; 147 + command[1] = offset >> 16; 148 + command[2] = offset >> 8; 149 + command[3] = offset; 150 + err = spi_write(flash->spi, command, 4); 151 + if (err) 152 + return err; 153 + 154 + err = sst25l_wait_till_ready(flash); 155 + if (err) 156 + return err; 157 + 158 + return sst25l_write_enable(flash, 0); 159 + } 160 + 161 + static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) 162 + { 163 + struct sst25l_flash *flash = to_sst25l_flash(mtd); 164 + uint32_t addr, end; 165 + int err; 166 + 167 + /* Sanity checks */ 168 + if (instr->addr + instr->len > flash->mtd.size) 169 + return -EINVAL; 170 + 171 + if ((uint32_t)instr->len % mtd->erasesize) 172 + return -EINVAL; 173 + 174 + if ((uint32_t)instr->addr % mtd->erasesize) 175 + return -EINVAL; 176 + 177 + addr = instr->addr; 178 + end = addr + instr->len; 179 + 180 + mutex_lock(&flash->lock); 181 + 182 + err = sst25l_wait_till_ready(flash); 183 + if (err) 184 + return err; 185 + 186 + while (addr < end) { 187 + err = sst25l_erase_sector(flash, addr); 188 + if (err) { 189 + mutex_unlock(&flash->lock); 190 + instr->state = MTD_ERASE_FAILED; 191 + dev_err(&flash->spi->dev, "Erase failed\n"); 192 + return err; 193 + } 194 + 195 + addr += mtd->erasesize; 196 + } 197 + 198 + mutex_unlock(&flash->lock); 199 + 200 + instr->state = MTD_ERASE_DONE; 201 + mtd_erase_callback(instr); 202 + return 0; 203 + } 204 + 205 + static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len, 206 + size_t *retlen, unsigned char *buf) 207 + { 208 + struct sst25l_flash *flash = to_sst25l_flash(mtd); 209 + struct spi_transfer transfer[2]; 210 + struct spi_message message; 211 + unsigned char command[4]; 212 + int ret; 213 + 214 + /* Sanity checking */ 215 + if (len == 0) 216 + return 0; 217 + 218 + if (from + len > flash->mtd.size) 219 + return -EINVAL; 220 + 221 + if (retlen) 222 + *retlen = 0; 223 + 224 + spi_message_init(&message); 225 + memset(&transfer, 0, sizeof(transfer)); 226 + 227 + command[0] = SST25L_CMD_READ; 228 + command[1] = from >> 16; 229 + command[2] = from >> 8; 230 + command[3] = from; 231 + 232 + transfer[0].tx_buf = command; 233 + transfer[0].len = sizeof(command); 234 + spi_message_add_tail(&transfer[0], &message); 235 + 236 + transfer[1].rx_buf = buf; 237 + transfer[1].len = len; 238 + spi_message_add_tail(&transfer[1], &message); 239 + 240 + mutex_lock(&flash->lock); 241 + 242 + /* Wait for previous write/erase to complete */ 243 + ret = sst25l_wait_till_ready(flash); 244 + if (ret) { 245 + mutex_unlock(&flash->lock); 246 + return ret; 247 + } 248 + 249 + spi_sync(flash->spi, &message); 250 + 251 + if (retlen && message.actual_length > sizeof(command)) 252 + *retlen += message.actual_length - sizeof(command); 253 + 254 + mutex_unlock(&flash->lock); 255 + return 0; 256 + } 257 + 258 + static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, 259 + size_t *retlen, const unsigned char *buf) 260 + { 261 + struct sst25l_flash *flash = to_sst25l_flash(mtd); 262 + int i, j, ret, bytes, copied = 0; 263 + unsigned char command[5]; 264 + 265 + /* Sanity checks */ 266 + if (!len) 267 + return 0; 268 + 269 + if (to + len > flash->mtd.size) 270 + return -EINVAL; 271 + 272 + if ((uint32_t)to % mtd->writesize) 273 + return -EINVAL; 274 + 275 + mutex_lock(&flash->lock); 276 + 277 + ret = sst25l_write_enable(flash, 1); 278 + if (ret) 279 + goto out; 280 + 281 + for (i = 0; i < len; i += mtd->writesize) { 282 + ret = sst25l_wait_till_ready(flash); 283 + if (ret) 284 + goto out; 285 + 286 + /* Write the first byte of the page */ 287 + command[0] = SST25L_CMD_AAI_PROGRAM; 288 + command[1] = (to + i) >> 16; 289 + command[2] = (to + i) >> 8; 290 + command[3] = (to + i); 291 + command[4] = buf[i]; 292 + ret = spi_write(flash->spi, command, 5); 293 + if (ret < 0) 294 + goto out; 295 + copied++; 296 + 297 + /* 298 + * Write the remaining bytes using auto address 299 + * increment mode 300 + */ 301 + bytes = min_t(uint32_t, mtd->writesize, len - i); 302 + for (j = 1; j < bytes; j++, copied++) { 303 + ret = sst25l_wait_till_ready(flash); 304 + if (ret) 305 + goto out; 306 + 307 + command[1] = buf[i + j]; 308 + ret = spi_write(flash->spi, command, 2); 309 + if (ret) 310 + goto out; 311 + } 312 + } 313 + 314 + out: 315 + ret = sst25l_write_enable(flash, 0); 316 + 317 + if (retlen) 318 + *retlen = copied; 319 + 320 + mutex_unlock(&flash->lock); 321 + return ret; 322 + } 323 + 324 + static struct flash_info *__init sst25l_match_device(struct spi_device *spi) 325 + { 326 + struct flash_info *flash_info = NULL; 327 + unsigned char command[4], response; 328 + int i, err; 329 + uint16_t id; 330 + 331 + command[0] = SST25L_CMD_READ_ID; 332 + command[1] = 0; 333 + command[2] = 0; 334 + command[3] = 0; 335 + err = spi_write_then_read(spi, command, sizeof(command), &response, 1); 336 + if (err < 0) { 337 + dev_err(&spi->dev, "error reading device id msb\n"); 338 + return NULL; 339 + } 340 + 341 + id = response << 8; 342 + 343 + command[0] = SST25L_CMD_READ_ID; 344 + command[1] = 0; 345 + command[2] = 0; 346 + command[3] = 1; 347 + err = spi_write_then_read(spi, command, sizeof(command), &response, 1); 348 + if (err < 0) { 349 + dev_err(&spi->dev, "error reading device id lsb\n"); 350 + return NULL; 351 + } 352 + 353 + id |= response; 354 + 355 + for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++) 356 + if (sst25l_flash_info[i].device_id == id) 357 + flash_info = &sst25l_flash_info[i]; 358 + 359 + if (!flash_info) 360 + dev_err(&spi->dev, "unknown id %.4x\n", id); 361 + 362 + return flash_info; 363 + } 364 + 365 + static int __init sst25l_probe(struct spi_device *spi) 366 + { 367 + struct flash_info *flash_info; 368 + struct sst25l_flash *flash; 369 + struct flash_platform_data *data; 370 + int ret, i; 371 + 372 + flash_info = sst25l_match_device(spi); 373 + if (!flash_info) 374 + return -ENODEV; 375 + 376 + flash = kzalloc(sizeof(struct sst25l_flash), GFP_KERNEL); 377 + if (!flash) 378 + return -ENOMEM; 379 + 380 + flash->spi = spi; 381 + mutex_init(&flash->lock); 382 + dev_set_drvdata(&spi->dev, flash); 383 + 384 + data = spi->dev.platform_data; 385 + if (data && data->name) 386 + flash->mtd.name = data->name; 387 + else 388 + flash->mtd.name = dev_name(&spi->dev); 389 + 390 + flash->mtd.type = MTD_NORFLASH; 391 + flash->mtd.flags = MTD_CAP_NORFLASH; 392 + flash->mtd.erasesize = flash_info->erase_size; 393 + flash->mtd.writesize = flash_info->page_size; 394 + flash->mtd.size = flash_info->page_size * flash_info->nr_pages; 395 + flash->mtd.erase = sst25l_erase; 396 + flash->mtd.read = sst25l_read; 397 + flash->mtd.write = sst25l_write; 398 + 399 + dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, 400 + (long long)flash->mtd.size >> 10); 401 + 402 + DEBUG(MTD_DEBUG_LEVEL2, 403 + "mtd .name = %s, .size = 0x%llx (%lldMiB) " 404 + ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", 405 + flash->mtd.name, 406 + (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), 407 + flash->mtd.erasesize, flash->mtd.erasesize / 1024, 408 + flash->mtd.numeraseregions); 409 + 410 + if (flash->mtd.numeraseregions) 411 + for (i = 0; i < flash->mtd.numeraseregions; i++) 412 + DEBUG(MTD_DEBUG_LEVEL2, 413 + "mtd.eraseregions[%d] = { .offset = 0x%llx, " 414 + ".erasesize = 0x%.8x (%uKiB), " 415 + ".numblocks = %d }\n", 416 + i, (long long)flash->mtd.eraseregions[i].offset, 417 + flash->mtd.eraseregions[i].erasesize, 418 + flash->mtd.eraseregions[i].erasesize / 1024, 419 + flash->mtd.eraseregions[i].numblocks); 420 + 421 + if (mtd_has_partitions()) { 422 + struct mtd_partition *parts = NULL; 423 + int nr_parts = 0; 424 + 425 + if (mtd_has_cmdlinepart()) { 426 + static const char *part_probes[] = 427 + {"cmdlinepart", NULL}; 428 + 429 + nr_parts = parse_mtd_partitions(&flash->mtd, 430 + part_probes, 431 + &parts, 0); 432 + } 433 + 434 + if (nr_parts <= 0 && data && data->parts) { 435 + parts = data->parts; 436 + nr_parts = data->nr_parts; 437 + } 438 + 439 + if (nr_parts > 0) { 440 + for (i = 0; i < nr_parts; i++) { 441 + DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " 442 + "{.name = %s, .offset = 0x%llx, " 443 + ".size = 0x%llx (%lldKiB) }\n", 444 + i, parts[i].name, 445 + (long long)parts[i].offset, 446 + (long long)parts[i].size, 447 + (long long)(parts[i].size >> 10)); 448 + } 449 + 450 + flash->partitioned = 1; 451 + return add_mtd_partitions(&flash->mtd, 452 + parts, nr_parts); 453 + } 454 + 455 + } else if (data->nr_parts) { 456 + dev_warn(&spi->dev, "ignoring %d default partitions on %s\n", 457 + data->nr_parts, data->name); 458 + } 459 + 460 + ret = add_mtd_device(&flash->mtd); 461 + if (ret == 1) { 462 + kfree(flash); 463 + dev_set_drvdata(&spi->dev, NULL); 464 + return -ENODEV; 465 + } 466 + 467 + return 0; 468 + } 469 + 470 + static int __exit sst25l_remove(struct spi_device *spi) 471 + { 472 + struct sst25l_flash *flash = dev_get_drvdata(&spi->dev); 473 + int ret; 474 + 475 + if (mtd_has_partitions() && flash->partitioned) 476 + ret = del_mtd_partitions(&flash->mtd); 477 + else 478 + ret = del_mtd_device(&flash->mtd); 479 + if (ret == 0) 480 + kfree(flash); 481 + return ret; 482 + } 483 + 484 + static struct spi_driver sst25l_driver = { 485 + .driver = { 486 + .name = "sst25l", 487 + .bus = &spi_bus_type, 488 + .owner = THIS_MODULE, 489 + }, 490 + .probe = sst25l_probe, 491 + .remove = __exit_p(sst25l_remove), 492 + }; 493 + 494 + static int __init sst25l_init(void) 495 + { 496 + return spi_register_driver(&sst25l_driver); 497 + } 498 + 499 + static void __exit sst25l_exit(void) 500 + { 501 + spi_unregister_driver(&sst25l_driver); 502 + } 503 + 504 + module_init(sst25l_init); 505 + module_exit(sst25l_exit); 506 + 507 + MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips"); 508 + MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, " 509 + "Ryan Mallon <ryan@bluewatersys.com>"); 510 + MODULE_LICENSE("GPL");