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

[PATCH] SPI eeprom driver

This is adds a simple SPI EEPROM driver, providing access to the EEPROM
through sysfs much like the I2C "eeprom" driver ... except this driver
supports write access, and multiple EEPROM sizes.

From: "Tuppa, Walter" <walter.tuppa@siemens.com>

Since I have EEPROMs on SPI with different address sizing, I made some
changes to your at25.c to support them. Works perfectly. (Also includes a
small bugfix for the "what size address" test.)

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Walter Tuppa <walter.tuppa@siemens.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Brownell and committed by
Linus Torvalds
b587b13a 3925a5ce

+414
+10
drivers/spi/Kconfig
··· 135 135 comment "SPI Protocol Masters" 136 136 depends on SPI_MASTER 137 137 138 + config SPI_AT25 139 + tristate "SPI EEPROMs from most vendors" 140 + depends on SPI_MASTER && SYSFS 141 + help 142 + Enable this driver to get read/write support to most SPI EEPROMs, 143 + after you configure the board init code to know about each eeprom 144 + on your target board. 145 + 146 + This driver can also be built as a module. If so, the module 147 + will be called at25. 138 148 139 149 # 140 150 # Add new SPI protocol masters in alphabetical order above this line
+1
drivers/spi/Makefile
··· 22 22 # ... add above this line ... 23 23 24 24 # SPI protocol drivers (device/link on bus) 25 + obj-$(CONFIG_SPI_AT25) += at25.o 25 26 # ... add above this line ... 26 27 27 28 # SPI slave controller drivers (upstream link)
+381
drivers/spi/at25.c
··· 1 + /* 2 + * at25.c -- support most SPI EEPROMs, such as Atmel AT25 models 3 + * 4 + * Copyright (C) 2006 David Brownell 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, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/init.h> 14 + #include <linux/module.h> 15 + #include <linux/slab.h> 16 + #include <linux/delay.h> 17 + #include <linux/device.h> 18 + #include <linux/sched.h> 19 + 20 + #include <linux/spi/spi.h> 21 + #include <linux/spi/eeprom.h> 22 + 23 + 24 + struct at25_data { 25 + struct spi_device *spi; 26 + struct mutex lock; 27 + struct spi_eeprom chip; 28 + struct bin_attribute bin; 29 + unsigned addrlen; 30 + }; 31 + 32 + #define AT25_WREN 0x06 /* latch the write enable */ 33 + #define AT25_WRDI 0x04 /* reset the write enable */ 34 + #define AT25_RDSR 0x05 /* read status register */ 35 + #define AT25_WRSR 0x01 /* write status register */ 36 + #define AT25_READ 0x03 /* read byte(s) */ 37 + #define AT25_WRITE 0x02 /* write byte(s)/sector */ 38 + 39 + #define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */ 40 + #define AT25_SR_WEN 0x02 /* write enable (latched) */ 41 + #define AT25_SR_BP0 0x04 /* BP for software writeprotect */ 42 + #define AT25_SR_BP1 0x08 43 + #define AT25_SR_WPEN 0x80 /* writeprotect enable */ 44 + 45 + 46 + #define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */ 47 + 48 + /* Specs often allow 5 msec for a page write, sometimes 20 msec; 49 + * it's important to recover from write timeouts. 50 + */ 51 + #define EE_TIMEOUT 25 52 + 53 + /*-------------------------------------------------------------------------*/ 54 + 55 + #define io_limit PAGE_SIZE /* bytes */ 56 + 57 + static ssize_t 58 + at25_ee_read( 59 + struct at25_data *at25, 60 + char *buf, 61 + unsigned offset, 62 + size_t count 63 + ) 64 + { 65 + u8 command[EE_MAXADDRLEN + 1]; 66 + u8 *cp; 67 + ssize_t status; 68 + struct spi_transfer t[2]; 69 + struct spi_message m; 70 + 71 + cp = command; 72 + *cp++ = AT25_READ; 73 + 74 + /* 8/16/24-bit address is written MSB first */ 75 + switch (at25->addrlen) { 76 + default: /* case 3 */ 77 + *cp++ = offset >> 16; 78 + case 2: 79 + *cp++ = offset >> 8; 80 + case 1: 81 + case 0: /* can't happen: for better codegen */ 82 + *cp++ = offset >> 0; 83 + } 84 + 85 + spi_message_init(&m); 86 + memset(t, 0, sizeof t); 87 + 88 + t[0].tx_buf = command; 89 + t[0].len = at25->addrlen + 1; 90 + spi_message_add_tail(&t[0], &m); 91 + 92 + t[1].rx_buf = buf; 93 + t[1].len = count; 94 + spi_message_add_tail(&t[1], &m); 95 + 96 + mutex_lock(&at25->lock); 97 + 98 + /* Read it all at once. 99 + * 100 + * REVISIT that's potentially a problem with large chips, if 101 + * other devices on the bus need to be accessed regularly or 102 + * this chip is clocked very slowly 103 + */ 104 + status = spi_sync(at25->spi, &m); 105 + dev_dbg(&at25->spi->dev, 106 + "read %Zd bytes at %d --> %d\n", 107 + count, offset, (int) status); 108 + 109 + mutex_unlock(&at25->lock); 110 + return status ? status : count; 111 + } 112 + 113 + static ssize_t 114 + at25_bin_read(struct kobject *kobj, char *buf, loff_t off, size_t count) 115 + { 116 + struct device *dev; 117 + struct at25_data *at25; 118 + 119 + dev = container_of(kobj, struct device, kobj); 120 + at25 = dev_get_drvdata(dev); 121 + 122 + if (unlikely(off >= at25->bin.size)) 123 + return 0; 124 + if ((off + count) > at25->bin.size) 125 + count = at25->bin.size - off; 126 + if (unlikely(!count)) 127 + return count; 128 + 129 + return at25_ee_read(at25, buf, off, count); 130 + } 131 + 132 + 133 + static ssize_t 134 + at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count) 135 + { 136 + ssize_t status = 0; 137 + unsigned written = 0; 138 + unsigned buf_size; 139 + u8 *bounce; 140 + 141 + /* Temp buffer starts with command and address */ 142 + buf_size = at25->chip.page_size; 143 + if (buf_size > io_limit) 144 + buf_size = io_limit; 145 + bounce = kmalloc(buf_size + at25->addrlen + 1, GFP_KERNEL); 146 + if (!bounce) 147 + return -ENOMEM; 148 + 149 + /* For write, rollover is within the page ... so we write at 150 + * most one page, then manually roll over to the next page. 151 + */ 152 + bounce[0] = AT25_WRITE; 153 + mutex_lock(&at25->lock); 154 + do { 155 + unsigned long timeout, retries; 156 + unsigned segment; 157 + unsigned offset = (unsigned) off; 158 + u8 *cp = bounce + 1; 159 + 160 + *cp = AT25_WREN; 161 + status = spi_write(at25->spi, cp, 1); 162 + if (status < 0) { 163 + dev_dbg(&at25->spi->dev, "WREN --> %d\n", 164 + (int) status); 165 + break; 166 + } 167 + 168 + /* 8/16/24-bit address is written MSB first */ 169 + switch (at25->addrlen) { 170 + default: /* case 3 */ 171 + *cp++ = offset >> 16; 172 + case 2: 173 + *cp++ = offset >> 8; 174 + case 1: 175 + case 0: /* can't happen: for better codegen */ 176 + *cp++ = offset >> 0; 177 + } 178 + 179 + /* Write as much of a page as we can */ 180 + segment = buf_size - (offset % buf_size); 181 + if (segment > count) 182 + segment = count; 183 + memcpy(cp, buf, segment); 184 + status = spi_write(at25->spi, bounce, 185 + segment + at25->addrlen + 1); 186 + dev_dbg(&at25->spi->dev, 187 + "write %u bytes at %u --> %d\n", 188 + segment, offset, (int) status); 189 + if (status < 0) 190 + break; 191 + 192 + /* REVISIT this should detect (or prevent) failed writes 193 + * to readonly sections of the EEPROM... 194 + */ 195 + 196 + /* Wait for non-busy status */ 197 + timeout = jiffies + msecs_to_jiffies(EE_TIMEOUT); 198 + retries = 0; 199 + do { 200 + int sr; 201 + 202 + sr = spi_w8r8(at25->spi, AT25_RDSR); 203 + if (sr < 0 || (sr & AT25_SR_nRDY)) { 204 + dev_dbg(&at25->spi->dev, 205 + "rdsr --> %d (%02x)\n", sr, sr); 206 + /* at HZ=100, this is sloooow */ 207 + msleep(1); 208 + continue; 209 + } 210 + if (!(sr & AT25_SR_nRDY)) 211 + break; 212 + } while (retries++ < 3 || time_before_eq(jiffies, timeout)); 213 + 214 + if (time_after(jiffies, timeout)) { 215 + dev_err(&at25->spi->dev, 216 + "write %d bytes offset %d, " 217 + "timeout after %u msecs\n", 218 + segment, offset, 219 + jiffies_to_msecs(jiffies - 220 + (timeout - EE_TIMEOUT))); 221 + status = -ETIMEDOUT; 222 + break; 223 + } 224 + 225 + off += segment; 226 + buf += segment; 227 + count -= segment; 228 + written += segment; 229 + 230 + } while (count > 0); 231 + 232 + mutex_unlock(&at25->lock); 233 + 234 + kfree(bounce); 235 + return written ? written : status; 236 + } 237 + 238 + static ssize_t 239 + at25_bin_write(struct kobject *kobj, char *buf, loff_t off, size_t count) 240 + { 241 + struct device *dev; 242 + struct at25_data *at25; 243 + 244 + dev = container_of(kobj, struct device, kobj); 245 + at25 = dev_get_drvdata(dev); 246 + 247 + if (unlikely(off >= at25->bin.size)) 248 + return -EFBIG; 249 + if ((off + count) > at25->bin.size) 250 + count = at25->bin.size - off; 251 + if (unlikely(!count)) 252 + return count; 253 + 254 + return at25_ee_write(at25, buf, off, count); 255 + } 256 + 257 + /*-------------------------------------------------------------------------*/ 258 + 259 + static int at25_probe(struct spi_device *spi) 260 + { 261 + struct at25_data *at25 = NULL; 262 + const struct spi_eeprom *chip; 263 + int err; 264 + int sr; 265 + int addrlen; 266 + 267 + /* Chip description */ 268 + chip = spi->dev.platform_data; 269 + if (!chip) { 270 + dev_dbg(&spi->dev, "no chip description\n"); 271 + err = -ENODEV; 272 + goto fail; 273 + } 274 + 275 + /* For now we only support 8/16/24 bit addressing */ 276 + if (chip->flags & EE_ADDR1) 277 + addrlen = 1; 278 + else if (chip->flags & EE_ADDR2) 279 + addrlen = 2; 280 + else if (chip->flags & EE_ADDR3) 281 + addrlen = 3; 282 + else { 283 + dev_dbg(&spi->dev, "unsupported address type\n"); 284 + err = -EINVAL; 285 + goto fail; 286 + } 287 + 288 + /* Ping the chip ... the status register is pretty portable, 289 + * unlike probing manufacturer IDs. We do expect that system 290 + * firmware didn't write it in the past few milliseconds! 291 + */ 292 + sr = spi_w8r8(spi, AT25_RDSR); 293 + if (sr < 0 || sr & AT25_SR_nRDY) { 294 + dev_dbg(&at25->spi->dev, "rdsr --> %d (%02x)\n", sr, sr); 295 + err = -ENXIO; 296 + goto fail; 297 + } 298 + 299 + if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) { 300 + err = -ENOMEM; 301 + goto fail; 302 + } 303 + 304 + mutex_init(&at25->lock); 305 + at25->chip = *chip; 306 + at25->spi = spi_dev_get(spi); 307 + dev_set_drvdata(&spi->dev, at25); 308 + at25->addrlen = addrlen; 309 + 310 + /* Export the EEPROM bytes through sysfs, since that's convenient. 311 + * Default to root-only access to the data; EEPROMs often hold data 312 + * that's sensitive for read and/or write, like ethernet addresses, 313 + * security codes, board-specific manufacturing calibrations, etc. 314 + */ 315 + at25->bin.attr.name = "eeprom"; 316 + at25->bin.attr.mode = S_IRUSR; 317 + at25->bin.attr.owner = THIS_MODULE; 318 + at25->bin.read = at25_bin_read; 319 + 320 + at25->bin.size = at25->chip.byte_len; 321 + if (!(chip->flags & EE_READONLY)) { 322 + at25->bin.write = at25_bin_write; 323 + at25->bin.attr.mode |= S_IWUSR; 324 + } 325 + 326 + err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin); 327 + if (err) 328 + goto fail; 329 + 330 + dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", 331 + (at25->bin.size < 1024) 332 + ? at25->bin.size 333 + : (at25->bin.size / 1024), 334 + (at25->bin.size < 1024) ? "Byte" : "KByte", 335 + at25->chip.name, 336 + (chip->flags & EE_READONLY) ? " (readonly)" : "", 337 + at25->chip.page_size); 338 + return 0; 339 + fail: 340 + dev_dbg(&spi->dev, "probe err %d\n", err); 341 + kfree(at25); 342 + return err; 343 + } 344 + 345 + static int __devexit at25_remove(struct spi_device *spi) 346 + { 347 + struct at25_data *at25; 348 + 349 + at25 = dev_get_drvdata(&spi->dev); 350 + sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin); 351 + kfree(at25); 352 + return 0; 353 + } 354 + 355 + /*-------------------------------------------------------------------------*/ 356 + 357 + static struct spi_driver at25_driver = { 358 + .driver = { 359 + .name = "at25", 360 + .owner = THIS_MODULE, 361 + }, 362 + .probe = at25_probe, 363 + .remove = __devexit_p(at25_remove), 364 + }; 365 + 366 + static int __init at25_init(void) 367 + { 368 + return spi_register_driver(&at25_driver); 369 + } 370 + module_init(at25_init); 371 + 372 + static void __exit at25_exit(void) 373 + { 374 + spi_unregister_driver(&at25_driver); 375 + } 376 + module_exit(at25_exit); 377 + 378 + MODULE_DESCRIPTION("Driver for most SPI EEPROMs"); 379 + MODULE_AUTHOR("David Brownell"); 380 + MODULE_LICENSE("GPL"); 381 +
+22
include/linux/spi/eeprom.h
··· 1 + #ifndef __LINUX_SPI_EEPROM_H 2 + #define __LINUX_SPI_EEPROM_H 3 + 4 + /* 5 + * Put one of these structures in platform_data for SPI EEPROMS handled 6 + * by the "at25" driver. On SPI, most EEPROMS understand the same core 7 + * command set. If you need to support EEPROMs that don't yet fit, add 8 + * flags to support those protocol options. These values all come from 9 + * the chip datasheets. 10 + */ 11 + struct spi_eeprom { 12 + u32 byte_len; 13 + char name[10]; 14 + u16 page_size; /* for writes */ 15 + u16 flags; 16 + #define EE_ADDR1 0x0001 /* 8 bit addrs */ 17 + #define EE_ADDR2 0x0002 /* 16 bit addrs */ 18 + #define EE_ADDR3 0x0004 /* 24 bit addrs */ 19 + #define EE_READONLY 0x0008 /* disallow writes */ 20 + }; 21 + 22 + #endif /* __LINUX_SPI_EEPROM_H */