diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-07-25 18:45:45 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 14:31:57 -0400 |
commit | 23fbee9dd5d2a41d36af49ff8e1669fb0c29fda8 (patch) | |
tree | 4e24699269b9d4d2655d961e7a0ffb29931e9b2d /arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c | |
parent | 132940401174ed04f9e8f1ae2dad6f47da26ee0a (diff) |
Support for Toshiba's RBHMA4500 eval board for the TX4938.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c')
-rw-r--r-- | arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c new file mode 100644 index 000000000000..951a208ee9b3 --- /dev/null +++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_eeprom.c | |||
@@ -0,0 +1,219 @@ | |||
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 */ | ||