linux/drivers/staging/rtl8712/rtl871x_eeprom.c
<<
>>
Prefs
   1/******************************************************************************
   2 * rtl871x_eeprom.c
   3 *
   4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
   5 * Linux device driver for RTL8192SU
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of version 2 of the GNU General Public License as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program; if not, write to the Free Software Foundation, Inc.,
  18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  19 *
  20 * Modifications for inclusion into the Linux staging tree are
  21 * Copyright(c) 2010 Larry Finger. All rights reserved.
  22 *
  23 * Contact information:
  24 * WLAN FAE <wlanfae@realtek.com>
  25 * Larry Finger <Larry.Finger@lwfinger.net>
  26 *
  27 ******************************************************************************/
  28
  29#define _RTL871X_EEPROM_C_
  30
  31#include "osdep_service.h"
  32#include "drv_types.h"
  33
  34static void up_clk(struct _adapter *padapter, u16 *x)
  35{
  36        *x = *x | _EESK;
  37        r8712_write8(padapter, EE_9346CR, (u8)*x);
  38        udelay(CLOCK_RATE);
  39}
  40
  41static void down_clk(struct _adapter *padapter, u16 *x)
  42{
  43        *x = *x & ~_EESK;
  44        r8712_write8(padapter, EE_9346CR, (u8)*x);
  45        udelay(CLOCK_RATE);
  46}
  47
  48static void shift_out_bits(struct _adapter *padapter, u16 data, u16 count)
  49{
  50        u16 x, mask;
  51
  52        if (padapter->bSurpriseRemoved)
  53                goto out;
  54        mask = 0x01 << (count - 1);
  55        x = r8712_read8(padapter, EE_9346CR);
  56        x &= ~(_EEDO | _EEDI);
  57        do {
  58                x &= ~_EEDI;
  59                if (data & mask)
  60                        x |= _EEDI;
  61                if (padapter->bSurpriseRemoved)
  62                        goto out;
  63                r8712_write8(padapter, EE_9346CR, (u8)x);
  64                udelay(CLOCK_RATE);
  65                up_clk(padapter, &x);
  66                down_clk(padapter, &x);
  67                mask >>= 1;
  68        } while (mask);
  69        if (padapter->bSurpriseRemoved)
  70                goto out;
  71        x &= ~_EEDI;
  72        r8712_write8(padapter, EE_9346CR, (u8)x);
  73out:;
  74}
  75
  76static u16 shift_in_bits(struct _adapter *padapter)
  77{
  78        u16 x, d = 0, i;
  79
  80        if (padapter->bSurpriseRemoved)
  81                goto out;
  82        x = r8712_read8(padapter, EE_9346CR);
  83        x &= ~(_EEDO | _EEDI);
  84        d = 0;
  85        for (i = 0; i < 16; i++) {
  86                d <<= 1;
  87                up_clk(padapter, &x);
  88                if (padapter->bSurpriseRemoved)
  89                        goto out;
  90                x = r8712_read8(padapter, EE_9346CR);
  91                x &= ~(_EEDI);
  92                if (x & _EEDO)
  93                        d |= 1;
  94                down_clk(padapter, &x);
  95        }
  96out:
  97        return d;
  98}
  99
 100static void standby(struct _adapter *padapter)
 101{
 102        u8   x;
 103
 104        x = r8712_read8(padapter, EE_9346CR);
 105        x &= ~(_EECS | _EESK);
 106        r8712_write8(padapter, EE_9346CR, x);
 107        udelay(CLOCK_RATE);
 108        x |= _EECS;
 109        r8712_write8(padapter, EE_9346CR, x);
 110        udelay(CLOCK_RATE);
 111}
 112
 113static u16 wait_eeprom_cmd_done(struct _adapter *padapter)
 114{
 115        u8      x;
 116        u16     i;
 117
 118        standby(padapter);
 119        for (i = 0; i < 200; i++) {
 120                x = r8712_read8(padapter, EE_9346CR);
 121                if (x & _EEDO)
 122                        return true;
 123                udelay(CLOCK_RATE);
 124        }
 125        return false;
 126}
 127
 128static void eeprom_clean(struct _adapter *padapter)
 129{
 130        u16 x;
 131
 132        if (padapter->bSurpriseRemoved)
 133                return;
 134        x = r8712_read8(padapter, EE_9346CR);
 135        if (padapter->bSurpriseRemoved)
 136                return;
 137        x &= ~(_EECS | _EEDI);
 138        r8712_write8(padapter, EE_9346CR, (u8)x);
 139        if (padapter->bSurpriseRemoved)
 140                return;
 141        up_clk(padapter, &x);
 142        if (padapter->bSurpriseRemoved)
 143                return;
 144        down_clk(padapter, &x);
 145}
 146
 147void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data)
 148{
 149        u8 x;
 150        u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new;
 151
 152        tmp8_ori = r8712_read8(padapter, 0x102502f1);
 153        tmp8_new = tmp8_ori & 0xf7;
 154        if (tmp8_ori != tmp8_new)
 155                r8712_write8(padapter, 0x102502f1, tmp8_new);
 156        tmp8_clk_ori = r8712_read8(padapter, 0x10250003);
 157        tmp8_clk_new = tmp8_clk_ori | 0x20;
 158        if (tmp8_clk_new != tmp8_clk_ori)
 159                r8712_write8(padapter, 0x10250003, tmp8_clk_new);
 160        x = r8712_read8(padapter, EE_9346CR);
 161        x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
 162        x |= _EEM1 | _EECS;
 163        r8712_write8(padapter, EE_9346CR, x);
 164        shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
 165        if (padapter->EepromAddressSize == 8)   /*CF+ and SDIO*/
 166                shift_out_bits(padapter, 0, 6);
 167        else    /* USB */
 168                shift_out_bits(padapter, 0, 4);
 169        standby(padapter);
 170        /* Erase this particular word.  Write the erase opcode and register
 171         * number in that order. The opcode is 3bits in length; reg is 6
 172         * bits long.
 173         */
 174        standby(padapter);
 175        /* write the new word to the EEPROM
 176         * send the write opcode the EEPORM
 177         */
 178        shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
 179        /* select which word in the EEPROM that we are writing to. */
 180        shift_out_bits(padapter, reg, padapter->EepromAddressSize);
 181        /* write the data to the selected EEPROM word. */
 182        shift_out_bits(padapter, data, 16);
 183        if (wait_eeprom_cmd_done(padapter)) {
 184                standby(padapter);
 185                shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
 186                shift_out_bits(padapter, reg, 4);
 187                eeprom_clean(padapter);
 188        }
 189        if (tmp8_clk_new != tmp8_clk_ori)
 190                r8712_write8(padapter, 0x10250003, tmp8_clk_ori);
 191        if (tmp8_new != tmp8_ori)
 192                r8712_write8(padapter, 0x102502f1, tmp8_ori);
 193}
 194
 195u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/
 196{
 197        u16 x;
 198        u16 data = 0;
 199        u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new;
 200
 201        tmp8_ori = r8712_read8(padapter, 0x102502f1);
 202        tmp8_new = tmp8_ori & 0xf7;
 203        if (tmp8_ori != tmp8_new)
 204                r8712_write8(padapter, 0x102502f1, tmp8_new);
 205        tmp8_clk_ori = r8712_read8(padapter, 0x10250003);
 206        tmp8_clk_new = tmp8_clk_ori | 0x20;
 207        if (tmp8_clk_new != tmp8_clk_ori)
 208                r8712_write8(padapter, 0x10250003, tmp8_clk_new);
 209        if (padapter->bSurpriseRemoved)
 210                goto out;
 211        /* select EEPROM, reset bits, set _EECS */
 212        x = r8712_read8(padapter, EE_9346CR);
 213        if (padapter->bSurpriseRemoved)
 214                goto out;
 215        x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
 216        x |= _EEM1 | _EECS;
 217        r8712_write8(padapter, EE_9346CR, (unsigned char)x);
 218        /* write the read opcode and register number in that order
 219         * The opcode is 3bits in length, reg is 6 bits long
 220         */
 221        shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
 222        shift_out_bits(padapter, reg, padapter->EepromAddressSize);
 223        /* Now read the data (16 bits) in from the selected EEPROM word */
 224        data = shift_in_bits(padapter);
 225        eeprom_clean(padapter);
 226out:
 227        if (tmp8_clk_new != tmp8_clk_ori)
 228                r8712_write8(padapter, 0x10250003, tmp8_clk_ori);
 229        if (tmp8_new != tmp8_ori)
 230                r8712_write8(padapter, 0x102502f1, tmp8_ori);
 231        return data;
 232}
 233
 234