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