From patchwork Tue Aug 10 22:12:22 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ohad Ben Cohen X-Patchwork-Id: 118702 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o7AMJUwp008261 for ; Tue, 10 Aug 2010 22:20:02 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933437Ab0HJWTT (ORCPT ); Tue, 10 Aug 2010 18:19:19 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:37116 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932974Ab0HJWTH (ORCPT ); Tue, 10 Aug 2010 18:19:07 -0400 Received: by bwz3 with SMTP id 3so2243422bwz.19 for ; Tue, 10 Aug 2010 15:19:05 -0700 (PDT) Received: by 10.204.126.92 with SMTP id b28mr4511934bks.47.1281478413768; Tue, 10 Aug 2010 15:13:33 -0700 (PDT) Received: from localhost.localdomain (85-250-37-93.bb.netvision.net.il [85.250.37.93]) by mx.google.com with ESMTPS id f10sm4569096bkl.17.2010.08.10.15.13.30 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 10 Aug 2010 15:13:32 -0700 (PDT) From: Ohad Ben-Cohen To: , , Cc: Mark Brown , , Chikkature Rajashekar Madhusudhan , Luciano Coelho , , San Mehat , Roger Quadros , Tony Lindgren , Nicolas Pitre , Pandita Vikram , Kalle Valo , Ohad Ben-Cohen Subject: [PATCH v3 3/9] wireless: wl1271: add platform driver to get board data Date: Wed, 11 Aug 2010 01:12:22 +0300 Message-Id: <1281478348-24833-4-git-send-email-ohad@wizery.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1281478348-24833-1-git-send-email-ohad@wizery.com> References: <1281478348-24833-1-git-send-email-ohad@wizery.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 10 Aug 2010 22:20:02 +0000 (UTC) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index faa5925..013eabb 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "wl1271_conf.h" #include "wl1271_ini.h" @@ -319,8 +320,19 @@ struct wl1271_if_operations { void (*disable_irq)(struct wl1271 *wl); }; +/* exact size needed for "wl1271_plat.x" */ +#define WL12XX_PLAT_NAME_LEN 14 + +struct wl12xx_plat_instance { + struct platform_driver pdriver; + char name[WL12XX_PLAT_NAME_LEN]; + struct wl12xx_platform_data *pdata; + struct completion data_ready; +}; + struct wl1271 { struct platform_device *plat_dev; + struct wl12xx_plat_instance *pinstance; struct ieee80211_hw *hw; bool mac80211_registered; diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index c41293a..5b43626 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -28,7 +28,11 @@ #include #include #include +#include +#include #include +#include +#include #include "wl1271.h" #include "wl12xx_80211.h" @@ -182,10 +186,84 @@ static struct wl1271_if_operations sdio_ops = { .disable_irq = wl1271_sdio_disable_interrupts }; +static int wl1271_plat_probe(struct platform_device *pdev) +{ + struct wl12xx_platform_data *pdata; + struct platform_driver *pdriver; + struct wl12xx_plat_instance *pinstance; + + pdata = pdev->dev.platform_data; + if (!pdata) { + wl1271_error("no platform data"); + return -ENODEV; + } + + pdriver = container_of(pdev->dev.driver, struct platform_driver, + driver); + pinstance = container_of(pdriver, struct wl12xx_plat_instance, pdriver); + + pinstance->pdata = pdata; + + complete(&pinstance->data_ready); + + return 0; +} + +static struct wl12xx_platform_data *wl1271_get_data(struct wl1271 *wl, int id) +{ + int ret; + struct wl12xx_plat_instance *pinstance; + + #define WL1271_PLAT_NAME "wl1271_plat.%d" + + pinstance = kzalloc(sizeof(*pinstance), GFP_KERNEL); + if (!pinstance) + return ERR_PTR(-ENOMEM); + + init_completion(&pinstance->data_ready); + + pinstance->pdriver.probe = wl1271_plat_probe; + + ret = snprintf(pinstance->name, ARRAY_SIZE(pinstance->name), + WL1271_PLAT_NAME, id); + if (ret >= WL12XX_PLAT_NAME_LEN) { + wl1271_error("truncated plat drv name\n"); + goto out_free; + } + + pinstance->pdriver.driver.name = pinstance->name; + pinstance->pdriver.driver.owner = THIS_MODULE; + + ret = platform_driver_register(&pinstance->pdriver); + if (ret < 0) { + wl1271_error("failed to register plat driver: %d", ret); + goto out_free; + } + + ret = wait_for_completion_interruptible_timeout(&pinstance->data_ready, + msecs_to_jiffies(15000)); + if (ret <= 0) { + wl1271_error("can't get platform device (%d)", ret); + ret = (ret == 0 ? -EAGAIN : ret); + goto unreg; + } + + wl->pinstance = pinstance; + + return pinstance->pdata; + +unreg: + platform_driver_unregister(&pinstance->pdriver); +out_free: + kfree(pinstance); + return ERR_PTR(ret); +} + static int __devinit wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct ieee80211_hw *hw; + struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; int ret; @@ -205,17 +283,24 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + wlan_data = wl1271_get_data(wl, func->card->host->index); + if (IS_ERR(wlan_data)) { + ret = PTR_ERR(wlan_data); + wl1271_error("missing wlan data (needed for irq/ref_clk)!"); + goto out_free; + } + wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO); if (wl->irq < 0) { ret = wl->irq; wl1271_error("could not get irq!"); - goto out_free; + goto put_data; } ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); - goto out_free; + goto put_data; } set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); @@ -236,13 +321,13 @@ static int __devinit wl1271_probe(struct sdio_func *func, return 0; - out_irq: +out_irq: free_irq(wl->irq, wl); - - - out_free: +put_data: + platform_driver_unregister(&wl->pinstance->pdriver); + kfree(wl->pinstance); +out_free: wl1271_free_hw(wl); - return ret; } @@ -253,6 +338,10 @@ static void __devexit wl1271_remove(struct sdio_func *func) free_irq(wl->irq, wl); wl1271_unregister_hw(wl); + + platform_driver_unregister(&wl->pinstance->pdriver); + kfree(wl->pinstance); + wl1271_free_hw(wl); }