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