rtl871x_eeprom.c (5816B)
1// SPDX-License-Identifier: GPL-2.0 2/****************************************************************************** 3 * rtl871x_eeprom.c 4 * 5 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 6 * Linux device driver for RTL8192SU 7 * 8 * Modifications for inclusion into the Linux staging tree are 9 * Copyright(c) 2010 Larry Finger. All rights reserved. 10 * 11 * Contact information: 12 * WLAN FAE <wlanfae@realtek.com> 13 * Larry Finger <Larry.Finger@lwfinger.net> 14 * 15 ******************************************************************************/ 16 17#define _RTL871X_EEPROM_C_ 18 19#include "osdep_service.h" 20#include "drv_types.h" 21 22static void up_clk(struct _adapter *padapter, u16 *x) 23{ 24 *x = *x | _EESK; 25 r8712_write8(padapter, EE_9346CR, (u8)*x); 26 udelay(CLOCK_RATE); 27} 28 29static void down_clk(struct _adapter *padapter, u16 *x) 30{ 31 *x = *x & ~_EESK; 32 r8712_write8(padapter, EE_9346CR, (u8)*x); 33 udelay(CLOCK_RATE); 34} 35 36static void shift_out_bits(struct _adapter *padapter, u16 data, u16 count) 37{ 38 u16 x, mask; 39 40 if (padapter->surprise_removed) 41 goto out; 42 mask = 0x01 << (count - 1); 43 x = r8712_read8(padapter, EE_9346CR); 44 x &= ~(_EEDO | _EEDI); 45 do { 46 x &= ~_EEDI; 47 if (data & mask) 48 x |= _EEDI; 49 if (padapter->surprise_removed) 50 goto out; 51 r8712_write8(padapter, EE_9346CR, (u8)x); 52 udelay(CLOCK_RATE); 53 up_clk(padapter, &x); 54 down_clk(padapter, &x); 55 mask >>= 1; 56 } while (mask); 57 if (padapter->surprise_removed) 58 goto out; 59 x &= ~_EEDI; 60 r8712_write8(padapter, EE_9346CR, (u8)x); 61out:; 62} 63 64static u16 shift_in_bits(struct _adapter *padapter) 65{ 66 u16 x, d = 0, i; 67 68 if (padapter->surprise_removed) 69 goto out; 70 x = r8712_read8(padapter, EE_9346CR); 71 x &= ~(_EEDO | _EEDI); 72 d = 0; 73 for (i = 0; i < 16; i++) { 74 d <<= 1; 75 up_clk(padapter, &x); 76 if (padapter->surprise_removed) 77 goto out; 78 x = r8712_read8(padapter, EE_9346CR); 79 x &= ~(_EEDI); 80 if (x & _EEDO) 81 d |= 1; 82 down_clk(padapter, &x); 83 } 84out: 85 return d; 86} 87 88static void standby(struct _adapter *padapter) 89{ 90 u8 x; 91 92 x = r8712_read8(padapter, EE_9346CR); 93 x &= ~(_EECS | _EESK); 94 r8712_write8(padapter, EE_9346CR, x); 95 udelay(CLOCK_RATE); 96 x |= _EECS; 97 r8712_write8(padapter, EE_9346CR, x); 98 udelay(CLOCK_RATE); 99} 100 101static u16 wait_eeprom_cmd_done(struct _adapter *padapter) 102{ 103 u8 x; 104 u16 i; 105 106 standby(padapter); 107 for (i = 0; i < 200; i++) { 108 x = r8712_read8(padapter, EE_9346CR); 109 if (x & _EEDO) 110 return true; 111 udelay(CLOCK_RATE); 112 } 113 return false; 114} 115 116static void eeprom_clean(struct _adapter *padapter) 117{ 118 u16 x; 119 120 if (padapter->surprise_removed) 121 return; 122 x = r8712_read8(padapter, EE_9346CR); 123 if (padapter->surprise_removed) 124 return; 125 x &= ~(_EECS | _EEDI); 126 r8712_write8(padapter, EE_9346CR, (u8)x); 127 if (padapter->surprise_removed) 128 return; 129 up_clk(padapter, &x); 130 if (padapter->surprise_removed) 131 return; 132 down_clk(padapter, &x); 133} 134 135void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data) 136{ 137 u8 x; 138 u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; 139 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); 150 x |= _EEM1 | _EECS; 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); 155 else /* USB */ 156 shift_out_bits(padapter, 0, 4); 157 standby(padapter); 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 160 * bits long. 161 */ 162 standby(padapter); 163 /* write the new word to the EEPROM 164 * send the write opcode the EEPORM 165 */ 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)) { 172 standby(padapter); 173 shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); 174 shift_out_bits(padapter, reg, 4); 175 eeprom_clean(padapter); 176 } 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); 181} 182 183u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/ 184{ 185 u16 x; 186 u16 data = 0; 187 u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; 188 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) 198 goto out; 199 /* select EEPROM, reset bits, set _EECS */ 200 x = r8712_read8(padapter, EE_9346CR); 201 if (padapter->surprise_removed) 202 goto out; 203 x &= ~(_EEDI | _EEDO | _EESK | _EEM0); 204 x |= _EEM1 | _EECS; 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 208 */ 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); 214out: 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); 219 return data; 220}