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/module.h> 19ec77e21bSRyan Mallon #include <linux/device.h> 20ec77e21bSRyan Mallon #include <linux/mutex.h> 21ec77e21bSRyan Mallon #include <linux/interrupt.h> 225a0e3ad6STejun Heo #include <linux/slab.h> 23d43c36dcSAlexey Dobriyan #include <linux/sched.h> 24ec77e21bSRyan Mallon 25ec77e21bSRyan Mallon #include <linux/mtd/mtd.h> 26ec77e21bSRyan Mallon #include <linux/mtd/partitions.h> 27ec77e21bSRyan Mallon 28ec77e21bSRyan Mallon #include <linux/spi/spi.h> 29ec77e21bSRyan Mallon #include <linux/spi/flash.h> 30ec77e21bSRyan Mallon 31ec77e21bSRyan Mallon /* Erases can take up to 3 seconds! */ 32ec77e21bSRyan Mallon #define MAX_READY_WAIT_JIFFIES msecs_to_jiffies(3000) 33ec77e21bSRyan Mallon 34ec77e21bSRyan Mallon #define SST25L_CMD_WRSR 0x01 /* Write status register */ 35ec77e21bSRyan Mallon #define SST25L_CMD_WRDI 0x04 /* Write disable */ 36ec77e21bSRyan Mallon #define SST25L_CMD_RDSR 0x05 /* Read status register */ 37ec77e21bSRyan Mallon #define SST25L_CMD_WREN 0x06 /* Write enable */ 38ec77e21bSRyan Mallon #define SST25L_CMD_READ 0x03 /* High speed read */ 39ec77e21bSRyan Mallon 40ec77e21bSRyan Mallon #define SST25L_CMD_EWSR 0x50 /* Enable write status register */ 41ec77e21bSRyan Mallon #define SST25L_CMD_SECTOR_ERASE 0x20 /* Erase sector */ 42ec77e21bSRyan Mallon #define SST25L_CMD_READ_ID 0x90 /* Read device ID */ 43ec77e21bSRyan Mallon #define SST25L_CMD_AAI_PROGRAM 0xaf /* Auto address increment */ 44ec77e21bSRyan Mallon 45ec77e21bSRyan Mallon #define SST25L_STATUS_BUSY (1 << 0) /* Chip is busy */ 46ec77e21bSRyan Mallon #define SST25L_STATUS_WREN (1 << 1) /* Write enabled */ 47ec77e21bSRyan Mallon #define SST25L_STATUS_BP0 (1 << 2) /* Block protection 0 */ 48ec77e21bSRyan Mallon #define SST25L_STATUS_BP1 (1 << 3) /* Block protection 1 */ 49ec77e21bSRyan Mallon 50ec77e21bSRyan Mallon struct sst25l_flash { 51ec77e21bSRyan Mallon struct spi_device *spi; 52ec77e21bSRyan Mallon struct mutex lock; 53ec77e21bSRyan Mallon struct mtd_info mtd; 54ec77e21bSRyan Mallon }; 55ec77e21bSRyan Mallon 56ec77e21bSRyan Mallon struct flash_info { 57ec77e21bSRyan Mallon const char *name; 58ec77e21bSRyan Mallon uint16_t device_id; 59ec77e21bSRyan Mallon unsigned page_size; 60ec77e21bSRyan Mallon unsigned nr_pages; 61ec77e21bSRyan Mallon unsigned erase_size; 62ec77e21bSRyan Mallon }; 63ec77e21bSRyan Mallon 64ec77e21bSRyan Mallon #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd) 65ec77e21bSRyan Mallon 66042a1909SBill Pemberton static struct flash_info sst25l_flash_info[] = { 67ec77e21bSRyan Mallon {"sst25lf020a", 0xbf43, 256, 1024, 4096}, 68ec77e21bSRyan Mallon {"sst25lf040a", 0xbf44, 256, 2048, 4096}, 69ec77e21bSRyan Mallon }; 70ec77e21bSRyan Mallon 71ec77e21bSRyan Mallon static int sst25l_status(struct sst25l_flash *flash, int *status) 72ec77e21bSRyan Mallon { 730ffe0ce3SH Hartley Sweeten struct spi_message m; 740ffe0ce3SH Hartley Sweeten struct spi_transfer t; 750ffe0ce3SH Hartley Sweeten unsigned char cmd_resp[2]; 76ec77e21bSRyan Mallon int err; 77ec77e21bSRyan Mallon 780ffe0ce3SH Hartley Sweeten spi_message_init(&m); 790ffe0ce3SH Hartley Sweeten memset(&t, 0, sizeof(struct spi_transfer)); 800ffe0ce3SH Hartley Sweeten 810ffe0ce3SH Hartley Sweeten cmd_resp[0] = SST25L_CMD_RDSR; 820ffe0ce3SH Hartley Sweeten cmd_resp[1] = 0xff; 830ffe0ce3SH Hartley Sweeten t.tx_buf = cmd_resp; 840ffe0ce3SH Hartley Sweeten t.rx_buf = cmd_resp; 850ffe0ce3SH Hartley Sweeten t.len = sizeof(cmd_resp); 860ffe0ce3SH Hartley Sweeten spi_message_add_tail(&t, &m); 870ffe0ce3SH Hartley Sweeten err = spi_sync(flash->spi, &m); 88ec77e21bSRyan Mallon if (err < 0) 89ec77e21bSRyan Mallon return err; 90ec77e21bSRyan Mallon 910ffe0ce3SH Hartley Sweeten *status = cmd_resp[1]; 92ec77e21bSRyan Mallon return 0; 93ec77e21bSRyan Mallon } 94ec77e21bSRyan Mallon 95ec77e21bSRyan Mallon static int sst25l_write_enable(struct sst25l_flash *flash, int enable) 96ec77e21bSRyan Mallon { 97ec77e21bSRyan Mallon unsigned char command[2]; 98ec77e21bSRyan Mallon int status, err; 99ec77e21bSRyan Mallon 100ec77e21bSRyan Mallon command[0] = enable ? SST25L_CMD_WREN : SST25L_CMD_WRDI; 101ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 1); 102ec77e21bSRyan Mallon if (err) 103ec77e21bSRyan Mallon return err; 104ec77e21bSRyan Mallon 105ec77e21bSRyan Mallon command[0] = SST25L_CMD_EWSR; 106ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 1); 107ec77e21bSRyan Mallon if (err) 108ec77e21bSRyan Mallon return err; 109ec77e21bSRyan Mallon 110ec77e21bSRyan Mallon command[0] = SST25L_CMD_WRSR; 111ec77e21bSRyan Mallon command[1] = enable ? 0 : SST25L_STATUS_BP0 | SST25L_STATUS_BP1; 112ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 2); 113ec77e21bSRyan Mallon if (err) 114ec77e21bSRyan Mallon return err; 115ec77e21bSRyan Mallon 116ec77e21bSRyan Mallon if (enable) { 117ec77e21bSRyan Mallon err = sst25l_status(flash, &status); 118ec77e21bSRyan Mallon if (err) 119ec77e21bSRyan Mallon return err; 120ec77e21bSRyan Mallon if (!(status & SST25L_STATUS_WREN)) 121ec77e21bSRyan Mallon return -EROFS; 122ec77e21bSRyan Mallon } 123ec77e21bSRyan Mallon 124ec77e21bSRyan Mallon return 0; 125ec77e21bSRyan Mallon } 126ec77e21bSRyan Mallon 127ec77e21bSRyan Mallon static int sst25l_wait_till_ready(struct sst25l_flash *flash) 128ec77e21bSRyan Mallon { 129ec77e21bSRyan Mallon unsigned long deadline; 130ec77e21bSRyan Mallon int status, err; 131ec77e21bSRyan Mallon 132ec77e21bSRyan Mallon deadline = jiffies + MAX_READY_WAIT_JIFFIES; 133ec77e21bSRyan Mallon do { 134ec77e21bSRyan Mallon err = sst25l_status(flash, &status); 135ec77e21bSRyan Mallon if (err) 136ec77e21bSRyan Mallon return err; 137ec77e21bSRyan Mallon if (!(status & SST25L_STATUS_BUSY)) 138ec77e21bSRyan Mallon return 0; 139ec77e21bSRyan Mallon 140ec77e21bSRyan Mallon cond_resched(); 141ec77e21bSRyan Mallon } while (!time_after_eq(jiffies, deadline)); 142ec77e21bSRyan Mallon 143ec77e21bSRyan Mallon return -ETIMEDOUT; 144ec77e21bSRyan Mallon } 145ec77e21bSRyan Mallon 146ec77e21bSRyan Mallon static int sst25l_erase_sector(struct sst25l_flash *flash, uint32_t offset) 147ec77e21bSRyan Mallon { 148ec77e21bSRyan Mallon unsigned char command[4]; 149ec77e21bSRyan Mallon int err; 150ec77e21bSRyan Mallon 151ec77e21bSRyan Mallon err = sst25l_write_enable(flash, 1); 152ec77e21bSRyan Mallon if (err) 153ec77e21bSRyan Mallon return err; 154ec77e21bSRyan Mallon 155ec77e21bSRyan Mallon command[0] = SST25L_CMD_SECTOR_ERASE; 156ec77e21bSRyan Mallon command[1] = offset >> 16; 157ec77e21bSRyan Mallon command[2] = offset >> 8; 158ec77e21bSRyan Mallon command[3] = offset; 159ec77e21bSRyan Mallon err = spi_write(flash->spi, command, 4); 160ec77e21bSRyan Mallon if (err) 161ec77e21bSRyan Mallon return err; 162ec77e21bSRyan Mallon 163ec77e21bSRyan Mallon err = sst25l_wait_till_ready(flash); 164ec77e21bSRyan Mallon if (err) 165ec77e21bSRyan Mallon return err; 166ec77e21bSRyan Mallon 167ec77e21bSRyan Mallon return sst25l_write_enable(flash, 0); 168ec77e21bSRyan Mallon } 169ec77e21bSRyan Mallon 170ec77e21bSRyan Mallon static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) 171ec77e21bSRyan Mallon { 172ec77e21bSRyan Mallon struct sst25l_flash *flash = to_sst25l_flash(mtd); 173ec77e21bSRyan Mallon uint32_t addr, end; 174ec77e21bSRyan Mallon int err; 175ec77e21bSRyan Mallon 176ec77e21bSRyan Mallon /* Sanity checks */ 177ec77e21bSRyan Mallon if ((uint32_t)instr->len % mtd->erasesize) 178ec77e21bSRyan Mallon return -EINVAL; 179ec77e21bSRyan Mallon 180ec77e21bSRyan Mallon if ((uint32_t)instr->addr % mtd->erasesize) 181ec77e21bSRyan Mallon return -EINVAL; 182ec77e21bSRyan Mallon 183ec77e21bSRyan Mallon addr = instr->addr; 184ec77e21bSRyan Mallon end = addr + instr->len; 185ec77e21bSRyan Mallon 186ec77e21bSRyan Mallon mutex_lock(&flash->lock); 187ec77e21bSRyan Mallon 188ec77e21bSRyan Mallon err = sst25l_wait_till_ready(flash); 1892eaaa5ffSJiri Slaby if (err) { 1902eaaa5ffSJiri Slaby mutex_unlock(&flash->lock); 191ec77e21bSRyan Mallon return err; 1922eaaa5ffSJiri Slaby } 193ec77e21bSRyan Mallon 194ec77e21bSRyan Mallon while (addr < end) { 195ec77e21bSRyan Mallon err = sst25l_erase_sector(flash, addr); 196ec77e21bSRyan Mallon if (err) { 197ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 198ec77e21bSRyan Mallon instr->state = MTD_ERASE_FAILED; 199ec77e21bSRyan Mallon dev_err(&flash->spi->dev, "Erase failed\n"); 200ec77e21bSRyan Mallon return err; 201ec77e21bSRyan Mallon } 202ec77e21bSRyan Mallon 203ec77e21bSRyan Mallon addr += mtd->erasesize; 204ec77e21bSRyan Mallon } 205ec77e21bSRyan Mallon 206ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 207ec77e21bSRyan Mallon 208ec77e21bSRyan Mallon instr->state = MTD_ERASE_DONE; 209ec77e21bSRyan Mallon mtd_erase_callback(instr); 210ec77e21bSRyan Mallon return 0; 211ec77e21bSRyan Mallon } 212ec77e21bSRyan Mallon 213ec77e21bSRyan Mallon static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len, 214ec77e21bSRyan Mallon size_t *retlen, unsigned char *buf) 215ec77e21bSRyan Mallon { 216ec77e21bSRyan Mallon struct sst25l_flash *flash = to_sst25l_flash(mtd); 217ec77e21bSRyan Mallon struct spi_transfer transfer[2]; 218ec77e21bSRyan Mallon struct spi_message message; 219ec77e21bSRyan Mallon unsigned char command[4]; 220ec77e21bSRyan Mallon int ret; 221ec77e21bSRyan Mallon 222ec77e21bSRyan Mallon spi_message_init(&message); 223ec77e21bSRyan Mallon memset(&transfer, 0, sizeof(transfer)); 224ec77e21bSRyan Mallon 225ec77e21bSRyan Mallon command[0] = SST25L_CMD_READ; 226ec77e21bSRyan Mallon command[1] = from >> 16; 227ec77e21bSRyan Mallon command[2] = from >> 8; 228ec77e21bSRyan Mallon command[3] = from; 229ec77e21bSRyan Mallon 230ec77e21bSRyan Mallon transfer[0].tx_buf = command; 231ec77e21bSRyan Mallon transfer[0].len = sizeof(command); 232ec77e21bSRyan Mallon spi_message_add_tail(&transfer[0], &message); 233ec77e21bSRyan Mallon 234ec77e21bSRyan Mallon transfer[1].rx_buf = buf; 235ec77e21bSRyan Mallon transfer[1].len = len; 236ec77e21bSRyan Mallon spi_message_add_tail(&transfer[1], &message); 237ec77e21bSRyan Mallon 238ec77e21bSRyan Mallon mutex_lock(&flash->lock); 239ec77e21bSRyan Mallon 240ec77e21bSRyan Mallon /* Wait for previous write/erase to complete */ 241ec77e21bSRyan Mallon ret = sst25l_wait_till_ready(flash); 242ec77e21bSRyan Mallon if (ret) { 243ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 244ec77e21bSRyan Mallon return ret; 245ec77e21bSRyan Mallon } 246ec77e21bSRyan Mallon 247ec77e21bSRyan Mallon spi_sync(flash->spi, &message); 248ec77e21bSRyan Mallon 249ec77e21bSRyan Mallon if (retlen && message.actual_length > sizeof(command)) 250ec77e21bSRyan Mallon *retlen += message.actual_length - sizeof(command); 251ec77e21bSRyan Mallon 252ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 253ec77e21bSRyan Mallon return 0; 254ec77e21bSRyan Mallon } 255ec77e21bSRyan Mallon 256ec77e21bSRyan Mallon static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, 257ec77e21bSRyan Mallon size_t *retlen, const unsigned char *buf) 258ec77e21bSRyan Mallon { 259ec77e21bSRyan Mallon struct sst25l_flash *flash = to_sst25l_flash(mtd); 260ec77e21bSRyan Mallon int i, j, ret, bytes, copied = 0; 261ec77e21bSRyan Mallon unsigned char command[5]; 262ec77e21bSRyan Mallon 263ec77e21bSRyan Mallon if ((uint32_t)to % mtd->writesize) 264ec77e21bSRyan Mallon return -EINVAL; 265ec77e21bSRyan Mallon 266ec77e21bSRyan Mallon mutex_lock(&flash->lock); 267ec77e21bSRyan Mallon 268ec77e21bSRyan Mallon ret = sst25l_write_enable(flash, 1); 269ec77e21bSRyan Mallon if (ret) 270ec77e21bSRyan Mallon goto out; 271ec77e21bSRyan Mallon 272ec77e21bSRyan Mallon for (i = 0; i < len; i += mtd->writesize) { 273ec77e21bSRyan Mallon ret = sst25l_wait_till_ready(flash); 274ec77e21bSRyan Mallon if (ret) 275ec77e21bSRyan Mallon goto out; 276ec77e21bSRyan Mallon 277ec77e21bSRyan Mallon /* Write the first byte of the page */ 278ec77e21bSRyan Mallon command[0] = SST25L_CMD_AAI_PROGRAM; 279ec77e21bSRyan Mallon command[1] = (to + i) >> 16; 280ec77e21bSRyan Mallon command[2] = (to + i) >> 8; 281ec77e21bSRyan Mallon command[3] = (to + i); 282ec77e21bSRyan Mallon command[4] = buf[i]; 283ec77e21bSRyan Mallon ret = spi_write(flash->spi, command, 5); 284ec77e21bSRyan Mallon if (ret < 0) 285ec77e21bSRyan Mallon goto out; 286ec77e21bSRyan Mallon copied++; 287ec77e21bSRyan Mallon 288ec77e21bSRyan Mallon /* 289ec77e21bSRyan Mallon * Write the remaining bytes using auto address 290ec77e21bSRyan Mallon * increment mode 291ec77e21bSRyan Mallon */ 292ec77e21bSRyan Mallon bytes = min_t(uint32_t, mtd->writesize, len - i); 293ec77e21bSRyan Mallon for (j = 1; j < bytes; j++, copied++) { 294ec77e21bSRyan Mallon ret = sst25l_wait_till_ready(flash); 295ec77e21bSRyan Mallon if (ret) 296ec77e21bSRyan Mallon goto out; 297ec77e21bSRyan Mallon 298ec77e21bSRyan Mallon command[1] = buf[i + j]; 299ec77e21bSRyan Mallon ret = spi_write(flash->spi, command, 2); 300ec77e21bSRyan Mallon if (ret) 301ec77e21bSRyan Mallon goto out; 302ec77e21bSRyan Mallon } 303ec77e21bSRyan Mallon } 304ec77e21bSRyan Mallon 305ec77e21bSRyan Mallon out: 306ec77e21bSRyan Mallon ret = sst25l_write_enable(flash, 0); 307ec77e21bSRyan Mallon 308ec77e21bSRyan Mallon if (retlen) 309ec77e21bSRyan Mallon *retlen = copied; 310ec77e21bSRyan Mallon 311ec77e21bSRyan Mallon mutex_unlock(&flash->lock); 312ec77e21bSRyan Mallon return ret; 313ec77e21bSRyan Mallon } 314ec77e21bSRyan Mallon 31506f25510SBill Pemberton static struct flash_info *sst25l_match_device(struct spi_device *spi) 316ec77e21bSRyan Mallon { 317ec77e21bSRyan Mallon struct flash_info *flash_info = NULL; 3180ffe0ce3SH Hartley Sweeten struct spi_message m; 3190ffe0ce3SH Hartley Sweeten struct spi_transfer t; 3200ffe0ce3SH Hartley Sweeten unsigned char cmd_resp[6]; 321ec77e21bSRyan Mallon int i, err; 322ec77e21bSRyan Mallon uint16_t id; 323ec77e21bSRyan Mallon 3240ffe0ce3SH Hartley Sweeten spi_message_init(&m); 3250ffe0ce3SH Hartley Sweeten memset(&t, 0, sizeof(struct spi_transfer)); 3260ffe0ce3SH Hartley Sweeten 3270ffe0ce3SH Hartley Sweeten cmd_resp[0] = SST25L_CMD_READ_ID; 3280ffe0ce3SH Hartley Sweeten cmd_resp[1] = 0; 3290ffe0ce3SH Hartley Sweeten cmd_resp[2] = 0; 3300ffe0ce3SH Hartley Sweeten cmd_resp[3] = 0; 3310ffe0ce3SH Hartley Sweeten cmd_resp[4] = 0xff; 3320ffe0ce3SH Hartley Sweeten cmd_resp[5] = 0xff; 3330ffe0ce3SH Hartley Sweeten t.tx_buf = cmd_resp; 3340ffe0ce3SH Hartley Sweeten t.rx_buf = cmd_resp; 3350ffe0ce3SH Hartley Sweeten t.len = sizeof(cmd_resp); 3360ffe0ce3SH Hartley Sweeten spi_message_add_tail(&t, &m); 3370ffe0ce3SH Hartley Sweeten err = spi_sync(spi, &m); 338ec77e21bSRyan Mallon if (err < 0) { 3390ffe0ce3SH Hartley Sweeten dev_err(&spi->dev, "error reading device id\n"); 340ec77e21bSRyan Mallon return NULL; 341ec77e21bSRyan Mallon } 342ec77e21bSRyan Mallon 3430ffe0ce3SH Hartley Sweeten id = (cmd_resp[4] << 8) | cmd_resp[5]; 344ec77e21bSRyan Mallon 345ec77e21bSRyan Mallon for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++) 346ec77e21bSRyan Mallon if (sst25l_flash_info[i].device_id == id) 347ec77e21bSRyan Mallon flash_info = &sst25l_flash_info[i]; 348ec77e21bSRyan Mallon 349ec77e21bSRyan Mallon if (!flash_info) 350ec77e21bSRyan Mallon dev_err(&spi->dev, "unknown id %.4x\n", id); 351ec77e21bSRyan Mallon 352ec77e21bSRyan Mallon return flash_info; 353ec77e21bSRyan Mallon } 354ec77e21bSRyan Mallon 35506f25510SBill Pemberton static int sst25l_probe(struct spi_device *spi) 356ec77e21bSRyan Mallon { 357ec77e21bSRyan Mallon struct flash_info *flash_info; 358ec77e21bSRyan Mallon struct sst25l_flash *flash; 359ec77e21bSRyan Mallon struct flash_platform_data *data; 360d81a32f2SArtem Bityutskiy int ret; 361ec77e21bSRyan Mallon 362ec77e21bSRyan Mallon flash_info = sst25l_match_device(spi); 363ec77e21bSRyan Mallon if (!flash_info) 364ec77e21bSRyan Mallon return -ENODEV; 365ec77e21bSRyan Mallon 366b38be288SSachin Kamat flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); 367ec77e21bSRyan Mallon if (!flash) 368ec77e21bSRyan Mallon return -ENOMEM; 369ec77e21bSRyan Mallon 370ec77e21bSRyan Mallon flash->spi = spi; 371ec77e21bSRyan Mallon mutex_init(&flash->lock); 3721594908aSJingoo Han spi_set_drvdata(spi, flash); 373ec77e21bSRyan Mallon 3740278fd3fSJingoo Han data = dev_get_platdata(&spi->dev); 375ec77e21bSRyan Mallon if (data && data->name) 376ec77e21bSRyan Mallon flash->mtd.name = data->name; 377ec77e21bSRyan Mallon 37890b99752SFrans Klaver flash->mtd.dev.parent = &spi->dev; 379ec77e21bSRyan Mallon flash->mtd.type = MTD_NORFLASH; 380ec77e21bSRyan Mallon flash->mtd.flags = MTD_CAP_NORFLASH; 381ec77e21bSRyan Mallon flash->mtd.erasesize = flash_info->erase_size; 382ec77e21bSRyan Mallon flash->mtd.writesize = flash_info->page_size; 383c4cc625eSArtem Bityutskiy flash->mtd.writebufsize = flash_info->page_size; 384ec77e21bSRyan Mallon flash->mtd.size = flash_info->page_size * flash_info->nr_pages; 3853c3c10bbSArtem Bityutskiy flash->mtd._erase = sst25l_erase; 3863c3c10bbSArtem Bityutskiy flash->mtd._read = sst25l_read; 3873c3c10bbSArtem Bityutskiy flash->mtd._write = sst25l_write; 388ec77e21bSRyan Mallon 389ec77e21bSRyan Mallon dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, 390ec77e21bSRyan Mallon (long long)flash->mtd.size >> 10); 391ec77e21bSRyan Mallon 392289c0522SBrian Norris pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " 393ec77e21bSRyan Mallon ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", 394ec77e21bSRyan Mallon flash->mtd.name, 395ec77e21bSRyan Mallon (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), 396ec77e21bSRyan Mallon flash->mtd.erasesize, flash->mtd.erasesize / 1024, 397ec77e21bSRyan Mallon flash->mtd.numeraseregions); 398ec77e21bSRyan Mallon 399ec77e21bSRyan Mallon 40042d7fbe2SArtem Bityutskiy ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, 40181939afcSDmitry Eremin-Solenikov data ? data->parts : NULL, 40281939afcSDmitry Eremin-Solenikov data ? data->nr_parts : 0); 403b38be288SSachin Kamat if (ret) 404ec77e21bSRyan Mallon return -ENODEV; 405ec77e21bSRyan Mallon 406ec77e21bSRyan Mallon return 0; 407ec77e21bSRyan Mallon } 408ec77e21bSRyan Mallon 409810b7e06SBill Pemberton static int sst25l_remove(struct spi_device *spi) 410ec77e21bSRyan Mallon { 4111594908aSJingoo Han struct sst25l_flash *flash = spi_get_drvdata(spi); 412ec77e21bSRyan Mallon 413b38be288SSachin Kamat return mtd_device_unregister(&flash->mtd); 414ec77e21bSRyan Mallon } 415ec77e21bSRyan Mallon 416ec77e21bSRyan Mallon static struct spi_driver sst25l_driver = { 417ec77e21bSRyan Mallon .driver = { 418ec77e21bSRyan Mallon .name = "sst25l", 419ec77e21bSRyan Mallon .owner = THIS_MODULE, 420ec77e21bSRyan Mallon }, 421ec77e21bSRyan Mallon .probe = sst25l_probe, 4225153b88cSBill Pemberton .remove = sst25l_remove, 423ec77e21bSRyan Mallon }; 424ec77e21bSRyan Mallon 425c9d1b752SAxel Lin module_spi_driver(sst25l_driver); 426ec77e21bSRyan Mallon 427ec77e21bSRyan Mallon MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips"); 428ec77e21bSRyan Mallon MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, " 4291c5454eeSRyan Mallon "Ryan Mallon"); 430ec77e21bSRyan Mallon MODULE_LICENSE("GPL"); 431