1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3 *
4 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5 *
6 ******************************************************************************/
7 #define _RTW_EEPROM_C_
8
9 #include <drv_conf.h>
10 #include <osdep_service.h>
11 #include <drv_types.h>
12
up_clk(_adapter * padapter,u16 * x)13 void up_clk(_adapter *padapter, u16 *x)
14 {
15 _func_enter_;
16 *x = *x | _EESK;
17 rtw_write8(padapter, EE_9346CR, (u8)*x);
18 udelay(CLOCK_RATE);
19
20 _func_exit_;
21
22 }
23
down_clk(_adapter * padapter,u16 * x)24 void down_clk(_adapter *padapter, u16 *x)
25 {
26 _func_enter_;
27 *x = *x & ~_EESK;
28 rtw_write8(padapter, EE_9346CR, (u8)*x);
29 udelay(CLOCK_RATE);
30 _func_exit_;
31 }
32
shift_out_bits(_adapter * padapter,u16 data,u16 count)33 void shift_out_bits(_adapter *padapter, u16 data, u16 count)
34 {
35 u16 x, mask;
36 _func_enter_;
37
38 if (padapter->bSurpriseRemoved == true) {
39 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
40 goto out;
41 }
42 mask = 0x01 << (count - 1);
43 x = rtw_read8(padapter, EE_9346CR);
44
45 x &= ~(_EEDO | _EEDI);
46
47 do {
48 x &= ~_EEDI;
49 if (data & mask)
50 x |= _EEDI;
51 if (padapter->bSurpriseRemoved == true) {
52 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
53 goto out;
54 }
55 rtw_write8(padapter, EE_9346CR, (u8)x);
56 udelay(CLOCK_RATE);
57 up_clk(padapter, &x);
58 down_clk(padapter, &x);
59 mask = mask >> 1;
60 } while (mask);
61 if (padapter->bSurpriseRemoved == true) {
62 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
63 goto out;
64 }
65 x &= ~_EEDI;
66 rtw_write8(padapter, EE_9346CR, (u8)x);
67 out:
68 _func_exit_;
69 }
70
shift_in_bits(_adapter * padapter)71 u16 shift_in_bits(_adapter *padapter)
72 {
73 u16 x, d = 0, i;
74 _func_enter_;
75 if (padapter->bSurpriseRemoved == true) {
76 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
77 goto out;
78 }
79 x = rtw_read8(padapter, EE_9346CR);
80
81 x &= ~(_EEDO | _EEDI);
82 d = 0;
83
84 for (i = 0; i < 16; i++) {
85 d = d << 1;
86 up_clk(padapter, &x);
87 if (padapter->bSurpriseRemoved == true) {
88 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
89 goto out;
90 }
91 x = rtw_read8(padapter, EE_9346CR);
92
93 x &= ~(_EEDI);
94 if (x & _EEDO)
95 d |= 1;
96
97 down_clk(padapter, &x);
98 }
99 out:
100 _func_exit_;
101
102 return d;
103 }
104
standby(_adapter * padapter)105 void standby(_adapter *padapter)
106 {
107 u8 x;
108 _func_enter_;
109 x = rtw_read8(padapter, EE_9346CR);
110
111 x &= ~(_EECS | _EESK);
112 rtw_write8(padapter, EE_9346CR, x);
113
114 udelay(CLOCK_RATE);
115 x |= _EECS;
116 rtw_write8(padapter, EE_9346CR, x);
117 udelay(CLOCK_RATE);
118 _func_exit_;
119 }
120
wait_eeprom_cmd_done(_adapter * padapter)121 u16 wait_eeprom_cmd_done(_adapter *padapter)
122 {
123 u8 x;
124 u16 i, res = false;
125 _func_enter_;
126 standby(padapter);
127 for (i = 0; i < 200; i++) {
128 x = rtw_read8(padapter, EE_9346CR);
129 if (x & _EEDO) {
130 res = true;
131 goto exit;
132 }
133 udelay(CLOCK_RATE);
134 }
135 exit:
136 _func_exit_;
137 return res;
138 }
139
eeprom_clean(_adapter * padapter)140 void eeprom_clean(_adapter *padapter)
141 {
142 u16 x;
143 _func_enter_;
144 if (padapter->bSurpriseRemoved == true) {
145 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
146 goto out;
147 }
148 x = rtw_read8(padapter, EE_9346CR);
149 if (padapter->bSurpriseRemoved == true) {
150 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
151 goto out;
152 }
153 x &= ~(_EECS | _EEDI);
154 rtw_write8(padapter, EE_9346CR, (u8)x);
155 if (padapter->bSurpriseRemoved == true) {
156 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
157 goto out;
158 }
159 up_clk(padapter, &x);
160 if (padapter->bSurpriseRemoved == true) {
161 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
162 goto out;
163 }
164 down_clk(padapter, &x);
165 out:
166 _func_exit_;
167 }
168
eeprom_write16(_adapter * padapter,u16 reg,u16 data)169 void eeprom_write16(_adapter *padapter, u16 reg, u16 data)
170 {
171 u8 x;
172
173 _func_enter_;
174
175 x = rtw_read8(padapter, EE_9346CR);
176
177 x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
178 x |= _EEM1 | _EECS;
179 rtw_write8(padapter, EE_9346CR, x);
180
181 shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
182
183 if (padapter->EepromAddressSize == 8) /*CF+ and SDIO*/
184 shift_out_bits(padapter, 0, 6);
185 else /*USB*/
186 shift_out_bits(padapter, 0, 4);
187
188 standby(padapter);
189
190 /* Commented out by rcnjko, 2004.0
191 * Erase this particular word. Write the erase opcode and register
192 * number in that order. The opcode is 3bits in length; reg is 6 bits long.
193 * shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3);
194 * shift_out_bits(Adapter, reg, Adapter->EepromAddressSize);
195 *
196 * if (wait_eeprom_cmd_done(Adapter ) == false)
197 * {
198 * return;
199 * }
200 */
201
202 standby(padapter);
203
204 /* write the new word to the EEPROM*/
205
206 /* send the write opcode the EEPORM*/
207 shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
208
209 /* select which word in the EEPROM that we are writing to.*/
210 shift_out_bits(padapter, reg, padapter->EepromAddressSize);
211
212 /* write the data to the selected EEPROM word.*/
213 shift_out_bits(padapter, data, 16);
214
215 if (wait_eeprom_cmd_done(padapter) == false) {
216
217 goto exit;
218 }
219
220 standby(padapter);
221
222 shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
223 shift_out_bits(padapter, reg, 4);
224
225 eeprom_clean(padapter);
226 exit:
227 _func_exit_;
228 return;
229 }
230
eeprom_read16(_adapter * padapter,u16 reg)231 u16 eeprom_read16(_adapter *padapter, u16 reg) /*ReadEEprom*/
232 {
233
234 u16 x;
235 u16 data = 0;
236
237 _func_enter_;
238
239 if (padapter->bSurpriseRemoved == true) {
240 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
241 goto out;
242 }
243 /* select EEPROM, reset bits, set _EECS*/
244 x = rtw_read8(padapter, EE_9346CR);
245
246 if (padapter->bSurpriseRemoved == true) {
247 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
248 goto out;
249 }
250
251 x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
252 x |= _EEM1 | _EECS;
253 rtw_write8(padapter, EE_9346CR, (unsigned char)x);
254
255 /* write the read opcode and register number in that order*/
256 /* The opcode is 3bits in length, reg is 6 bits long*/
257 shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
258 shift_out_bits(padapter, reg, padapter->EepromAddressSize);
259
260 /* Now read the data (16 bits) in from the selected EEPROM word*/
261 data = shift_in_bits(padapter);
262
263 eeprom_clean(padapter);
264 out:
265 _func_exit_;
266 return data;
267
268
269 }
270
271
272
273
274 /*From even offset*/
eeprom_read_sz(_adapter * padapter,u16 reg,u8 * data,u32 sz)275 void eeprom_read_sz(_adapter *padapter, u16 reg, u8 *data, u32 sz)
276 {
277
278 u16 x, data16;
279 u32 i;
280 _func_enter_;
281 if (padapter->bSurpriseRemoved == true) {
282 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
283 goto out;
284 }
285 /* select EEPROM, reset bits, set _EECS*/
286 x = rtw_read8(padapter, EE_9346CR);
287
288 if (padapter->bSurpriseRemoved == true) {
289 RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
290 goto out;
291 }
292
293 x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
294 x |= _EEM1 | _EECS;
295 rtw_write8(padapter, EE_9346CR, (unsigned char)x);
296
297 /* write the read opcode and register number in that order*/
298 /* The opcode is 3bits in length, reg is 6 bits long*/
299 shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
300 shift_out_bits(padapter, reg, padapter->EepromAddressSize);
301
302
303 for (i = 0; i < sz; i += 2) {
304 data16 = shift_in_bits(padapter);
305 data[i] = data16 & 0xff;
306 data[i+1] = data16 >> 8;
307 }
308
309 eeprom_clean(padapter);
310 out:
311 _func_exit_;
312
313
314
315 }
316
317
318 /*addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg)*/
eeprom_read(_adapter * padapter,u32 addr_off,u8 sz,u8 * rbuf)319 u8 eeprom_read(_adapter *padapter, u32 addr_off, u8 sz, u8 *rbuf)
320 {
321 u8 quotient, remainder, addr_2align_odd;
322 u16 reg, stmp, i = 0, idx = 0;
323 _func_enter_;
324 reg = (u16)(addr_off >> 1);
325 addr_2align_odd = (u8)(addr_off & 0x1);
326
327 /*read that start at high part: e.g 1,3,5,7,9,...*/
328 if (addr_2align_odd) {
329 stmp = eeprom_read16(padapter, reg);
330 rbuf[idx++] = (u8) ((stmp>>8)&0xff); /*return hogh-part of the short*/
331 reg++; sz--;
332 }
333
334 quotient = sz >> 1;
335 remainder = sz & 0x1;
336
337 for (i = 0; i < quotient; i++) {
338 stmp = eeprom_read16(padapter, reg+i);
339 rbuf[idx++] = (u8) (stmp&0xff);
340 rbuf[idx++] = (u8) ((stmp>>8)&0xff);
341 }
342
343 reg = reg+i;
344 if (remainder) { /*end of read at lower part of short : 0,2,4,6,...*/
345 stmp = eeprom_read16(padapter, reg);
346 rbuf[idx] = (u8)(stmp & 0xff);
347 }
348 _func_exit_;
349 return true;
350 }
351
352
353
read_eeprom_content(_adapter * padapter)354 void read_eeprom_content(_adapter *padapter)
355 {
356
357 _func_enter_;
358
359
360 _func_exit_;
361 }
362