2 * Intel Wireless Multicomm 3200 WiFi driver
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
39 #include <linux/kernel.h>
46 static struct iwm_eeprom_entry eeprom_map
[] = {
48 {"Signature", IWM_EEPROM_SIG_OFF
, IWM_EEPROM_SIG_LEN
},
50 [IWM_EEPROM_VERSION
] =
51 {"Version", IWM_EEPROM_VERSION_OFF
, IWM_EEPROM_VERSION_LEN
},
53 [IWM_EEPROM_OEM_HW_VERSION
] =
54 {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF
,
55 IWM_EEPROM_OEM_HW_VERSION_LEN
},
57 [IWM_EEPROM_MAC_VERSION
] =
58 {"MAC version", IWM_EEPROM_MAC_VERSION_OFF
, IWM_EEPROM_MAC_VERSION_LEN
},
60 [IWM_EEPROM_CARD_ID
] =
61 {"Card ID", IWM_EEPROM_CARD_ID_OFF
, IWM_EEPROM_CARD_ID_LEN
},
63 [IWM_EEPROM_RADIO_CONF
] =
64 {"Radio config", IWM_EEPROM_RADIO_CONF_OFF
, IWM_EEPROM_RADIO_CONF_LEN
},
66 [IWM_EEPROM_SKU_CAP
] =
67 {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF
, IWM_EEPROM_SKU_CAP_LEN
},
69 [IWM_EEPROM_CALIB_RXIQ_OFFSET
] =
70 {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF
, IWM_EEPROM_INDIRECT_LEN
},
72 [IWM_EEPROM_CALIB_RXIQ
] =
73 {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN
},
77 static int iwm_eeprom_read(struct iwm_priv
*iwm
, u8 eeprom_id
)
80 u32 entry_size
, chunk_size
, data_offset
= 0, addr_offset
= 0;
82 struct iwm_udma_wifi_cmd udma_cmd
;
83 struct iwm_umac_cmd umac_cmd
;
84 struct iwm_umac_cmd_eeprom_proxy eeprom_cmd
;
86 if (eeprom_id
> (IWM_EEPROM_LAST
- 1))
89 entry_size
= eeprom_map
[eeprom_id
].length
;
91 if (eeprom_id
>= IWM_EEPROM_INDIRECT_DATA
) {
93 u32 off_id
= eeprom_id
- IWM_EEPROM_INDIRECT_DATA
+
94 IWM_EEPROM_INDIRECT_OFFSET
;
96 eeprom_map
[eeprom_id
].offset
=
97 *(u16
*)(iwm
->eeprom
+ eeprom_map
[off_id
].offset
) << 1;
100 addr
= eeprom_map
[eeprom_id
].offset
;
103 udma_cmd
.credit_group
= 0x4;
104 udma_cmd
.ra_tid
= UMAC_HDI_ACT_TBL_IDX_HOST_CMD
;
105 udma_cmd
.lmac_offset
= 0;
107 umac_cmd
.id
= UMAC_CMD_OPCODE_EEPROM_PROXY
;
110 while (entry_size
> 0) {
111 chunk_size
= min_t(u32
, entry_size
, IWM_MAX_EEPROM_DATA_LEN
);
113 eeprom_cmd
.hdr
.type
=
114 cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ
);
115 eeprom_cmd
.hdr
.offset
= cpu_to_le32(addr
+ addr_offset
);
116 eeprom_cmd
.hdr
.len
= cpu_to_le32(chunk_size
);
118 ret
= iwm_hal_send_umac_cmd(iwm
, &udma_cmd
,
119 &umac_cmd
, &eeprom_cmd
,
120 sizeof(struct iwm_umac_cmd_eeprom_proxy
));
122 IWM_ERR(iwm
, "Couldn't read eeprom\n");
126 ret
= iwm_notif_handle(iwm
, UMAC_CMD_OPCODE_EEPROM_PROXY
,
129 IWM_ERR(iwm
, "Did not get any eeprom answer\n");
133 data_offset
+= chunk_size
;
134 addr_offset
+= chunk_size
;
135 entry_size
-= chunk_size
;
141 u8
*iwm_eeprom_access(struct iwm_priv
*iwm
, u8 eeprom_id
)
144 return ERR_PTR(-ENODEV
);
146 return iwm
->eeprom
+ eeprom_map
[eeprom_id
].offset
;
149 int iwm_eeprom_init(struct iwm_priv
*iwm
)
154 iwm
->eeprom
= kzalloc(IWM_EEPROM_LEN
, GFP_KERNEL
);
158 for (i
= IWM_EEPROM_FIRST
; i
< IWM_EEPROM_LAST
; i
++) {
159 ret
= iwm_eeprom_read(iwm
, i
);
161 IWM_ERR(iwm
, "Couldn't read eeprom entry #%d: %s\n",
162 i
, eeprom_map
[i
].name
);
167 IWM_DBG_BOOT(iwm
, DBG
, "EEPROM dump:\n");
168 for (i
= IWM_EEPROM_FIRST
; i
< IWM_EEPROM_LAST
; i
++) {
170 sprintf(name
, "%s: ", eeprom_map
[i
].name
);
172 IWM_HEXDUMP(iwm
, DBG
, BOOT
, name
,
173 iwm
->eeprom
+ eeprom_map
[i
].offset
,
174 eeprom_map
[i
].length
);
180 void iwm_eeprom_exit(struct iwm_priv
*iwm
)