diff options
author | Yin, Fengwei <fengwei.yin@linaro.org> | 2015-07-28 15:21:54 +0800 |
---|---|---|
committer | Yin, Fengwei <fengwei.yin@linaro.org> | 2015-07-28 15:22:42 +0800 |
commit | c66734552d2c5c61bf282f6653a66224289ebc90 (patch) | |
tree | 4ae5794417020b45b4f37675979117662f4baf89 /drivers | |
parent | ae26616db10ee71757263fc7d068823d21c23689 (diff) |
Migrate the wifi driver from old smd driver to new smd driver.
Signed-off-by: Yin, Fengwei <fengwei.yin@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c | 119 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcnss_core.c | 227 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcnss_core.h | 9 |
4 files changed, 163 insertions, 194 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 332c303f81b1..3da80a3a4f9d 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -954,7 +954,7 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) /* 3620 powersaving currently unstable */ if (wcn->chip_version == WCN36XX_CHIP_3620) - wcn->hw->flags &= ~IEEE80211_HW_SUPPORTS_PS; + __clear_bit(IEEE80211_HW_SUPPORTS_PS, wcn->hw->flags); wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c index db2393a459e6..edefa2283dc2 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c @@ -20,22 +20,18 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> -#include <linux/regulator/rpm-smd-regulator.h> #include <linux/workqueue.h> #include <linux/of.h> #include <linux/clk.h> -#include <soc/qcom/smd.h> -#include <soc/qcom/smsm.h> +#include <linux/soc/qcom/smd.h> #include "wcn36xx.h" #include "wcnss_core.h" -#include <soc/qcom/subsystem_restart.h> -#include <soc/qcom/subsystem_notif.h> - #define MAC_ADDR_0 "wlan/macaddr0" static void *pil; +#if 0 struct wcn36xx_msm { struct wcn36xx_platform_ctrl_ops ctrl_ops; struct platform_device *core; @@ -225,13 +221,6 @@ int wcn36xx_msm_powerup(const struct subsys_desc *desc) return 0; } -static const struct of_device_id wcn36xx_msm_match_table[] = { - { .compatible = "qcom,wcn3660", .data = (void *)WCN36XX_CHIP_3660 }, - { .compatible = "qcom,wcn3680", .data = (void *)WCN36XX_CHIP_3680 }, - { .compatible = "qcom,wcn3620", .data = (void *)WCN36XX_CHIP_3620 }, - { } -}; - static int wcn36xx_msm_get_chip_type(void) { return wmsm.chip_type; @@ -248,6 +237,61 @@ static struct wcn36xx_msm wmsm = { }, }; +static int wcn36xx_wlan_ctrl_probe(struct platform_device *pdev) +{ + wmsm.core = platform_device_alloc("wcn36xx", -1); + + for (n = 0; n < ARRAY_SIZE(rnames); n++) { + r = platform_get_resource_byname(pdev, rtype[n], rnames[n]); + if (!r) { + dev_err(&wmsm.core->dev, + "Missing resource %s'\n", rnames[n]); + ret = -ENOMEM; + return ret; + } + res[n] = *r; + } + + platform_device_add_resources(wmsm.core, res, n); + + ret = platform_device_add_data(wmsm.core, &wmsm.ctrl_ops, + sizeof(wmsm.ctrl_ops)); + if (ret) { + dev_err(&wmsm.core->dev, "Can't add platform data\n"); + ret = -ENOMEM; + return ret; + } + + platform_device_add(wmsm.core); +} + +static int wcn36xx_wlan_ctrl_remove(struct platform_device *pdev) +{ + platform_device_del(wmsm.core); + platform_device_put(wmsm.core); +} +#endif + +struct wcn36xx_platform_data { + enum wcn36xx_chip_type chip_type; + + struct qcom_smd_channel *wlan_ctrl_channel; + struct completion wlan_ctrl_ack; + struct mutex wlan_ctrl_lock; + + struct pinctrl *pinctrl; +}; + +static struct wcn36xx_platform_data wcn36xx_data; + +static const struct of_device_id wcn36xx_msm_match_table[] = { + { .compatible = "qcom,wcn3660", .data = (void *)WCN36XX_CHIP_3660 }, + { .compatible = "qcom,wcn3680", .data = (void *)WCN36XX_CHIP_3680 }, + { .compatible = "qcom,wcn3620", .data = (void *)WCN36XX_CHIP_3620 }, + { } +}; +MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table); + static int wcn36xx_msm_probe(struct platform_device *pdev) { int ret; @@ -265,17 +309,17 @@ static int wcn36xx_msm_probe(struct platform_device *pdev) if (!of_id) return -EINVAL; - wmsm.chip_type = (enum wcn36xx_chip_type)of_id->data; + wcn36xx_data.chip_type = (enum wcn36xx_chip_type)of_id->data; - wmsm.pinctrl = devm_pinctrl_get(&pdev->dev); - if (IS_ERR_OR_NULL(wmsm.pinctrl)) - return PTR_ERR(wmsm.pinctrl); + wcn36xx_data.pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(wcn36xx_data.pinctrl)) + return PTR_ERR(wcn36xx_data.pinctrl); - ps = pinctrl_lookup_state(wmsm.pinctrl, "wcnss_default"); + ps = pinctrl_lookup_state(wcn36xx_data.pinctrl, "wcnss_default"); if (IS_ERR_OR_NULL(ps)) return PTR_ERR(ps); - ret = pinctrl_select_state(wmsm.pinctrl, ps); + ret = pinctrl_select_state(wcn36xx_data.pinctrl, ps); if (ret) return ret; @@ -286,32 +330,6 @@ static int wcn36xx_msm_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(pil)) return PTR_ERR(pil); - wmsm.core = platform_device_alloc("wcn36xx", -1); - - for (n = 0; n < ARRAY_SIZE(rnames); n++) { - r = platform_get_resource_byname(pdev, rtype[n], rnames[n]); - if (!r) { - dev_err(&wmsm.core->dev, - "Missing resource %s'\n", rnames[n]); - ret = -ENOMEM; - return ret; - } - res[n] = *r; - } - - platform_device_add_resources(wmsm.core, res, n); - - ret = platform_device_add_data(wmsm.core, &wmsm.ctrl_ops, - sizeof(wmsm.ctrl_ops)); - if (ret) { - dev_err(&wmsm.core->dev, "Can't add platform data\n"); - ret = -ENOMEM; - return ret; - } - - platform_device_add(wmsm.core); - wcnss_core_init(); - dev_info(&pdev->dev, "%s initialized\n", __func__); return 0; @@ -321,22 +339,17 @@ static int wcn36xx_msm_remove(struct platform_device *pdev) { struct pinctrl_state *ps; - wcnss_core_deinit(); - platform_device_del(wmsm.core); - platform_device_put(wmsm.core); - - if (wmsm.pinctrl) { - ps = pinctrl_lookup_state(wmsm.pinctrl, "wcnss_sleep"); + if (wcn36xx_data.pinctrl) { + ps = pinctrl_lookup_state(wcn36xx_data.pinctrl, "wcnss_sleep"); if (IS_ERR_OR_NULL(ps)) return PTR_ERR(ps); - pinctrl_select_state(wmsm.pinctrl, ps); + pinctrl_select_state(wcn36xx_data.pinctrl, ps); } return 0; } -MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table); static struct platform_driver wcn36xx_msm_driver = { .probe = wcn36xx_msm_probe, diff --git a/drivers/net/wireless/ath/wcn36xx/wcnss_core.c b/drivers/net/wireless/ath/wcn36xx/wcnss_core.c index 9d94d76ed05c..67a9a70841ec 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcnss_core.c +++ b/drivers/net/wireless/ath/wcn36xx/wcnss_core.c @@ -20,6 +20,8 @@ #define WCNSS_INVALID_IRIS_REG 0xbaadbaad +#define WCNSS_CTRL_TIMEOUT (msecs_to_jiffies(500)) + struct vregs_info { const char * const name; int state; @@ -254,111 +256,27 @@ int wcnss_core_prepare(struct platform_device *pdev) return ret; } -static struct wcn36xx_ctrl_nv_data ctrl_nv_data; -static void wcn36xx_download_notify(void *data, unsigned int event) -{ - struct wcn36xx_ctrl_nv_data *ctrl_nv_data = data; - - switch (event) { - case SMD_EVENT_OPEN: - complete(&ctrl_nv_data->smd_open_compl); - schedule_work(&ctrl_nv_data->download_work); - break; - case SMD_EVENT_DATA: - schedule_work(&ctrl_nv_data->rx_work); - break; - case SMD_EVENT_CLOSE: - case SMD_EVENT_STATUS: - case SMD_EVENT_REOPEN_READY: - break; - default: - pr_err("%s: SMD_EVENT (%d) not supported\n", - __func__, event); - break; - } -} +struct wcnss_platform_data { + struct qcom_smd_channel *channel; + struct completion ack; + struct mutex lock; -static unsigned char wcnss_fw_status(struct wcn36xx_ctrl_nv_data *data) -{ - int len = 0; - int rc = 0; + struct work_struct rx_work; + struct work_struct download_work; - unsigned char fw_status = 0xFF; - - len = smd_read_avail(data->smd_ch); - if (len < 1) { - pr_err("%s: invalid firmware status", __func__); - return fw_status; - } - - rc = smd_read(data->smd_ch, &fw_status, 1); - if (rc < 0) { - pr_err("%s: incomplete data read from smd\n", __func__); - return fw_status; - } - return fw_status; -} - -static void wcn36xx_nv_rx_work(struct work_struct *worker) -{ - struct wcn36xx_ctrl_nv_data *data = - container_of(worker, struct wcn36xx_ctrl_nv_data, rx_work); - int len = 0, ret = 0; - unsigned char buf[sizeof(struct wcnss_version)]; - struct smd_msg_hdr *phdr; - - len = smd_read_avail(data->smd_ch); - if (len > 4096) { - pr_err("%s: frame larger than allowed size\n", __func__); - smd_read(data->smd_ch, NULL, len); - return; - } - - if (len < sizeof(struct smd_msg_hdr)) - return; - - ret = smd_read(data->smd_ch, buf, sizeof(struct smd_msg_hdr)); - if (ret < sizeof(struct smd_msg_hdr)) { - pr_err("%s: incomplete header from smd\n", __func__); - return; - } - - phdr = (struct smd_msg_hdr *)buf; - - switch (phdr->msg_type) { - case WCNSS_NV_DOWNLOAD_RSP: - pr_info("fw_status: %d\n", wcnss_fw_status(data)); - break; - } - return; -} - -static int wcn36xx_nv_smd_tx(struct wcn36xx_ctrl_nv_data *nv_data, void *buf, int len) -{ - int ret = 0; - - ret = smd_write_avail(nv_data->smd_ch); - if (ret < len) { - pr_err("wcnss: no space available. %d needed. Just %d avail\n", - len, ret); - return -ENOSPC; - } - ret = smd_write(nv_data->smd_ch, buf, len); - if (ret < len) { - pr_err("wcnss: failed to write Command %d", len); - ret = -ENODEV; - } - return ret; + struct qcom_smd_device *sdev; } +static completion fw_ready_compl; #define NV_FILE_NAME "wlan/prima/WCNSS_qcom_wlan_nv.bin" static void wcn36xx_nv_download_work(struct work_struct *worker) { int ret = 0, i, retry = 3; const struct firmware *nv = NULL; - struct wcn36xx_ctrl_nv_data *data = - container_of(worker, struct wcn36xx_ctrl_nv_data, download_work); - struct device *dev = &data->pdev->dev; + struct wcnss_platform_data *wcnss_data = + container_of(worker, struct wcnss_platform_data, download_work); + struct device *dev = &wcnss_data->sdev->dev; + struct nvbin_dnld_req_msg *msg; const void *nv_blob_start; char *pkt = NULL; @@ -409,18 +327,18 @@ static void wcn36xx_nv_download_work(struct work_struct *worker) memcpy(pkt + sizeof(struct nvbin_dnld_req_msg), nv_blob_start + i * NV_FRAGMENT_SIZE, pkt_len); - ret = wcn36xx_nv_smd_tx(data, pkt, msg->hdr.msg_len); - - while ((ret == -ENOSPC) && (retry++ <= 3)) { - dev_err(dev, "smd_tx failed, %d times retry\n", retry); - msleep(100); - ret = wcn36xx_nv_smd_tx(data, pkt, msg->hdr.msg_len); + ret = qcom_smd_send(wcnss_data->channel, pkt, msg->hdr.msg_len); + if (ret) { + dev_err(dev, "nv download failed\n"); + goto out; } - if (ret < 0) { - dev_err(dev, "nv download failed\n"); + ret = wait_for_completion_timeout(&rpm->ack, WCNSS_CTRL_TIMEOUT); + if (!ret) { + ret = -ETIMEDOUT; goto out; } + i++; nv_blob_size -= NV_FRAGMENT_SIZE; msleep(100); @@ -432,49 +350,96 @@ out: return; } -static int wcnss_ctrl_remove(struct platform_device *pdev) +static int qcom_smd_wcnss_ctrl_callback(struct qcom_smd_device *qsdev, + const void *data, + size_t count) { - smd_close(ctrl_nv_data.smd_ch); + struct wcnss_platform_data *wcnss_data = dev_get_drvdata(&qsdev->dev); + struct smd_msg_hdr *phdr = (struct smd_msg_hdr *)data; + unsigned char *tmp = data; - return 0; + switch (phdr->msg_type) { + /* CBC COMPLETE means firmware ready for go */ + case WCNSS_CBC_COMPLETE_IND: + complete(&fw_ready_compl); + pr_info("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n"); + break; + + case WCNSS_NV_DOWNLOAD_RSP: + pr_info("fw_status: %d\n", tmp[sizeof(*phdr)]); + break; + } + + complete(&wcnss_data->ack); + return; } -static int wcnss_ctrl_probe(struct platform_device *pdev) +static int qcom_smd_wcnss_ctrl_probe(struct qcom_smd_device *sdev) { - int ret = 0; + struct wcnss_platform_data *wcnss_data; - INIT_WORK(&ctrl_nv_data.rx_work, wcn36xx_nv_rx_work); - INIT_WORK(&ctrl_nv_data.download_work, wcn36xx_nv_download_work); - init_completion(&ctrl_nv_data.smd_open_compl); - ctrl_nv_data.pdev = pdev; + wcnss_data = devm_kzalloc(&sdev->dev, sizeof(*wcnss_data), GFP_KERNEL); + if (!wcnss_data) + return -ENOMEM; - ret = smd_named_open_on_edge("WCNSS_CTRL", SMD_APPS_WCNSS, - &ctrl_nv_data.smd_ch, &ctrl_nv_data, wcn36xx_download_notify); - if (ret) { - dev_err(&pdev->dev, "wcnss_ctrl open failed\n"); - return ret; - } - smd_disable_read_intr(ctrl_nv_data.smd_ch); - return ret; + mutex_init(&wcnss_data->lock); + init_completion(&wcnss_data->ack); + + wcnss_data->channel = sdev->channel; + wcnss_data->pdev = sdev; + + dev_set_drvdata(&sdev->dev, wcnss_data); + + INIT_WORK(&wcnss_data->rx_work, wcn36xx_nv_rx_work); + INIT_WORK(&wcnss_data->download_work, wcn36xx_nv_download_work); + + of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev); + + /* We are ready for download here */ + schedule_work(&wcnss_data->download_work); + return 0; +} + +static void qcom_smd_wcnss_ctrl_remove(struct qcom_smd_device *sdev) +{ + of_platform_depopulate(&sdev->dev); } -/* platform device for WCNSS_CTRL SMD channel */ -static struct platform_driver wcnss_ctrl_driver = { - .driver = { - .name = "WCNSS_CTRL", - .owner = THIS_MODULE, +static const struct of_device_id qcom_smd_wcnss_ctrl_of_match[] = { + { .compatible = "qcom,wcnss-ctrl" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); + +static struct qcom_smd_driver qcom_smd_wcnss_ctrl_driver = { + .probe = qcom_smd_wcnss_ctrl_probe, + .remove = qcom_smd_wcnss_ctrl_remove, + .callback = qcom_smd_wcnss_ctrl_callback, + .driver = { + .name = "qcom_smd_rpm", + .owner = THIS_MODULE, + .of_match_table = qcom_smd_wcnss_ctrl_of_match, }, - .probe = wcnss_ctrl_probe, - .remove = wcnss_ctrl_remove, }; void wcnss_core_init(void) { - platform_driver_register(&wcnss_ctrl_driver); + int ret = 0; + + init_completion(&fw_ready_compl); + qcom_smd_driver_register(&qcom_smd_wcnss_ctrl_driver); + + ret = wait_for_completion_interruptible_timeout( + &fw_ready_compl, msecs_to_jiffies(FW_READY_TIMEOUT)); + if (ret <= 0) { + pr_err("timeout waiting for wcnss firmware ready indicator\n"); + return -EAGAIN; + } + + return 0; } void wcnss_core_deinit(void) { - platform_driver_unregister(&wcnss_ctrl_driver); + qcom_smd_driver_unregister(&qcom_smd_wcnss_ctrl_driver); } - diff --git a/drivers/net/wireless/ath/wcn36xx/wcnss_core.h b/drivers/net/wireless/ath/wcn36xx/wcnss_core.h index 50f564079f01..45877ab4f876 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcnss_core.h +++ b/drivers/net/wireless/ath/wcn36xx/wcnss_core.h @@ -34,15 +34,6 @@ #define WCNSS_NV_DOWNLOAD_REQ 0x01000002 #define WCNSS_NV_DOWNLOAD_RSP 0x01000003 -struct wcn36xx_ctrl_nv_data { - struct workqueue_struct *wq; - struct work_struct rx_work; - struct work_struct download_work; - struct completion smd_open_compl; - smd_channel_t *smd_ch; - struct platform_device *pdev; -}; - struct smd_msg_hdr { unsigned int msg_type; unsigned int msg_len; |