1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
5 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
6 * Linux device driver for RTL8192SU
8 * Modifications for inclusion into the Linux staging tree are
9 * Copyright(c) 2010 Larry Finger. All rights reserved.
11 * Contact information:
12 * WLAN FAE <wlanfae@realtek.com>
13 * Larry Finger <Larry.Finger@lwfinger.net>
15 ******************************************************************************/
17 #define _RTL871X_EEPROM_C_
19 #include "osdep_service.h"
20 #include "drv_types.h"
22 static void up_clk(struct _adapter *padapter, u16 *x)
25 r8712_write8(padapter, EE_9346CR, (u8)*x);
29 static void down_clk(struct _adapter *padapter, u16 *x)
32 r8712_write8(padapter, EE_9346CR, (u8)*x);
36 static void shift_out_bits(struct _adapter *padapter, u16 data, u16 count)
40 if (padapter->surprise_removed)
42 mask = 0x01 << (count - 1);
43 x = r8712_read8(padapter, EE_9346CR);
44 x &= ~(_EEDO | _EEDI);
49 if (padapter->surprise_removed)
51 r8712_write8(padapter, EE_9346CR, (u8)x);
54 down_clk(padapter, &x);
57 if (padapter->surprise_removed)
60 r8712_write8(padapter, EE_9346CR, (u8)x);
64 static u16 shift_in_bits(struct _adapter *padapter)
68 if (padapter->surprise_removed)
70 x = r8712_read8(padapter, EE_9346CR);
71 x &= ~(_EEDO | _EEDI);
73 for (i = 0; i < 16; i++) {
76 if (padapter->surprise_removed)
78 x = r8712_read8(padapter, EE_9346CR);
82 down_clk(padapter, &x);
88 static void standby(struct _adapter *padapter)
92 x = r8712_read8(padapter, EE_9346CR);
93 x &= ~(_EECS | _EESK);
94 r8712_write8(padapter, EE_9346CR, x);
97 r8712_write8(padapter, EE_9346CR, x);
101 static u16 wait_eeprom_cmd_done(struct _adapter *padapter)
107 for (i = 0; i < 200; i++) {
108 x = r8712_read8(padapter, EE_9346CR);
116 static void eeprom_clean(struct _adapter *padapter)
120 if (padapter->surprise_removed)
122 x = r8712_read8(padapter, EE_9346CR);
123 if (padapter->surprise_removed)
125 x &= ~(_EECS | _EEDI);
126 r8712_write8(padapter, EE_9346CR, (u8)x);
127 if (padapter->surprise_removed)
129 up_clk(padapter, &x);
130 if (padapter->surprise_removed)
132 down_clk(padapter, &x);
135 void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data)
138 u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new;
140 tmp8_ori = r8712_read8(padapter, 0x102502f1);
141 tmp8_new = tmp8_ori & 0xf7;
142 if (tmp8_ori != tmp8_new)
143 r8712_write8(padapter, 0x102502f1, tmp8_new);
144 tmp8_clk_ori = r8712_read8(padapter, 0x10250003);
145 tmp8_clk_new = tmp8_clk_ori | 0x20;
146 if (tmp8_clk_new != tmp8_clk_ori)
147 r8712_write8(padapter, 0x10250003, tmp8_clk_new);
148 x = r8712_read8(padapter, EE_9346CR);
149 x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
151 r8712_write8(padapter, EE_9346CR, x);
152 shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
153 if (padapter->eeprom_address_size == 8) /*CF+ and SDIO*/
154 shift_out_bits(padapter, 0, 6);
156 shift_out_bits(padapter, 0, 4);
158 /* Erase this particular word. Write the erase opcode and register
159 * number in that order. The opcode is 3bits in length; reg is 6
163 /* write the new word to the EEPROM
164 * send the write opcode the EEPORM
166 shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
167 /* select which word in the EEPROM that we are writing to. */
168 shift_out_bits(padapter, reg, padapter->eeprom_address_size);
169 /* write the data to the selected EEPROM word. */
170 shift_out_bits(padapter, data, 16);
171 if (wait_eeprom_cmd_done(padapter)) {
173 shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
174 shift_out_bits(padapter, reg, 4);
175 eeprom_clean(padapter);
177 if (tmp8_clk_new != tmp8_clk_ori)
178 r8712_write8(padapter, 0x10250003, tmp8_clk_ori);
179 if (tmp8_new != tmp8_ori)
180 r8712_write8(padapter, 0x102502f1, tmp8_ori);
183 u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/
187 u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new;
189 tmp8_ori = r8712_read8(padapter, 0x102502f1);
190 tmp8_new = tmp8_ori & 0xf7;
191 if (tmp8_ori != tmp8_new)
192 r8712_write8(padapter, 0x102502f1, tmp8_new);
193 tmp8_clk_ori = r8712_read8(padapter, 0x10250003);
194 tmp8_clk_new = tmp8_clk_ori | 0x20;
195 if (tmp8_clk_new != tmp8_clk_ori)
196 r8712_write8(padapter, 0x10250003, tmp8_clk_new);
197 if (padapter->surprise_removed)
199 /* select EEPROM, reset bits, set _EECS */
200 x = r8712_read8(padapter, EE_9346CR);
201 if (padapter->surprise_removed)
203 x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
205 r8712_write8(padapter, EE_9346CR, (unsigned char)x);
206 /* write the read opcode and register number in that order
207 * The opcode is 3bits in length, reg is 6 bits long
209 shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
210 shift_out_bits(padapter, reg, padapter->eeprom_address_size);
211 /* Now read the data (16 bits) in from the selected EEPROM word */
212 data = shift_in_bits(padapter);
213 eeprom_clean(padapter);
215 if (tmp8_clk_new != tmp8_clk_ori)
216 r8712_write8(padapter, 0x10250003, tmp8_clk_ori);
217 if (tmp8_new != tmp8_ori)
218 r8712_write8(padapter, 0x102502f1, tmp8_ori);