1ec77e21bSRyan Mallon /* 2ec77e21bSRyan Mallon * sst25l.c 3ec77e21bSRyan Mallon * 4ec77e21bSRyan Mallon * Driver for SST25L SPI Flash chips 5ec77e21bSRyan Mallon * 6ec77e21bSRyan Mallon * Copyright © 2009 Bluewater Systems Ltd 7ec77e21bSRyan Mallon * Author: Andre Renaud <andre@bluewatersys.com> 81c5454eeSRyan Mallon * Author: Ryan Mallon 9ec77e21bSRyan Mallon * 10ec77e21bSRyan Mallon * Based on m25p80.c 11ec77e21bSRyan Mallon * 12ec77e21bSRyan Mallon * This code is free software; you can redistribute it and/or modify 13ec77e21bSRyan Mallon * it under the terms of the GNU General Public License version 2 as 14ec77e21bSRyan Mallon * published by the Free Software Foundation. 15ec77e21bSRyan Mallon * 16ec77e21bSRyan Mallon */ 17ec77e21bSRyan Mallon 18ec77e21bSRyan Mallon #include <linux/init.h> 19ec77e21bSRyan Mallon #include <linux/module.h> 20ec77e21bSRyan Mallon #include <linux/device.h> 21ec77e21bSRyan Mallon #include <linux/mutex.h> 22ec77e21bSRyan Mallon #include <linux/interrupt.h> 235a0e3ad6STejun Heo #include <linux/slab.h> 24d43c36dcSAlexey Dobriyan #include <linux/sched.h> 25ec77e21bSRyan Mallon 26ec77e21bSRyan Mallon #include <linux/mtd/mtd.h> 27ec77e21bSRyan Mallon #include <linux/mtd/partitions.h> 28ec77e21bSRyan Mallon 29ec77e21bSRyan Mallon #include <linux/spi/spi.h> 30ec77e21bSRyan Mallon #include <linux/spi/flash.h> 31ec77e21bSRyan Mallon 32ec77e21bSRyan Mallon /* Erases can take up to 3 seconds! */ 33ec77e21bSRyan Mallon #define MAX_READY_WAIT_JIFFIES msecs_to_jiffies(3000) 34ec77e21bSRyan Mallon 35ec77e21bSRyan Mallon #define SST25L_CMD_WRSR 0x01 /* Write status register */ 36ec77e21bSRyan Mallon #define SST25L_CMD_WRDI 0x04 /* Write disable */ 37ec77e21bSRyan Mallon #define SST25L_CMD_RDSR 0x05 /* Read status register */ 38ec77e21bSRyan Mallon #define SST25L_CMD_WREN 0x06 /* Write enable */ 39ec77e21bSRyan Mallon #define SST25L_CMD_READ 0x03 /* High speed read */ 40ec77e21bSRyan Mallon 41ec77e21bSRyan Mallon #define SST25L_CMD_EWSR 0x50 /* Enable write status register */ 42ec77e21bSRyan Mallon #define SST25L_CMD_SECTOR_ERASE 0x20 /* Erase sector */ 43ec77e21bSRyan Mallon #define SST25L_CMD_READ_ID 0x90 /* Read device ID */ 44ec77e21bSRyan Mallon #define SST25L_CMD_AAI_PROGRAM 0xaf /* Auto address increment */ 45ec77e21bSRyan Mallon 46ec77e21bSRyan Mallon #define SST25L_STATUS_BUSY (1 << 0) /* Chip is busy */ 47ec77e21bSRyan Mallon #define SST25L_STATUS_WREN (1 << 1) /* Write enabled */ 48ec77e21bSRyan Mallon #define SST25L_STATUS_BP0 (1 << 2) /* Block protection 0 */ 49ec77e21bSRyan Mallon #define SST25L_STATUS_BP1 (1 << 3) /* Block protection 1 */ 50ec77e21bSRyan Mallon 51ec77e21bSRyan Mallon struct sst25l_flash { 52ec77e21bSRyan Mallon struct spi_device *spi; 53ec77e21bSRyan Mallon struct mutex lock; 54ec77e21bSRyan Mallon struct mtd_info mtd; 55ec77e21bSRyan Mallon }; 56ec77e21bSRyan Mallon 57ec77e21bSRyan Mallon struct flash_info { 58ec77e21bSRyan Mallon const char *name; 59ec77e21bSRyan Mallon uint16_t device_id; 60ec77e21bSRyan Mallon unsigned page_size; 61ec77e21bSRyan Mallon unsigned nr_pages; 62ec77e21bSRyan Mallon unsigned erase_size; 63ec77e21bSRyan Mallon }; 64ec77e21bSRyan Mallon 65ec77e21bSRyan Mallon #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd) 66ec77e21bSRyan Mallon 6761cc8276SMike Frysinger static struct flash_info __devinitdata sst25l_flash_info[] = { 68ec77e21bSRyan Mallon {"sst25lf020a", 0xbf43, 256, 1024, 4096}, 69ec77e21bSRyan Mallon {"sst25lf040a", 0xbf44, 256, 2048, 4096}, 70ec77e21bSRyan Mallon }; 71ec77e21bSRyan Mallon 72ec77e21bSRyan Mallon static int sst25l_status(struct sst25l_flash *flash, int *status) 73ec77e21bSRyan Mallon { 740ffe0ce3SH Hartley Sweeten struct spi_message m; 750ffe0ce3SH Hartley Sweeten struct spi_transfer t; 760ffe0ce3SH Hartley Sweeten unsigned char cmd_resp[2]; 77ec77e21bSRyan Mallon int err; 78ec77e21bSRyan Mallon 790ffe0ce3SH Hartley Sweeten spi_message_init(&m); 800ffe0ce3SH Hartley Sweeten memset(&t, 0, sizeof(struct spi_transfer)); 810ffe0ce3SH Hartley Sweeten 820ffe0ce3SH Hartley Sweeten cmd_resp[0] = SST25L_CMD_RDSR; 830ffe0ce3SH Hartley Sweeten cmd_resp[1] = 0xff; 840ffe0ce3SH Hartley Sweeten t.tx_buf = cmd_resp; 850ffe0ce3SH Hartley Sweeten t.rx_buf = cmd_resp; 860ffe0ce3SH Hartley Sweeten t.len = sizeof(cmd_resp); 870ffe0ce3SH Hartley Sweeten spi_message_add_tail(&t, &m); 880ffe0ce3SH Hartley Sweeten err = spi_sync(flash->spi, &m); 89ec77e21bSRyan Mallon if (err < 0) 90ec77e21bSRyan Mallon return err; 91ec77e21bSRyan Mallon 920ffe0ce3SH Hartley Sweeten *status = cmd_resp[1]; 93ec77e21bSRyan Mallon return 0; 94ec77e21bSRyan Mallon } 95ec77e21bSRyan Mallon 96ec77e21bSRyan Mallon static int sst25l_write_enable(struct sst25l_flash *flash, int enable) 97ec77e21bSRyan Mallon { 98ec77e21bSRyan Mallon unsigned char command[2]; 99ec77e21bSRyan Mallon int status, err; 100ec77e21bSRyan Mallon 101ec77e21bSRyan Mallon command[0] = enable ? SST25L_CMD_WREN : SST25L_CMD_WRDI; 102ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 1); 103ec77e21bSRyan Mallon if (err) 104ec77e21bSRyan Mallon return err; 105ec77e21bSRyan Mallon 106ec77e21bSRyan Mallon command[0] = SST25L_CMD_EWSR; 107ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 1); 108ec77e21bSRyan Mallon if (err) 109ec77e21bSRyan Mallon return err; 110ec77e21bSRyan Mallon 111ec77e21bSRyan Mallon command[0] = SST25L_CMD_WRSR; 112ec77e21bSRyan Mallon command[1] = enable ? 0 : SST25L_STATUS_BP0 | SST25L_STATUS_BP1; 113ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 2); 114ec77e21bSRyan Mallon if (err) 115ec77e21bSRyan Mallon return err; 116ec77e21bSRyan Mallon 117ec77e21bSRyan Mallon if (enable) { 118ec77e21bSRyan Mallon err = sst25l_status(flash, &status); 119ec77e21bSRyan Mallon if (err) 120ec77e21bSRyan Mallon return err; 121ec77e21bSRyan Mallon if (!(status & SST25L_STATUS_WREN)) 122ec77e21bSRyan Mallon return -EROFS; 123ec77e21bSRyan Mallon } 124ec77e21bSRyan Mallon 125ec77e21bSRyan Mallon return 0; 126ec77e21bSRyan Mallon } 127ec77e21bSRyan Mallon 128ec77e21bSRyan Mallon static int sst25l_wait_till_ready(struct sst25l_flash *flash) 129ec77e21bSRyan Mallon { 130ec77e21bSRyan Mallon unsigned long deadline; 131ec77e21bSRyan Mallon int status, err; 132ec77e21bSRyan Mallon 133ec77e21bSRyan Mallon deadline = jiffies + MAX_READY_WAIT_JIFFIES; 134ec77e21bSRyan Mallon do { 135ec77e21bSRyan Mallon err = sst25l_status(flash, &status); 136ec77e21bSRyan Mallon if (err) 137ec77e21bSRyan Mallon return err; 138ec77e21bSRyan Mallon if (!(status & SST25L_STATUS_BUSY)) 139ec77e21bSRyan Mallon return 0; 140ec77e21bSRyan Mallon 141ec77e21bSRyan Mallon cond_resched(); 142ec77e21bSRyan Mallon } while (!time_after_eq(jiffies, deadline)); 143ec77e21bSRyan Mallon 144ec77e21bSRyan Mallon return -ETIMEDOUT; 145ec77e21bSRyan Mallon } 146ec77e21bSRyan Mallon 147ec77e21bSRyan Mallon static int sst25l_erase_sector(struct sst25l_flash *flash, uint32_t offset) 148ec77e21bSRyan Mallon { 149ec77e21bSRyan Mallon unsigned char command[4]; 150ec77e21bSRyan Mallon int err; 151ec77e21bSRyan Mallon 152ec77e21bSRyan Mallon err = sst25l_write_enable(flash, 1); 153ec77e21bSRyan Mallon if (err) 154ec77e21bSRyan Mallon return err; 155ec77e21bSRyan Mallon 156ec77e21bSRyan Mallon command[0] = SST25L_CMD_SECTOR_ERASE; 157ec77e21bSRyan Mallon command[1] = offset >> 16; 158ec77e21bSRyan Mallon command[2] = offset >> 8; 159ec77e21bSRyan Mallon command[3] = offset; 160ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 4); 161ec77e21bSRyan Mallon if (err) 162ec77e21bSRyan Mallon return err; 163ec77e21bSRyan Mallon 164ec77e21bSRyan Mallon err = sst25l_wait_till_ready(flash); 165ec77e21bSRyan Mallon if (err) 166ec77e21bSRyan Mallon return err; 167ec77e21bSRyan Mallon 168ec77e21bSRyan Mallon return sst25l_write_enable(flash, 0); 169ec77e21bSRyan Mallon } 170ec77e21bSRyan Mallon 171ec77e21bSRyan Mallon static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) 172ec77e21bSRyan Mallon { 173ec77e21bSRyan Mallon struct sst25l_flash *flash = to_sst25l_flash(mtd); 174ec77e21bSRyan Mallon uint32_t addr, end; 175ec77e21bSRyan Mallon int err; 176ec77e21bSRyan Mallon 177ec77e21bSRyan Mallon /* Sanity checks */ 178ec77e21bSRyan Mallon if (instr->addr + instr->len > flash->mtd.size) 179ec77e21bSRyan Mallon return -EINVAL; 180ec77e21bSRyan Mallon 181ec77e21bSRyan Mallon if ((uint32_t)instr->len % mtd->erasesize) 182ec77e21bSRyan Mallon return -EINVAL; 183ec77e21bSRyan Mallon 184ec77e21bSRyan Mallon if ((uint32_t)instr->addr % mtd->erasesize) 185ec77e21bSRyan Mallon return -EINVAL; 186ec77e21bSRyan Mallon 187ec77e21bSRyan Mallon addr = instr->addr; 188ec77e21bSRyan Mallon end = addr + instr->len; 189ec77e21bSRyan Mallon 190ec77e21bSRyan Mallon mutex_lock(&flash->lock); 191ec77e21bSRyan Mallon 192ec77e21bSRyan Mallon err = sst25l_wait_till_ready(flash); 1932eaaa5ffSJiri Slaby if (err) { 1942eaaa5ffSJiri Slaby mutex_unlock(&flash->lock); 195ec77e21bSRyan Mallon return err; 1962eaaa5ffSJiri Slaby } 197ec77e21bSRyan Mallon 198ec77e21bSRyan Mallon while (addr < end) { 199ec77e21bSRyan Mallon err = sst25l_erase_sector(flash, addr); 200ec77e21bSRyan Mallon if (err) { 201ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 202ec77e21bSRyan Mallon instr->state = MTD_ERASE_FAILED; 203ec77e21bSRyan Mallon dev_err(&flash->spi->dev, "Erase failed\n"); 204ec77e21bSRyan Mallon return err; 205ec77e21bSRyan Mallon } 206ec77e21bSRyan Mallon 207ec77e21bSRyan Mallon addr += mtd->erasesize; 208ec77e21bSRyan Mallon } 209ec77e21bSRyan Mallon 210ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 211ec77e21bSRyan Mallon 212ec77e21bSRyan Mallon instr->state = MTD_ERASE_DONE; 213ec77e21bSRyan Mallon mtd_erase_callback(instr); 214ec77e21bSRyan Mallon return 0; 215ec77e21bSRyan Mallon } 216ec77e21bSRyan Mallon 217ec77e21bSRyan Mallon static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len, 218ec77e21bSRyan Mallon size_t *retlen, unsigned char *buf) 219ec77e21bSRyan Mallon { 220ec77e21bSRyan Mallon struct sst25l_flash *flash = to_sst25l_flash(mtd); 221ec77e21bSRyan Mallon struct spi_transfer transfer[2]; 222ec77e21bSRyan Mallon struct spi_message message; 223ec77e21bSRyan Mallon unsigned char command[4]; 224ec77e21bSRyan Mallon int ret; 225ec77e21bSRyan Mallon 226ec77e21bSRyan Mallon /* Sanity checking */ 227ec77e21bSRyan Mallon if (len == 0) 228ec77e21bSRyan Mallon return 0; 229ec77e21bSRyan Mallon 230ec77e21bSRyan Mallon if (from + len > flash->mtd.size) 231ec77e21bSRyan Mallon return -EINVAL; 232ec77e21bSRyan Mallon 233ec77e21bSRyan Mallon if (retlen) 234ec77e21bSRyan Mallon *retlen = 0; 235ec77e21bSRyan Mallon 236ec77e21bSRyan Mallon spi_message_init(&message); 237ec77e21bSRyan Mallon memset(&transfer, 0, sizeof(transfer)); 238ec77e21bSRyan Mallon 239ec77e21bSRyan Mallon command[0] = SST25L_CMD_READ; 240ec77e21bSRyan Mallon command[1] = from >> 16; 241ec77e21bSRyan Mallon command[2] = from >> 8; 242ec77e21bSRyan Mallon command[3] = from; 243ec77e21bSRyan Mallon 244ec77e21bSRyan Mallon transfer[0].tx_buf = command; 245ec77e21bSRyan Mallon transfer[0].len = sizeof(command); 246ec77e21bSRyan Mallon spi_message_add_tail(&transfer[0], &message); 247ec77e21bSRyan Mallon 248ec77e21bSRyan Mallon transfer[1].rx_buf = buf; 249ec77e21bSRyan Mallon transfer[1].len = len; 250ec77e21bSRyan Mallon spi_message_add_tail(&transfer[1], &message); 251ec77e21bSRyan Mallon 252ec77e21bSRyan Mallon mutex_lock(&flash->lock); 253ec77e21bSRyan Mallon 254ec77e21bSRyan Mallon /* Wait for previous write/erase to complete */ 255ec77e21bSRyan Mallon ret = sst25l_wait_till_ready(flash); 256ec77e21bSRyan Mallon if (ret) { 257ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 258ec77e21bSRyan Mallon return ret; 259ec77e21bSRyan Mallon } 260ec77e21bSRyan Mallon 261ec77e21bSRyan Mallon spi_sync(flash->spi, &message); 262ec77e21bSRyan Mallon 263ec77e21bSRyan Mallon if (retlen && message.actual_length > sizeof(command)) 264ec77e21bSRyan Mallon *retlen += message.actual_length - sizeof(command); 265ec77e21bSRyan Mallon 266ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 267ec77e21bSRyan Mallon return 0; 268ec77e21bSRyan Mallon } 269ec77e21bSRyan Mallon 270ec77e21bSRyan Mallon static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, 271ec77e21bSRyan Mallon size_t *retlen, const unsigned char *buf) 272ec77e21bSRyan Mallon { 273ec77e21bSRyan Mallon struct sst25l_flash *flash = to_sst25l_flash(mtd); 274ec77e21bSRyan Mallon int i, j, ret, bytes, copied = 0; 275ec77e21bSRyan Mallon unsigned char command[5]; 276ec77e21bSRyan Mallon 277ec77e21bSRyan Mallon /* Sanity checks */ 278ec77e21bSRyan Mallon if (!len) 279ec77e21bSRyan Mallon return 0; 280ec77e21bSRyan Mallon 281ec77e21bSRyan Mallon if (to + len > flash->mtd.size) 282ec77e21bSRyan Mallon return -EINVAL; 283ec77e21bSRyan Mallon 284ec77e21bSRyan Mallon if ((uint32_t)to % mtd->writesize) 285ec77e21bSRyan Mallon return -EINVAL; 286ec77e21bSRyan Mallon 287ec77e21bSRyan Mallon mutex_lock(&flash->lock); 288ec77e21bSRyan Mallon 289ec77e21bSRyan Mallon ret = sst25l_write_enable(flash, 1); 290ec77e21bSRyan Mallon if (ret) 291ec77e21bSRyan Mallon goto out; 292ec77e21bSRyan Mallon 293ec77e21bSRyan Mallon for (i = 0; i < len; i += mtd->writesize) { 294ec77e21bSRyan Mallon ret = sst25l_wait_till_ready(flash); 295ec77e21bSRyan Mallon if (ret) 296ec77e21bSRyan Mallon goto out; 297ec77e21bSRyan Mallon 298ec77e21bSRyan Mallon /* Write the first byte of the page */ 299ec77e21bSRyan Mallon command[0] = SST25L_CMD_AAI_PROGRAM; 300ec77e21bSRyan Mallon command[1] = (to + i) >> 16; 301ec77e21bSRyan Mallon command[2] = (to + i) >> 8; 302ec77e21bSRyan Mallon command[3] = (to + i); 303ec77e21bSRyan Mallon command[4] = buf[i]; 304ec77e21bSRyan Mallon ret = spi_write(flash->spi, command, 5); 305ec77e21bSRyan Mallon if (ret < 0) 306ec77e21bSRyan Mallon goto out; 307ec77e21bSRyan Mallon copied++; 308ec77e21bSRyan Mallon 309ec77e21bSRyan Mallon /* 310ec77e21bSRyan Mallon * Write the remaining bytes using auto address 311ec77e21bSRyan Mallon * increment mode 312ec77e21bSRyan Mallon */ 313ec77e21bSRyan Mallon bytes = min_t(uint32_t, mtd->writesize, len - i); 314ec77e21bSRyan Mallon for (j = 1; j < bytes; j++, copied++) { 315ec77e21bSRyan Mallon ret = sst25l_wait_till_ready(flash); 316ec77e21bSRyan Mallon if (ret) 317ec77e21bSRyan Mallon goto out; 318ec77e21bSRyan Mallon 319ec77e21bSRyan Mallon command[1] = buf[i + j]; 320ec77e21bSRyan Mallon ret = spi_write(flash->spi, command, 2); 321ec77e21bSRyan Mallon if (ret) 322ec77e21bSRyan Mallon goto out; 323ec77e21bSRyan Mallon } 324ec77e21bSRyan Mallon } 325ec77e21bSRyan Mallon 326ec77e21bSRyan Mallon out: 327ec77e21bSRyan Mallon ret = sst25l_write_enable(flash, 0); 328ec77e21bSRyan Mallon 329ec77e21bSRyan Mallon if (retlen) 330ec77e21bSRyan Mallon *retlen = copied; 331ec77e21bSRyan Mallon 332ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 333ec77e21bSRyan Mallon return ret; 334ec77e21bSRyan Mallon } 335ec77e21bSRyan Mallon 3366b2995b6SFabio Estevam static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) 337ec77e21bSRyan Mallon { 338ec77e21bSRyan Mallon struct flash_info *flash_info = NULL; 3390ffe0ce3SH Hartley Sweeten struct spi_message m; 3400ffe0ce3SH Hartley Sweeten struct spi_transfer t; 3410ffe0ce3SH Hartley Sweeten unsigned char cmd_resp[6]; 342ec77e21bSRyan Mallon int i, err; 343ec77e21bSRyan Mallon uint16_t id; 344ec77e21bSRyan Mallon 3450ffe0ce3SH Hartley Sweeten spi_message_init(&m); 3460ffe0ce3SH Hartley Sweeten memset(&t, 0, sizeof(struct spi_transfer)); 3470ffe0ce3SH Hartley Sweeten 3480ffe0ce3SH Hartley Sweeten cmd_resp[0] = SST25L_CMD_READ_ID; 3490ffe0ce3SH Hartley Sweeten cmd_resp[1] = 0; 3500ffe0ce3SH Hartley Sweeten cmd_resp[2] = 0; 3510ffe0ce3SH Hartley Sweeten cmd_resp[3] = 0; 3520ffe0ce3SH Hartley Sweeten cmd_resp[4] = 0xff; 3530ffe0ce3SH Hartley Sweeten cmd_resp[5] = 0xff; 3540ffe0ce3SH Hartley Sweeten t.tx_buf = cmd_resp; 3550ffe0ce3SH Hartley Sweeten t.rx_buf = cmd_resp; 3560ffe0ce3SH Hartley Sweeten t.len = sizeof(cmd_resp); 3570ffe0ce3SH Hartley Sweeten spi_message_add_tail(&t, &m); 3580ffe0ce3SH Hartley Sweeten err = spi_sync(spi, &m); 359ec77e21bSRyan Mallon if (err < 0) { 3600ffe0ce3SH Hartley Sweeten dev_err(&spi->dev, "error reading device id\n"); 361ec77e21bSRyan Mallon return NULL; 362ec77e21bSRyan Mallon } 363ec77e21bSRyan Mallon 3640ffe0ce3SH Hartley Sweeten id = (cmd_resp[4] << 8) | cmd_resp[5]; 365ec77e21bSRyan Mallon 366ec77e21bSRyan Mallon for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++) 367ec77e21bSRyan Mallon if (sst25l_flash_info[i].device_id == id) 368ec77e21bSRyan Mallon flash_info = &sst25l_flash_info[i]; 369ec77e21bSRyan Mallon 370ec77e21bSRyan Mallon if (!flash_info) 371ec77e21bSRyan Mallon dev_err(&spi->dev, "unknown id %.4x\n", id); 372ec77e21bSRyan Mallon 373ec77e21bSRyan Mallon return flash_info; 374ec77e21bSRyan Mallon } 375ec77e21bSRyan Mallon 3766b2995b6SFabio Estevam static int __devinit sst25l_probe(struct spi_device *spi) 377ec77e21bSRyan Mallon { 378ec77e21bSRyan Mallon struct flash_info *flash_info; 379ec77e21bSRyan Mallon struct sst25l_flash *flash; 380ec77e21bSRyan Mallon struct flash_platform_data *data; 381ec77e21bSRyan Mallon int ret, i; 382ec77e21bSRyan Mallon 383ec77e21bSRyan Mallon flash_info = sst25l_match_device(spi); 384ec77e21bSRyan Mallon if (!flash_info) 385ec77e21bSRyan Mallon return -ENODEV; 386ec77e21bSRyan Mallon 387ec77e21bSRyan Mallon flash = kzalloc(sizeof(struct sst25l_flash), GFP_KERNEL); 388ec77e21bSRyan Mallon if (!flash) 389ec77e21bSRyan Mallon return -ENOMEM; 390ec77e21bSRyan Mallon 391ec77e21bSRyan Mallon flash->spi = spi; 392ec77e21bSRyan Mallon mutex_init(&flash->lock); 393ec77e21bSRyan Mallon dev_set_drvdata(&spi->dev, flash); 394ec77e21bSRyan Mallon 395ec77e21bSRyan Mallon data = spi->dev.platform_data; 396ec77e21bSRyan Mallon if (data && data->name) 397ec77e21bSRyan Mallon flash->mtd.name = data->name; 398ec77e21bSRyan Mallon else 399ec77e21bSRyan Mallon flash->mtd.name = dev_name(&spi->dev); 400ec77e21bSRyan Mallon 401ec77e21bSRyan Mallon flash->mtd.type = MTD_NORFLASH; 402ec77e21bSRyan Mallon flash->mtd.flags = MTD_CAP_NORFLASH; 403ec77e21bSRyan Mallon flash->mtd.erasesize = flash_info->erase_size; 404ec77e21bSRyan Mallon flash->mtd.writesize = flash_info->page_size; 405ec77e21bSRyan Mallon flash->mtd.size = flash_info->page_size * flash_info->nr_pages; 406ec77e21bSRyan Mallon flash->mtd.erase = sst25l_erase; 407ec77e21bSRyan Mallon flash->mtd.read = sst25l_read; 408ec77e21bSRyan Mallon flash->mtd.write = sst25l_write; 409ec77e21bSRyan Mallon 410ec77e21bSRyan Mallon dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, 411ec77e21bSRyan Mallon (long long)flash->mtd.size >> 10); 412ec77e21bSRyan Mallon 413289c0522SBrian Norris pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " 414ec77e21bSRyan Mallon ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", 415ec77e21bSRyan Mallon flash->mtd.name, 416ec77e21bSRyan Mallon (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), 417ec77e21bSRyan Mallon flash->mtd.erasesize, flash->mtd.erasesize / 1024, 418ec77e21bSRyan Mallon flash->mtd.numeraseregions); 419ec77e21bSRyan Mallon 420ec77e21bSRyan Mallon 42181939afcSDmitry Eremin-Solenikov ret = mtd_device_parse_register(&flash->mtd, NULL, 0, 42281939afcSDmitry Eremin-Solenikov data ? data->parts : NULL, 42381939afcSDmitry Eremin-Solenikov data ? data->nr_parts : 0); 42481939afcSDmitry Eremin-Solenikov if (ret) { 425ec77e21bSRyan Mallon kfree(flash); 426ec77e21bSRyan Mallon dev_set_drvdata(&spi->dev, NULL); 427ec77e21bSRyan Mallon return -ENODEV; 428ec77e21bSRyan Mallon } 429ec77e21bSRyan Mallon 430ec77e21bSRyan Mallon return 0; 431ec77e21bSRyan Mallon } 432ec77e21bSRyan Mallon 43361cc8276SMike Frysinger static int __devexit sst25l_remove(struct spi_device *spi) 434ec77e21bSRyan Mallon { 435ec77e21bSRyan Mallon struct sst25l_flash *flash = dev_get_drvdata(&spi->dev); 436ec77e21bSRyan Mallon int ret; 437ec77e21bSRyan Mallon 43898b3979bSJamie Iles ret = mtd_device_unregister(&flash->mtd); 439ec77e21bSRyan Mallon if (ret == 0) 440ec77e21bSRyan Mallon kfree(flash); 441ec77e21bSRyan Mallon return ret; 442ec77e21bSRyan Mallon } 443ec77e21bSRyan Mallon 444ec77e21bSRyan Mallon static struct spi_driver sst25l_driver = { 445ec77e21bSRyan Mallon .driver = { 446ec77e21bSRyan Mallon .name = "sst25l", 447ec77e21bSRyan Mallon .bus = &spi_bus_type, 448ec77e21bSRyan Mallon .owner = THIS_MODULE, 449ec77e21bSRyan Mallon }, 450ec77e21bSRyan Mallon .probe = sst25l_probe, 45161cc8276SMike Frysinger .remove = __devexit_p(sst25l_remove), 452ec77e21bSRyan Mallon }; 453ec77e21bSRyan Mallon 454ec77e21bSRyan Mallon static int __init sst25l_init(void) 455ec77e21bSRyan Mallon { 456ec77e21bSRyan Mallon return spi_register_driver(&sst25l_driver); 457ec77e21bSRyan Mallon } 458ec77e21bSRyan Mallon 459ec77e21bSRyan Mallon static void __exit sst25l_exit(void) 460ec77e21bSRyan Mallon { 461ec77e21bSRyan Mallon spi_unregister_driver(&sst25l_driver); 462ec77e21bSRyan Mallon } 463ec77e21bSRyan Mallon 464ec77e21bSRyan Mallon module_init(sst25l_init); 465ec77e21bSRyan Mallon module_exit(sst25l_exit); 466ec77e21bSRyan Mallon 467ec77e21bSRyan Mallon MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips"); 468ec77e21bSRyan Mallon MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, " 4691c5454eeSRyan Mallon "Ryan Mallon"); 470ec77e21bSRyan Mallon MODULE_LICENSE("GPL"); 471