diff options
author | Eliad Peller <eliad@wizery.com> | 2015-03-18 12:38:28 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2015-03-24 12:48:14 -0400 |
commit | 5ea5c518ccaba0de97efb71c3bccbcdee681c2e6 (patch) | |
tree | ec53d5f41d602523928155ab6ad301423c805ff1 /drivers/net | |
parent | d96c8b77407de054e7a485bdef793ed5be827df4 (diff) |
wlcore: add device-tree support
When running with device-tree, we no longer have a board file
that can set up the platform data for wlcore.
Allow this data to be passed from DT.
Signed-off-by: Ido Yariv <ido@wizery.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
Tested-by: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
Tested-by: Nikita Kiryanov <nikita@compulab.co.il>
Acked-by: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ti/wlcore/sdio.c | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 2bce00afea1f..b55dc0ede513 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <linux/wl12xx.h> | 34 | #include <linux/wl12xx.h> |
35 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
36 | #include <linux/printk.h> | 36 | #include <linux/printk.h> |
37 | #include <linux/of.h> | ||
38 | #include <linux/of_irq.h> | ||
37 | 39 | ||
38 | #include "wlcore.h" | 40 | #include "wlcore.h" |
39 | #include "wl12xx_80211.h" | 41 | #include "wl12xx_80211.h" |
@@ -214,6 +216,82 @@ static struct wl1271_if_operations sdio_ops = { | |||
214 | .set_block_size = wl1271_sdio_set_block_size, | 216 | .set_block_size = wl1271_sdio_set_block_size, |
215 | }; | 217 | }; |
216 | 218 | ||
219 | #ifdef CONFIG_OF | ||
220 | static const struct of_device_id wlcore_sdio_of_match_table[] = { | ||
221 | { .compatible = "ti,wl1271" }, | ||
222 | { .compatible = "ti,wl1273" }, | ||
223 | { .compatible = "ti,wl1281" }, | ||
224 | { .compatible = "ti,wl1283" }, | ||
225 | { .compatible = "ti,wl1801" }, | ||
226 | { .compatible = "ti,wl1805" }, | ||
227 | { .compatible = "ti,wl1807" }, | ||
228 | { .compatible = "ti,wl1831" }, | ||
229 | { .compatible = "ti,wl1835" }, | ||
230 | { .compatible = "ti,wl1837" }, | ||
231 | { } | ||
232 | }; | ||
233 | |||
234 | static struct wl12xx_platform_data *wlcore_probe_of(struct device *dev) | ||
235 | { | ||
236 | struct device_node *np = dev->of_node; | ||
237 | struct wl12xx_platform_data *pdata; | ||
238 | |||
239 | if (!np || !of_match_node(wlcore_sdio_of_match_table, np)) | ||
240 | return NULL; | ||
241 | |||
242 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
243 | if (!pdata) | ||
244 | return NULL; | ||
245 | |||
246 | pdata->irq = irq_of_parse_and_map(np, 0); | ||
247 | if (!pdata->irq) { | ||
248 | dev_err(dev, "No irq in platform data\n"); | ||
249 | kfree(pdata); | ||
250 | return NULL; | ||
251 | } | ||
252 | |||
253 | pdata->irq_trigger = | ||
254 | irqd_get_trigger_type(irq_get_irq_data(pdata->irq)); | ||
255 | |||
256 | /* optional clock frequency params */ | ||
257 | of_property_read_u32(np, "ref-clock-frequency", | ||
258 | &pdata->ref_clock_freq); | ||
259 | of_property_read_u32(np, "tcxo-clock-frequency", | ||
260 | &pdata->tcxo_clock_freq); | ||
261 | |||
262 | return pdata; | ||
263 | } | ||
264 | #else | ||
265 | static struct wl12xx_platform_data *wlcore_probe_of(struct device *dev) | ||
266 | { | ||
267 | return NULL; | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | static struct wl12xx_platform_data * | ||
272 | wlcore_get_platform_data(struct device *dev) | ||
273 | { | ||
274 | struct wl12xx_platform_data *pdata; | ||
275 | |||
276 | /* first, look for DT data */ | ||
277 | pdata = wlcore_probe_of(dev); | ||
278 | if (pdata) | ||
279 | return pdata; | ||
280 | |||
281 | /* if not found - fallback to static platform data */ | ||
282 | pdata = wl12xx_get_platform_data(); | ||
283 | if (!IS_ERR(pdata)) | ||
284 | return kmemdup(pdata, sizeof(*pdata), GFP_KERNEL); | ||
285 | |||
286 | dev_err(dev, "No platform data set\n"); | ||
287 | return NULL; | ||
288 | } | ||
289 | |||
290 | static void wlcore_del_platform_data(struct wl12xx_platform_data *pdata) | ||
291 | { | ||
292 | kfree(pdata); | ||
293 | } | ||
294 | |||
217 | static int wl1271_probe(struct sdio_func *func, | 295 | static int wl1271_probe(struct sdio_func *func, |
218 | const struct sdio_device_id *id) | 296 | const struct sdio_device_id *id) |
219 | { | 297 | { |
@@ -245,12 +323,9 @@ static int wl1271_probe(struct sdio_func *func, | |||
245 | /* Use block mode for transferring over one block size of data */ | 323 | /* Use block mode for transferring over one block size of data */ |
246 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; | 324 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; |
247 | 325 | ||
248 | pdev_data.pdata = wl12xx_get_platform_data(); | 326 | pdev_data.pdata = wlcore_get_platform_data(&func->dev); |
249 | if (IS_ERR(pdev_data.pdata)) { | 327 | if (!pdev_data.pdata) |
250 | ret = PTR_ERR(pdev_data.pdata); | ||
251 | dev_err(glue->dev, "missing wlan platform data: %d\n", ret); | ||
252 | goto out_free_glue; | 328 | goto out_free_glue; |
253 | } | ||
254 | 329 | ||
255 | /* if sdio can keep power while host is suspended, enable wow */ | 330 | /* if sdio can keep power while host is suspended, enable wow */ |
256 | mmcflags = sdio_get_host_pm_caps(func); | 331 | mmcflags = sdio_get_host_pm_caps(func); |
@@ -279,7 +354,7 @@ static int wl1271_probe(struct sdio_func *func, | |||
279 | if (!glue->core) { | 354 | if (!glue->core) { |
280 | dev_err(glue->dev, "can't allocate platform_device"); | 355 | dev_err(glue->dev, "can't allocate platform_device"); |
281 | ret = -ENOMEM; | 356 | ret = -ENOMEM; |
282 | goto out_free_glue; | 357 | goto out_free_pdata; |
283 | } | 358 | } |
284 | 359 | ||
285 | glue->core->dev.parent = &func->dev; | 360 | glue->core->dev.parent = &func->dev; |
@@ -313,6 +388,9 @@ static int wl1271_probe(struct sdio_func *func, | |||
313 | out_dev_put: | 388 | out_dev_put: |
314 | platform_device_put(glue->core); | 389 | platform_device_put(glue->core); |
315 | 390 | ||
391 | out_free_pdata: | ||
392 | wlcore_del_platform_data(pdev_data.pdata); | ||
393 | |||
316 | out_free_glue: | 394 | out_free_glue: |
317 | kfree(glue); | 395 | kfree(glue); |
318 | 396 | ||
@@ -323,11 +401,14 @@ out: | |||
323 | static void wl1271_remove(struct sdio_func *func) | 401 | static void wl1271_remove(struct sdio_func *func) |
324 | { | 402 | { |
325 | struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); | 403 | struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); |
404 | struct wlcore_platdev_data *pdev_data = glue->core->dev.platform_data; | ||
405 | struct wl12xx_platform_data *pdata = pdev_data->pdata; | ||
326 | 406 | ||
327 | /* Undo decrement done above in wl1271_probe */ | 407 | /* Undo decrement done above in wl1271_probe */ |
328 | pm_runtime_get_noresume(&func->dev); | 408 | pm_runtime_get_noresume(&func->dev); |
329 | 409 | ||
330 | platform_device_unregister(glue->core); | 410 | platform_device_unregister(glue->core); |
411 | wlcore_del_platform_data(pdata); | ||
331 | kfree(glue); | 412 | kfree(glue); |
332 | } | 413 | } |
333 | 414 | ||