Commit 9467d64b0e88763914c01f71ddf591b166c4f526
Committed by
Jeff Garzik
1 parent
7dcca30a32
Exists in
master
and in
7 other branches
[PATCH] Add 93cx6 eeprom library
This patch adds a library for reading from 93cx6 eeproms. Signed-off-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 4 changed files with 307 additions and 1 deletions Side-by-side Diff
drivers/misc/Kconfig
... | ... | @@ -34,6 +34,11 @@ |
34 | 34 | If you choose to build module, its name will be phantom. If unsure, |
35 | 35 | say N here. |
36 | 36 | |
37 | +config EEPROM_93CX6 | |
38 | + tristate "EEPROM 93CX6 support" | |
39 | + ---help--- | |
40 | + This is a driver for the EEPROM chipsets 93c46 and 93c66. | |
41 | + The driver supports both read as well as write commands. | |
37 | 42 | |
38 | 43 | If unsure, say N. |
39 | 44 | |
... | ... | @@ -186,7 +191,6 @@ |
186 | 191 | notifications when the bay lever is ejected or inserted. |
187 | 192 | |
188 | 193 | If you are not sure, say Y here. |
189 | - | |
190 | 194 | |
191 | 195 | endmenu |
drivers/misc/Makefile
drivers/misc/eeprom_93cx6.c
1 | +/* | |
2 | + Copyright (C) 2004 - 2006 rt2x00 SourceForge Project | |
3 | + <http://rt2x00.serialmonkey.com> | |
4 | + | |
5 | + This program is free software; you can redistribute it and/or modify | |
6 | + it under the terms of the GNU General Public License as published by | |
7 | + the Free Software Foundation; either version 2 of the License, or | |
8 | + (at your option) any later version. | |
9 | + | |
10 | + This program is distributed in the hope that it will be useful, | |
11 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | + GNU General Public License for more details. | |
14 | + | |
15 | + You should have received a copy of the GNU General Public License | |
16 | + along with this program; if not, write to the | |
17 | + Free Software Foundation, Inc., | |
18 | + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | + */ | |
20 | + | |
21 | +/* | |
22 | + Module: eeprom_93cx6 | |
23 | + Abstract: EEPROM reader routines for 93cx6 chipsets. | |
24 | + Supported chipsets: 93c46 & 93c66. | |
25 | + */ | |
26 | + | |
27 | +#include <linux/kernel.h> | |
28 | +#include <linux/module.h> | |
29 | +#include <linux/version.h> | |
30 | +#include <linux/delay.h> | |
31 | +#include <linux/eeprom_93cx6.h> | |
32 | + | |
33 | +MODULE_AUTHOR("http://rt2x00.serialmonkey.com"); | |
34 | +MODULE_VERSION("1.0"); | |
35 | +MODULE_DESCRIPTION("EEPROM 93cx6 chip driver"); | |
36 | +MODULE_LICENSE("GPL"); | |
37 | + | |
38 | +static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom) | |
39 | +{ | |
40 | + eeprom->reg_data_clock = 1; | |
41 | + eeprom->register_write(eeprom); | |
42 | + udelay(1); | |
43 | +} | |
44 | + | |
45 | +static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom) | |
46 | +{ | |
47 | + eeprom->reg_data_clock = 0; | |
48 | + eeprom->register_write(eeprom); | |
49 | + udelay(1); | |
50 | +} | |
51 | + | |
52 | +static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom) | |
53 | +{ | |
54 | + /* | |
55 | + * Clear all flags, and enable chip select. | |
56 | + */ | |
57 | + eeprom->register_read(eeprom); | |
58 | + eeprom->reg_data_in = 0; | |
59 | + eeprom->reg_data_out = 0; | |
60 | + eeprom->reg_data_clock = 0; | |
61 | + eeprom->reg_chip_select = 1; | |
62 | + eeprom->register_write(eeprom); | |
63 | + | |
64 | + /* | |
65 | + * kick a pulse. | |
66 | + */ | |
67 | + eeprom_93cx6_pulse_high(eeprom); | |
68 | + eeprom_93cx6_pulse_low(eeprom); | |
69 | +} | |
70 | + | |
71 | +static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom) | |
72 | +{ | |
73 | + /* | |
74 | + * Clear chip_select and data_in flags. | |
75 | + */ | |
76 | + eeprom->register_read(eeprom); | |
77 | + eeprom->reg_data_in = 0; | |
78 | + eeprom->reg_chip_select = 0; | |
79 | + eeprom->register_write(eeprom); | |
80 | + | |
81 | + /* | |
82 | + * kick a pulse. | |
83 | + */ | |
84 | + eeprom_93cx6_pulse_high(eeprom); | |
85 | + eeprom_93cx6_pulse_low(eeprom); | |
86 | +} | |
87 | + | |
88 | +static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom, | |
89 | + const u16 data, const u16 count) | |
90 | +{ | |
91 | + unsigned int i; | |
92 | + | |
93 | + eeprom->register_read(eeprom); | |
94 | + | |
95 | + /* | |
96 | + * Clear data flags. | |
97 | + */ | |
98 | + eeprom->reg_data_in = 0; | |
99 | + eeprom->reg_data_out = 0; | |
100 | + | |
101 | + /* | |
102 | + * Start writing all bits. | |
103 | + */ | |
104 | + for (i = count; i > 0; i--) { | |
105 | + /* | |
106 | + * Check if this bit needs to be set. | |
107 | + */ | |
108 | + eeprom->reg_data_in = !!(data & (1 << (i - 1))); | |
109 | + | |
110 | + /* | |
111 | + * Write the bit to the eeprom register. | |
112 | + */ | |
113 | + eeprom->register_write(eeprom); | |
114 | + | |
115 | + /* | |
116 | + * Kick a pulse. | |
117 | + */ | |
118 | + eeprom_93cx6_pulse_high(eeprom); | |
119 | + eeprom_93cx6_pulse_low(eeprom); | |
120 | + } | |
121 | + | |
122 | + eeprom->reg_data_in = 0; | |
123 | + eeprom->register_write(eeprom); | |
124 | +} | |
125 | + | |
126 | +static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom, | |
127 | + u16 *data, const u16 count) | |
128 | +{ | |
129 | + unsigned int i; | |
130 | + u16 buf = 0; | |
131 | + | |
132 | + eeprom->register_read(eeprom); | |
133 | + | |
134 | + /* | |
135 | + * Clear data flags. | |
136 | + */ | |
137 | + eeprom->reg_data_in = 0; | |
138 | + eeprom->reg_data_out = 0; | |
139 | + | |
140 | + /* | |
141 | + * Start reading all bits. | |
142 | + */ | |
143 | + for (i = count; i > 0; i--) { | |
144 | + eeprom_93cx6_pulse_high(eeprom); | |
145 | + | |
146 | + eeprom->register_read(eeprom); | |
147 | + | |
148 | + /* | |
149 | + * Clear data_in flag. | |
150 | + */ | |
151 | + eeprom->reg_data_in = 0; | |
152 | + | |
153 | + /* | |
154 | + * Read if the bit has been set. | |
155 | + */ | |
156 | + if (eeprom->reg_data_out) | |
157 | + buf |= (1 << (i - 1)); | |
158 | + | |
159 | + eeprom_93cx6_pulse_low(eeprom); | |
160 | + } | |
161 | + | |
162 | + *data = buf; | |
163 | +} | |
164 | + | |
165 | +/** | |
166 | + * eeprom_93cx6_read - Read multiple words from eeprom | |
167 | + * @eeprom: Pointer to eeprom structure | |
168 | + * @word: Word index from where we should start reading | |
169 | + * @data: target pointer where the information will have to be stored | |
170 | + * | |
171 | + * This function will read the eeprom data as host-endian word | |
172 | + * into the given data pointer. | |
173 | + */ | |
174 | +void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word, | |
175 | + u16 *data) | |
176 | +{ | |
177 | + u16 command; | |
178 | + | |
179 | + /* | |
180 | + * Initialize the eeprom register | |
181 | + */ | |
182 | + eeprom_93cx6_startup(eeprom); | |
183 | + | |
184 | + /* | |
185 | + * Select the read opcode and the word to be read. | |
186 | + */ | |
187 | + command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word; | |
188 | + eeprom_93cx6_write_bits(eeprom, command, | |
189 | + PCI_EEPROM_WIDTH_OPCODE + eeprom->width); | |
190 | + | |
191 | + /* | |
192 | + * Read the requested 16 bits. | |
193 | + */ | |
194 | + eeprom_93cx6_read_bits(eeprom, data, 16); | |
195 | + | |
196 | + /* | |
197 | + * Cleanup eeprom register. | |
198 | + */ | |
199 | + eeprom_93cx6_cleanup(eeprom); | |
200 | +} | |
201 | +EXPORT_SYMBOL_GPL(eeprom_93cx6_read); | |
202 | + | |
203 | +/** | |
204 | + * eeprom_93cx6_multiread - Read multiple words from eeprom | |
205 | + * @eeprom: Pointer to eeprom structure | |
206 | + * @word: Word index from where we should start reading | |
207 | + * @data: target pointer where the information will have to be stored | |
208 | + * @words: Number of words that should be read. | |
209 | + * | |
210 | + * This function will read all requested words from the eeprom, | |
211 | + * this is done by calling eeprom_93cx6_read() multiple times. | |
212 | + * But with the additional change that while the eeprom_93cx6_read | |
213 | + * will return host ordered bytes, this method will return little | |
214 | + * endian words. | |
215 | + */ | |
216 | +void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word, | |
217 | + __le16 *data, const u16 words) | |
218 | +{ | |
219 | + unsigned int i; | |
220 | + u16 tmp; | |
221 | + | |
222 | + for (i = 0; i < words; i++) { | |
223 | + tmp = 0; | |
224 | + eeprom_93cx6_read(eeprom, word + i, &tmp); | |
225 | + data[i] = cpu_to_le16(tmp); | |
226 | + } | |
227 | +} | |
228 | +EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread); |
include/linux/eeprom_93cx6.h
1 | +/* | |
2 | + Copyright (C) 2004 - 2006 rt2x00 SourceForge Project | |
3 | + <http://rt2x00.serialmonkey.com> | |
4 | + | |
5 | + This program is free software; you can redistribute it and/or modify | |
6 | + it under the terms of the GNU General Public License as published by | |
7 | + the Free Software Foundation; either version 2 of the License, or | |
8 | + (at your option) any later version. | |
9 | + | |
10 | + This program is distributed in the hope that it will be useful, | |
11 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | + GNU General Public License for more details. | |
14 | + | |
15 | + You should have received a copy of the GNU General Public License | |
16 | + along with this program; if not, write to the | |
17 | + Free Software Foundation, Inc., | |
18 | + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | + */ | |
20 | + | |
21 | +/* | |
22 | + Module: eeprom_93cx6 | |
23 | + Abstract: EEPROM reader datastructures for 93cx6 chipsets. | |
24 | + Supported chipsets: 93c46 & 93c66. | |
25 | + */ | |
26 | + | |
27 | +/* | |
28 | + * EEPROM operation defines. | |
29 | + */ | |
30 | +#define PCI_EEPROM_WIDTH_93C46 6 | |
31 | +#define PCI_EEPROM_WIDTH_93C66 8 | |
32 | +#define PCI_EEPROM_WIDTH_OPCODE 3 | |
33 | +#define PCI_EEPROM_WRITE_OPCODE 0x05 | |
34 | +#define PCI_EEPROM_READ_OPCODE 0x06 | |
35 | +#define PCI_EEPROM_EWDS_OPCODE 0x10 | |
36 | +#define PCI_EEPROM_EWEN_OPCODE 0x13 | |
37 | + | |
38 | +/** | |
39 | + * struct eeprom_93cx6 - control structure for setting the commands | |
40 | + * for reading the eeprom data. | |
41 | + * @data: private pointer for the driver. | |
42 | + * @register_read(struct eeprom_93cx6 *eeprom): handler to | |
43 | + * read the eeprom register, this function should set all reg_* fields. | |
44 | + * @register_write(struct eeprom_93cx6 *eeprom): handler to | |
45 | + * write to the eeprom register by using all reg_* fields. | |
46 | + * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines | |
47 | + * @reg_data_in: register field to indicate data input | |
48 | + * @reg_data_out: register field to indicate data output | |
49 | + * @reg_data_clock: register field to set the data clock | |
50 | + * @reg_chip_select: register field to set the chip select | |
51 | + * | |
52 | + * This structure is used for the communication between the driver | |
53 | + * and the eeprom_93cx6 handlers for reading the eeprom. | |
54 | + */ | |
55 | +struct eeprom_93cx6 { | |
56 | + void *data; | |
57 | + | |
58 | + void (*register_read)(struct eeprom_93cx6 *eeprom); | |
59 | + void (*register_write)(struct eeprom_93cx6 *eeprom); | |
60 | + | |
61 | + int width; | |
62 | + | |
63 | + char reg_data_in; | |
64 | + char reg_data_out; | |
65 | + char reg_data_clock; | |
66 | + char reg_chip_select; | |
67 | +}; | |
68 | + | |
69 | +extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, | |
70 | + const u8 word, u16 *data); | |
71 | +extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, | |
72 | + const u8 word, __le16 *data, const u16 words); |