OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [spi/] [at25.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
 
31
struct 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
 
64
static ssize_t
65
at25_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
 
120
static ssize_t
121
at25_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
 
141
static ssize_t
142
at25_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
 
246
static ssize_t
247
at25_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
 
268
static 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;
347
fail:
348
        dev_dbg(&spi->dev, "probe err %d\n", err);
349
        kfree(at25);
350
        return err;
351
}
352
 
353
static 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
 
365
static 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
 
374
static int __init at25_init(void)
375
{
376
        return spi_register_driver(&at25_driver);
377
}
378
module_init(at25_init);
379
 
380
static void __exit at25_exit(void)
381
{
382
        spi_unregister_driver(&at25_driver);
383
}
384
module_exit(at25_exit);
385
 
386
MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
387
MODULE_AUTHOR("David Brownell");
388
MODULE_LICENSE("GPL");
389
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.