blob: 880615f938168a395009e6d77016e0a393376889 [file] [log] [blame]
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2010 Nokia Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/platform_device.h>
24
Luciano Coelhoffeb5012011-11-21 18:55:51 +020025#include <linux/err.h>
26
Luciano Coelhob2ba99f2011-11-20 23:32:10 +020027#include "../wlcore/wlcore.h"
Luciano Coelhoffeb5012011-11-21 18:55:51 +020028#include "../wlcore/debug.h"
Luciano Coelho4ded91c2012-04-11 10:54:52 +030029#include "../wlcore/io.h"
Luciano Coelhoffeb5012011-11-21 18:55:51 +020030
Luciano Coelho00782132011-11-29 13:38:37 +020031#include "reg.h"
Luciano Coelho25a43d72011-11-21 20:37:14 +020032
Luciano Coelho25a43d72011-11-21 20:37:14 +020033static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = {
34 [PART_DOWN] = {
35 .mem = {
36 .start = 0x00000000,
37 .size = 0x000177c0
38 },
39 .reg = {
40 .start = REGISTERS_BASE,
41 .size = 0x00008800
42 },
43 .mem2 = {
44 .start = 0x00000000,
45 .size = 0x00000000
46 },
47 .mem3 = {
48 .start = 0x00000000,
49 .size = 0x00000000
50 },
51 },
52
Luciano Coelho00782132011-11-29 13:38:37 +020053 [PART_BOOT] = { /* in wl12xx we can use a mix of work and down
54 * partition here */
55 .mem = {
56 .start = 0x00040000,
57 .size = 0x00014fc0
58 },
59 .reg = {
60 .start = REGISTERS_BASE,
61 .size = 0x00008800
62 },
63 .mem2 = {
64 .start = 0x00000000,
65 .size = 0x00000000
66 },
67 .mem3 = {
68 .start = 0x00000000,
69 .size = 0x00000000
70 },
71 },
72
Luciano Coelho25a43d72011-11-21 20:37:14 +020073 [PART_WORK] = {
74 .mem = {
75 .start = 0x00040000,
76 .size = 0x00014fc0
77 },
78 .reg = {
79 .start = REGISTERS_BASE,
80 .size = 0x0000a000
81 },
82 .mem2 = {
83 .start = 0x003004f8,
84 .size = 0x00000004
85 },
86 .mem3 = {
87 .start = 0x00040404,
88 .size = 0x00000000
89 },
90 },
91
92 [PART_DRPW] = {
93 .mem = {
94 .start = 0x00040000,
95 .size = 0x00014fc0
96 },
97 .reg = {
98 .start = DRPW_BASE,
99 .size = 0x00006000
100 },
101 .mem2 = {
102 .start = 0x00000000,
103 .size = 0x00000000
104 },
105 .mem3 = {
106 .start = 0x00000000,
107 .size = 0x00000000
108 }
109 }
110};
111
Luciano Coelho00782132011-11-29 13:38:37 +0200112static const int wl12xx_rtable[REG_TABLE_LEN] = {
113 [REG_ECPU_CONTROL] = WL12XX_REG_ECPU_CONTROL,
114 [REG_INTERRUPT_NO_CLEAR] = WL12XX_REG_INTERRUPT_NO_CLEAR,
115 [REG_INTERRUPT_ACK] = WL12XX_REG_INTERRUPT_ACK,
116 [REG_COMMAND_MAILBOX_PTR] = WL12XX_REG_COMMAND_MAILBOX_PTR,
117 [REG_EVENT_MAILBOX_PTR] = WL12XX_REG_EVENT_MAILBOX_PTR,
118 [REG_INTERRUPT_TRIG] = WL12XX_REG_INTERRUPT_TRIG,
119 [REG_INTERRUPT_MASK] = WL12XX_REG_INTERRUPT_MASK,
120 [REG_PC_ON_RECOVERY] = WL12XX_SCR_PAD4,
121 [REG_CHIP_ID_B] = WL12XX_CHIP_ID_B,
122 [REG_CMD_MBOX_ADDRESS] = WL12XX_CMD_MBOX_ADDRESS,
123
124 /* data access memory addresses, used with partition translation */
125 [REG_SLV_MEM_DATA] = WL1271_SLV_MEM_DATA,
126 [REG_SLV_REG_DATA] = WL1271_SLV_REG_DATA,
127
128 /* raw data access memory addresses */
129 [REG_RAW_FW_STATUS_ADDR] = FW_STATUS_ADDR,
130};
131
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200132/* TODO: maybe move to a new header file? */
133#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
134#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
135#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
136
137#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
138#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
139#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
140
141static int wl12xx_identify_chip(struct wl1271 *wl)
142{
143 int ret = 0;
144
145 switch (wl->chip.id) {
146 case CHIP_ID_1271_PG10:
147 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
148 wl->chip.id);
149
150 wl->quirks |= WLCORE_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
151 wl->plt_fw_name = WL127X_PLT_FW_NAME;
152 wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
153 wl->mr_fw_name = WL127X_FW_NAME_MULTI;
154 break;
155
156 case CHIP_ID_1271_PG20:
157 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
158 wl->chip.id);
159
160 wl->quirks |= WLCORE_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
161 wl->plt_fw_name = WL127X_PLT_FW_NAME;
162 wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
163 wl->mr_fw_name = WL127X_FW_NAME_MULTI;
164 break;
165
166 case CHIP_ID_1283_PG20:
167 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
168 wl->chip.id);
169 wl->plt_fw_name = WL128X_PLT_FW_NAME;
170 wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
171 wl->mr_fw_name = WL128X_FW_NAME_MULTI;
172 break;
173 case CHIP_ID_1283_PG10:
174 default:
175 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
176 ret = -ENODEV;
177 goto out;
178 }
179
180out:
181 return ret;
182}
183
Luciano Coelho4ded91c2012-04-11 10:54:52 +0300184static s8 wl12xx_get_pg_ver(struct wl1271 *wl)
185{
186 u32 die_info;
187
188 if (wl->chip.id == CHIP_ID_1283_PG20)
189 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
190 else
191 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
192
193 return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
194}
195
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200196static struct wlcore_ops wl12xx_ops = {
197 .identify_chip = wl12xx_identify_chip,
Luciano Coelho4ded91c2012-04-11 10:54:52 +0300198 .get_pg_ver = wl12xx_get_pg_ver,
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200199};
200
Luciano Coelhoffeb5012011-11-21 18:55:51 +0200201static int __devinit wl12xx_probe(struct platform_device *pdev)
202{
203 struct wl1271 *wl;
204 struct ieee80211_hw *hw;
205
206 hw = wlcore_alloc_hw();
207 if (IS_ERR(hw)) {
208 wl1271_error("can't allocate hw");
209 return PTR_ERR(hw);
210 }
211
212 wl = hw->priv;
Luciano Coelhoc31be252011-11-21 19:25:24 +0200213 wl->ops = &wl12xx_ops;
Luciano Coelho25a43d72011-11-21 20:37:14 +0200214 wl->ptable = wl12xx_ptable;
Luciano Coelho00782132011-11-29 13:38:37 +0200215 wl->rtable = wl12xx_rtable;
Luciano Coelhoffeb5012011-11-21 18:55:51 +0200216
217 return wlcore_probe(wl, pdev);
218}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +0200219
220static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
221 { "wl12xx", 0 },
222 { } /* Terminating Entry */
223};
224MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
225
226static struct platform_driver wl12xx_driver = {
Luciano Coelhoffeb5012011-11-21 18:55:51 +0200227 .probe = wl12xx_probe,
Luciano Coelhob2ba99f2011-11-20 23:32:10 +0200228 .remove = __devexit_p(wlcore_remove),
229 .id_table = wl12xx_id_table,
230 .driver = {
231 .name = "wl12xx_driver",
232 .owner = THIS_MODULE,
233 }
234};
235
236static int __init wl12xx_init(void)
237{
238 return platform_driver_register(&wl12xx_driver);
239}
240module_init(wl12xx_init);
241
242static void __exit wl12xx_exit(void)
243{
244 platform_driver_unregister(&wl12xx_driver);
245}
246module_exit(wl12xx_exit);
247
248MODULE_LICENSE("GPL v2");
249MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200250MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
251MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
252MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
253MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
254MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
255MODULE_FIRMWARE(WL128X_PLT_FW_NAME);