Merge ../linux-2.6 by hand
[pandora-kernel.git] / arch / mips / tx4938 / toshiba_rbtx4938 / spi_eeprom.c
1 /*
2  * linux/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c
3  * Copyright (C) 2000-2001 Toshiba Corporation
4  *
5  * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
6  * terms of the GNU General Public License version 2. This program is
7  * licensed "as is" without any warranty of any kind, whether express
8  * or implied.
9  *
10  * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
11  */
12 #include <linux/config.h>
13 #include <linux/init.h>
14 #include <linux/delay.h>
15 #include <linux/proc_fs.h>
16 #include <linux/spinlock.h>
17 #include <asm/tx4938/spi.h>
18 #include <asm/tx4938/tx4938.h>
19
20 /* ATMEL 250x0 instructions */
21 #define ATMEL_WREN      0x06
22 #define ATMEL_WRDI      0x04
23 #define ATMEL_RDSR      0x05
24 #define ATMEL_WRSR      0x01
25 #define ATMEL_READ      0x03
26 #define ATMEL_WRITE     0x02
27
28 #define ATMEL_SR_BSY    0x01
29 #define ATMEL_SR_WEN    0x02
30 #define ATMEL_SR_BP0    0x04
31 #define ATMEL_SR_BP1    0x08
32
33 DEFINE_SPINLOCK(spi_eeprom_lock);
34
35 static struct spi_dev_desc seeprom_dev_desc = {
36         .baud           = 1500000,      /* 1.5Mbps */
37         .tcss           = 1,
38         .tcsh           = 1,
39         .tcsr           = 1,
40         .byteorder      = 1,            /* MSB-First */
41         .polarity       = 0,            /* High-Active */
42         .phase          = 0,            /* Sample-Then-Shift */
43
44 };
45 static inline int
46 spi_eeprom_io(int chipid,
47               unsigned char **inbufs, unsigned int *incounts,
48               unsigned char **outbufs, unsigned int *outcounts)
49 {
50         return txx9_spi_io(chipid, &seeprom_dev_desc,
51                            inbufs, incounts, outbufs, outcounts, 0);
52 }
53
54 int spi_eeprom_write_enable(int chipid, int enable)
55 {
56         unsigned char inbuf[1];
57         unsigned char *inbufs[1];
58         unsigned int incounts[2];
59         unsigned long flags;
60         int stat;
61         inbuf[0] = enable ? ATMEL_WREN : ATMEL_WRDI;
62         inbufs[0] = inbuf;
63         incounts[0] = sizeof(inbuf);
64         incounts[1] = 0;
65         spin_lock_irqsave(&spi_eeprom_lock, flags);
66         stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL);
67         spin_unlock_irqrestore(&spi_eeprom_lock, flags);
68         return stat;
69 }
70
71 static int spi_eeprom_read_status_nolock(int chipid)
72 {
73         unsigned char inbuf[2], outbuf[2];
74         unsigned char *inbufs[1], *outbufs[1];
75         unsigned int incounts[2], outcounts[2];
76         int stat;
77         inbuf[0] = ATMEL_RDSR;
78         inbuf[1] = 0;
79         inbufs[0] = inbuf;
80         incounts[0] = sizeof(inbuf);
81         incounts[1] = 0;
82         outbufs[0] = outbuf;
83         outcounts[0] = sizeof(outbuf);
84         outcounts[1] = 0;
85         stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts);
86         if (stat < 0)
87                 return stat;
88         return outbuf[1];
89 }
90
91 int spi_eeprom_read_status(int chipid)
92 {
93         unsigned long flags;
94         int stat;
95         spin_lock_irqsave(&spi_eeprom_lock, flags);
96         stat = spi_eeprom_read_status_nolock(chipid);
97         spin_unlock_irqrestore(&spi_eeprom_lock, flags);
98         return stat;
99 }
100
101 int spi_eeprom_read(int chipid, int address, unsigned char *buf, int len)
102 {
103         unsigned char inbuf[2];
104         unsigned char *inbufs[2], *outbufs[2];
105         unsigned int incounts[2], outcounts[3];
106         unsigned long flags;
107         int stat;
108         inbuf[0] = ATMEL_READ;
109         inbuf[1] = address;
110         inbufs[0] = inbuf;
111         inbufs[1] = NULL;
112         incounts[0] = sizeof(inbuf);
113         incounts[1] = 0;
114         outbufs[0] = NULL;
115         outbufs[1] = buf;
116         outcounts[0] = 2;
117         outcounts[1] = len;
118         outcounts[2] = 0;
119         spin_lock_irqsave(&spi_eeprom_lock, flags);
120         stat = spi_eeprom_io(chipid, inbufs, incounts, outbufs, outcounts);
121         spin_unlock_irqrestore(&spi_eeprom_lock, flags);
122         return stat;
123 }
124
125 int spi_eeprom_write(int chipid, int address, unsigned char *buf, int len)
126 {
127         unsigned char inbuf[2];
128         unsigned char *inbufs[2];
129         unsigned int incounts[3];
130         unsigned long flags;
131         int i, stat;
132
133         if (address / 8 != (address + len - 1) / 8)
134                 return -EINVAL;
135         stat = spi_eeprom_write_enable(chipid, 1);
136         if (stat < 0)
137                 return stat;
138         stat = spi_eeprom_read_status(chipid);
139         if (stat < 0)
140                 return stat;
141         if (!(stat & ATMEL_SR_WEN))
142                 return -EPERM;
143
144         inbuf[0] = ATMEL_WRITE;
145         inbuf[1] = address;
146         inbufs[0] = inbuf;
147         inbufs[1] = buf;
148         incounts[0] = sizeof(inbuf);
149         incounts[1] = len;
150         incounts[2] = 0;
151         spin_lock_irqsave(&spi_eeprom_lock, flags);
152         stat = spi_eeprom_io(chipid, inbufs, incounts, NULL, NULL);
153         if (stat < 0)
154                 goto unlock_return;
155
156         /* write start.  max 10ms */
157         for (i = 10; i > 0; i--) {
158                 int stat = spi_eeprom_read_status_nolock(chipid);
159                 if (stat < 0)
160                         goto unlock_return;
161                 if (!(stat & ATMEL_SR_BSY))
162                         break;
163                 mdelay(1);
164         }
165         spin_unlock_irqrestore(&spi_eeprom_lock, flags);
166         if (i == 0)
167                 return -EIO;
168         return len;
169  unlock_return:
170         spin_unlock_irqrestore(&spi_eeprom_lock, flags);
171         return stat;
172 }
173
174 #ifdef CONFIG_PROC_FS
175 #define MAX_SIZE        0x80    /* for ATMEL 25010 */
176 static int spi_eeprom_read_proc(char *page, char **start, off_t off,
177                                 int count, int *eof, void *data)
178 {
179         unsigned int size = MAX_SIZE;
180         if (spi_eeprom_read((int)data, 0, (unsigned char *)page, size) < 0)
181                 size = 0;
182         return size;
183 }
184
185 static int spi_eeprom_write_proc(struct file *file, const char *buffer,
186                                  unsigned long count, void *data)
187 {
188         unsigned int size = MAX_SIZE;
189         int i;
190         if (file->f_pos >= size)
191                 return -EIO;
192         if (file->f_pos + count > size)
193                 count = size - file->f_pos;
194         for (i = 0; i < count; i += 8) {
195                 int len = count - i < 8 ? count - i : 8;
196                 if (spi_eeprom_write((int)data, file->f_pos,
197                                      (unsigned char *)buffer, len) < 0) {
198                         count = -EIO;
199                         break;
200                 }
201                 buffer += len;
202                 file->f_pos += len;
203         }
204         return count;
205 }
206
207 __init void spi_eeprom_proc_create(struct proc_dir_entry *dir, int chipid)
208 {
209         struct proc_dir_entry *entry;
210         char name[128];
211         sprintf(name, "seeprom-%d", chipid);
212         entry = create_proc_entry(name, 0600, dir);
213         if (entry) {
214                 entry->read_proc = spi_eeprom_read_proc;
215                 entry->write_proc = spi_eeprom_write_proc;
216                 entry->data = (void *)chipid;
217         }
218 }
219 #endif /* CONFIG_PROC_FS */