]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Migrate the wifi driver from old smd driver to new smd driver.
authorYin, Fengwei <fengwei.yin@linaro.org>
Tue, 28 Jul 2015 07:21:54 +0000 (15:21 +0800)
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Mon, 11 Jan 2016 09:55:25 +0000 (09:55 +0000)
Signed-off-by: Yin, Fengwei <fengwei.yin@linaro.org>
Conflicts:
arch/arm64/boot/dts/qcom/msm8916.dtsi

drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
drivers/net/wireless/ath/wcn36xx/wcn36xx.h
drivers/net/wireless/ath/wcn36xx/wcnss_core.c
drivers/net/wireless/ath/wcn36xx/wcnss_core.h

index 478edd9290c51f75c361cb53616752a65ea4a3dd..4bdd0da0793cb4e9bb203248a3f552caf70378ed 100644 (file)
@@ -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) |
@@ -1047,17 +1047,19 @@ static int wcn36xx_probe(struct platform_device *pdev)
                goto dma_mask_err;
        }
        dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
-       wcn->ctrl_ops = pdev->dev.platform_data;
+       wcn->wcn36xx_data = pdev->dev.platform_data;
+       wcn->ctrl_ops = &wcn->wcn36xx_data->ctrl_ops;
+       wcn->wcn36xx_data->wcn = wcn;
        if (!wcn->ctrl_ops->get_chip_type) {
                dev_err(&pdev->dev, "Missing ops->get_chip_type\n");
                ret = -EINVAL;
                goto out_wq;
        }
-       wcn->chip_version = wcn->ctrl_ops->get_chip_type();
+       wcn->chip_version = wcn->ctrl_ops->get_chip_type(wcn);
 
        mutex_init(&wcn->hal_mutex);
 
-       if (!wcn->ctrl_ops->get_hw_mac(addr)) {
+       if (!wcn->ctrl_ops->get_hw_mac(wcn, addr)) {
                wcn36xx_info("mac address: %pM\n", addr);
                SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
        }
index 0e22bae2ddf6e30cd248c790ed832a632cd42425..1bef8ce88d2e8aa1f11dec26c5c322c2ecd22378 100644 (file)
@@ -253,7 +253,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
 
        init_completion(&wcn->hal_rsp_compl);
        start = jiffies;
-       ret = wcn->ctrl_ops->tx(wcn->hal_buf, len);
+       ret = wcn->ctrl_ops->tx(wcn, wcn->hal_buf, len);
        if (ret) {
                wcn36xx_err("HAL TX failed\n");
                goto out;
@@ -2251,7 +2251,7 @@ out:
 
 void wcn36xx_smd_close(struct wcn36xx *wcn)
 {
-       wcn->ctrl_ops->close();
+       wcn->ctrl_ops->close(wcn);
        destroy_workqueue(wcn->hal_ind_wq);
        mutex_destroy(&wcn->hal_ind_mutex);
 }
index db2393a459e6162daebed807473991a5e097264b..647cf026d37c54c0e3cc7ac13a313ab21f2d9c1e 100644 (file)
 #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/of_platform.h>
 #include <linux/clk.h>
-#include <soc/qcom/smd.h>
-#include <soc/qcom/smsm.h>
+#include <linux/remoteproc.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;
-
-struct wcn36xx_msm {
-       struct wcn36xx_platform_ctrl_ops ctrl_ops;
-       struct platform_device *core;
-       void *drv_priv;
-       void (*rsp_cb)(void *drv_priv, void *buf, size_t len);
-       /* SMD related */
-       struct workqueue_struct *wq;
-       struct work_struct      smd_work;
-       struct completion       smd_compl;
-       smd_channel_t           *smd_ch;
-       struct pinctrl *pinctrl;
-       enum wcn36xx_chip_type chip_type;
-};
-
-static struct wcn36xx_msm wmsm;
-
 static int wcn36xx_msm_smsm_change_state(u32 clear_mask, u32 set_mask)
 {
-        return smsm_change_state(SMSM_APPS_STATE, clear_mask, set_mask);
+       return 0;
 }
 
-static int wcn36xx_msm_get_hw_mac(u8 *addr)
+static int wcn36xx_msm_get_hw_mac(struct wcn36xx *wcn, u8 *addr)
 {
        const struct firmware *addr_file = NULL;
        int status;
        u8 tmp[18];
        static const u8 qcom_oui[3] = {0x00, 0x0A, 0xF5};
        static const char *files = {MAC_ADDR_0};
+       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
 
-       status = request_firmware(&addr_file, files, &wmsm.core->dev);
+       status = request_firmware(&addr_file, files, &pdata->core->dev);
 
        if (status < 0) {
                /* Assign a random mac with Qualcomm oui */
-               dev_err(&wmsm.core->dev, "Failed (%d) to read macaddress file %s, using a random address instead", status,
-                            files);
+               dev_err(&pdata->core->dev, "Failed (%d) to read macaddress"
+                       "file %s, using a random address instead", status, files);
                memcpy(addr, qcom_oui, 3);
                get_random_bytes(addr + 3, 3);
        } else {
@@ -90,163 +70,114 @@ static int wcn36xx_msm_get_hw_mac(u8 *addr)
        return 0;
 }
 
-static int wcn36xx_msm_smd_send_and_wait(char *buf, size_t len)
+static int wcn36xx_msm_smd_send_and_wait(struct wcn36xx *wcn, char *buf, size_t len)
 {
-       int avail;
        int ret = 0;
+       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
 
-       avail = smd_write_avail(wmsm.smd_ch);
-
-       if (avail >= len) {
-               avail = smd_write(wmsm.smd_ch, buf, len);
-               if (avail != len) {
-                       dev_err(&wmsm.core->dev,
-                               "Cannot write to SMD channel\n");
-                       ret = -EAGAIN;
-                       goto out;
-               }
-       } else {
-               dev_err(&wmsm.core->dev,
-                       "SMD channel can accept only %d bytes\n", avail);
-               ret = -ENOMEM;
-               goto out;
+       mutex_lock(&pdata->wlan_ctrl_lock);
+       ret = qcom_smd_send(pdata->wlan_ctrl_channel, buf, len);
+       if (ret) {
+               dev_err(wcn->dev, "wlan ctrl channel tx failed\n");
        }
+       mutex_unlock(&pdata->wlan_ctrl_lock);
 
-out:
        return ret;
 }
 
-static void wcn36xx_msm_smd_notify(void *data, unsigned event)
+static int wcn36xx_msm_smd_open(struct wcn36xx *wcn, void *rsp_cb)
 {
-       struct wcn36xx_msm *wmsm_priv = (struct wcn36xx_msm *)data;
-
-       switch (event) {
-       case SMD_EVENT_OPEN:
-               complete(&wmsm_priv->smd_compl);
-               break;
-       case SMD_EVENT_DATA:
-               queue_work(wmsm_priv->wq, &wmsm_priv->smd_work);
-               break;
-       case SMD_EVENT_CLOSE:
-               break;
-       case SMD_EVENT_STATUS:
-               break;
-       case SMD_EVENT_REOPEN_READY:
-               break;
-       default:
-               dev_err(&wmsm_priv->core->dev,
-                       "%s: SMD_EVENT (%d) not supported\n", __func__, event);
-               break;
-       }
+       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
+
+       pdata->cb = rsp_cb;
+       return 0;
 }
 
-static void wcn36xx_msm_smd_work(struct work_struct *work)
+static void wcn36xx_msm_smd_close(struct wcn36xx *wcn)
 {
-       int avail;
-       int msg_len;
-       void *msg;
-       int ret;
-       struct wcn36xx_msm *wmsm_priv =
-               container_of(work, struct wcn36xx_msm, smd_work);
-
-       while (1) {
-               msg_len = smd_cur_packet_size(wmsm_priv->smd_ch);
-               if (0 == msg_len) {
-                       return;
-               }
-               avail = smd_read_avail(wmsm_priv->smd_ch);
-               if (avail < msg_len) {
-                       return;
-               }
-               msg = kmalloc(msg_len, GFP_KERNEL);
-               if (NULL == msg) {
-                       return;
-               }
+       return;
+}
 
-               ret = smd_read(wmsm_priv->smd_ch, msg, msg_len);
-               if (ret != msg_len) {
-                       return;
-               }
-               wmsm_priv->rsp_cb(wmsm_priv->drv_priv, msg, msg_len);
-               kfree(msg);
-       }
+static int wcn36xx_msm_get_chip_type(struct wcn36xx *wcn)
+{
+       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
+       return pdata->chip_type;
 }
 
-int wcn36xx_msm_smd_open(void *drv_priv, void *rsp_cb)
+static struct wcn36xx_platform_data wcn36xx_data = {
+       .ctrl_ops = {
+               .open = wcn36xx_msm_smd_open,
+               .close = wcn36xx_msm_smd_close,
+               .tx = wcn36xx_msm_smd_send_and_wait,
+               .get_hw_mac = wcn36xx_msm_get_hw_mac,
+               .smsm_change_state = wcn36xx_msm_smsm_change_state,
+               .get_chip_type = wcn36xx_msm_get_chip_type,
+       },
+};
+
+static int qcom_smd_wlan_ctrl_probe(struct qcom_smd_device *sdev)
 {
-       int ret, left;
-       wmsm.drv_priv = drv_priv;
-       wmsm.rsp_cb = rsp_cb;
-       INIT_WORK(&wmsm.smd_work, wcn36xx_msm_smd_work);
-       init_completion(&wmsm.smd_compl);
-
-       wmsm.wq = create_workqueue("wcn36xx_msm_smd_wq");
-       if (!wmsm.wq) {
-               dev_err(&wmsm.core->dev, "failed to allocate wq");
-               ret = -ENOMEM;
-               return ret;
-       }
+       pr_info("%s: enter\n", __func__);
+        mutex_init(&wcn36xx_data.wlan_ctrl_lock);
+        init_completion(&wcn36xx_data.wlan_ctrl_ack);
 
-       ret = smd_named_open_on_edge("WLAN_CTRL", SMD_APPS_WCNSS,
-               &wmsm.smd_ch, &wmsm, wcn36xx_msm_smd_notify);
-       if (ret) {
-               dev_err(&wmsm.core->dev,
-                       "smd_named_open_on_edge failed: %d\n", ret);
-               return ret;
-       }
+       wcn36xx_data.sdev = sdev;
 
-       left = wait_for_completion_interruptible_timeout(&wmsm.smd_compl,
-               msecs_to_jiffies(HAL_MSG_TIMEOUT));
-       if (left <= 0) {
-               dev_err(&wmsm.core->dev,
-                       "timeout waiting for smd open: %d\n", ret);
-               return left;
-       }
+        dev_set_drvdata(&sdev->dev, &wcn36xx_data);
+       wcn36xx_data.wlan_ctrl_channel = sdev->channel;
 
-       /* Not to receive INT until the whole buf from SMD is read */
-       smd_disable_read_intr(wmsm.smd_ch);
+       of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
 
-       return 0;
+        return 0;
 }
 
-void wcn36xx_msm_smd_close(void)
+static void qcom_smd_wlan_ctrl_remove(struct qcom_smd_device *sdev)
 {
-       smd_close(wmsm.smd_ch);
-       flush_workqueue(wmsm.wq);
-       destroy_workqueue(wmsm.wq);
+        of_platform_depopulate(&sdev->dev);
 }
 
-int wcn36xx_msm_shutdown(const struct subsys_desc *desc, bool force_stop)
-{
-       return 0;
-}
-int wcn36xx_msm_powerup(const struct subsys_desc *desc)
+static int qcom_smd_wlan_ctrl_callback(struct qcom_smd_device *qsdev,
+                                 const void *data,
+                                 size_t count)
 {
+       struct wcn36xx_platform_data *pdata = dev_get_drvdata(&qsdev->dev);
+       void *buf = kzalloc(count, GFP_ATOMIC);
+       if (!buf) {
+               dev_err(&pdata->core->dev, "can't allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       memcpy_fromio(buf, data, count);
+       pdata->cb(pdata->wcn, buf, count);
+       kfree(buf);
+
        return 0;
 }
 
+static const struct of_device_id qcom_smd_wlan_ctrl_of_match[] = {
+       { .compatible = "qcom,wlan-ctrl" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qcom_smd_wlan_ctrl_of_match);
+
+static struct qcom_smd_driver qcom_smd_wlan_ctrl_driver = {
+       .probe = qcom_smd_wlan_ctrl_probe,
+       .remove = qcom_smd_wlan_ctrl_remove,
+       .callback = qcom_smd_wlan_ctrl_callback,
+       .driver  = {
+               .name  = "qcom_smd_wlan_ctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = qcom_smd_wlan_ctrl_of_match,
+       },
+};
+
 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;
-}
-
-static struct wcn36xx_msm wmsm = {
-       .ctrl_ops = {
-               .open = wcn36xx_msm_smd_open,
-               .close = wcn36xx_msm_smd_close,
-               .tx = wcn36xx_msm_smd_send_and_wait,
-               .get_hw_mac = wcn36xx_msm_get_hw_mac,
-               .smsm_change_state = wcn36xx_msm_smsm_change_state,
-               .get_chip_type = wcn36xx_msm_get_chip_type,
-       },
-};
+MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table);
 
 static int wcn36xx_msm_probe(struct platform_device *pdev)
 {
@@ -254,44 +185,42 @@ static int wcn36xx_msm_probe(struct platform_device *pdev)
        const struct of_device_id *of_id;
        struct resource *r;
        struct resource res[3];
-       struct pinctrl_state *ps;
        static const char const *rnames[] = {
                "wcnss_mmio", "wcnss_wlantx_irq", "wcnss_wlanrx_irq" };
        static const int rtype[] = {
                IORESOURCE_MEM, IORESOURCE_IRQ, IORESOURCE_IRQ };
+       struct device_node *dn;
        int n;
 
-       of_id = of_match_node(wcn36xx_msm_match_table, pdev->dev.of_node);
-       if (!of_id)
-               return -EINVAL;
-
-       wmsm.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);
+       wcnss_core_prepare(pdev);
 
-       ps = pinctrl_lookup_state(wmsm.pinctrl, "wcnss_default");
-       if (IS_ERR_OR_NULL(ps))
-                       return PTR_ERR(ps);
+       dn = of_parse_phandle(pdev->dev.of_node, "rproc", 0);
+       if (!dn) {
+               dev_err(&pdev->dev, "No rproc specified in DT\n");
+       } else {
+               struct rproc *rproc= rproc_get_by_phandle(dn->phandle);
+               if (rproc)
+                       rproc_boot(rproc);
+               else {
+                       dev_err(&pdev->dev, "No rproc registered\n");
+               }
+       }
 
-       ret = pinctrl_select_state(wmsm.pinctrl, ps);
-       if (ret)
-               return ret;
+       qcom_smd_driver_register(&qcom_smd_wlan_ctrl_driver);
+       wcnss_core_init();
 
-       wcnss_core_prepare(pdev);
+       of_id = of_match_node(wcn36xx_msm_match_table, pdev->dev.of_node);
+       if (!of_id)
+               return -EINVAL;
 
-       if (IS_ERR_OR_NULL(pil))
-               pil = subsystem_get("wcnss");
-       if (IS_ERR_OR_NULL(pil))
-               return PTR_ERR(pil);
+       wcn36xx_data.chip_type = (enum wcn36xx_chip_type)of_id->data;
 
-       wmsm.core = platform_device_alloc("wcn36xx", -1);
+       wcn36xx_data.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,
+                       dev_err(&wcn36xx_data.core->dev,
                                "Missing resource %s'\n", rnames[n]);
                        ret = -ENOMEM;
                        return ret;
@@ -299,18 +228,10 @@ static int wcn36xx_msm_probe(struct platform_device *pdev)
                res[n] = *r;
        }
 
-       platform_device_add_resources(wmsm.core, res, n);
+       platform_device_add_resources(wcn36xx_data.core, res, n);
+       wcn36xx_data.core->dev.platform_data = &wcn36xx_data;
 
-       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();
+       platform_device_add(wcn36xx_data.core);
 
        dev_info(&pdev->dev, "%s initialized\n", __func__);
 
@@ -319,25 +240,11 @@ static int wcn36xx_msm_probe(struct platform_device *pdev)
 
 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 (IS_ERR_OR_NULL(ps))
-                       return PTR_ERR(ps);
-
-               pinctrl_select_state(wmsm.pinctrl, ps);
-       }
-
+       platform_device_del(wcn36xx_data.core);
+       platform_device_put(wcn36xx_data.core);
        return 0;
 }
 
-MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table);
-
 static struct platform_driver wcn36xx_msm_driver = {
        .probe          = wcn36xx_msm_probe,
        .remove         = wcn36xx_msm_remove,
@@ -357,8 +264,6 @@ module_init(wcn36xx_msm_init);
 static void __exit wcn36xx_msm_exit(void)
 {
        platform_driver_unregister(&wcn36xx_msm_driver);
-       if (pil)
-               subsystem_put(pil);
 }
 module_exit(wcn36xx_msm_exit);
 
index 9ca730c1df54f59b73c7770be859b565a55b3d37..d9f8b6450487dd173f906313907bcceb7612cf7b 100644 (file)
@@ -116,14 +116,32 @@ enum wcn36xx_chip_type {
  * @tx: sends a buffer.
  */
 struct wcn36xx_platform_ctrl_ops {
-       int (*open)(void *drv_priv, void *rsp_cb);
-       void (*close)(void);
-       int (*tx)(char *buf, size_t len);
-       int (*get_hw_mac)(u8 *addr);
-       int (*get_chip_type)(void);
+       int (*open)(struct wcn36xx *wcn, void *rsp_cb);
+       void (*close)(struct wcn36xx *wcn);
+       int (*tx)(struct wcn36xx *wcn, char *buf, size_t len);
+       int (*get_hw_mac)(struct wcn36xx *wcn, u8 *addr);
+       int (*get_chip_type)(struct wcn36xx *wcn);
        int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
 };
 
+struct wcn36xx_platform_data {
+       enum wcn36xx_chip_type chip_type;
+
+       struct platform_device *core;
+
+       struct qcom_smd_device *sdev;
+        struct qcom_smd_channel *wlan_ctrl_channel;
+        struct completion wlan_ctrl_ack;
+        struct mutex wlan_ctrl_lock;
+
+       struct pinctrl *pinctrl;
+
+       struct wcn36xx *wcn;
+
+       void (*cb)(struct wcn36xx *wcn, void *buf, size_t len);
+       struct wcn36xx_platform_ctrl_ops ctrl_ops;
+};
+
 /**
  * struct wcn36xx_vif - holds VIF related fields
  *
@@ -212,6 +230,7 @@ struct wcn36xx {
        int                     rx_irq;
        void __iomem            *mmio;
 
+       struct wcn36xx_platform_data *wcn36xx_data;
        struct wcn36xx_platform_ctrl_ops *ctrl_ops;
        /*
         * smd_buf must be protected with smd_mutex to garantee
index b3e4b826d887c6de13492c4b1412f2cb341fa47e..645968b39116ba7b796888d5a756e630868eeb3d 100644 (file)
@@ -3,19 +3,20 @@
 #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/of_platform.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"
 
+#define        WCNSS_CTRL_TIMEOUT      (msecs_to_jiffies(500))
+
 static int wcnss_core_config(struct platform_device *pdev, void __iomem *base)
 {
        int ret = 0;
-       u32 value, iris_read = INVALID_IRIS_REG;
+       u32 value, iris_read_v = INVALID_IRIS_REG;
        int clk_48m = 0;
 
        value = readl_relaxed(base + SPARE_OFFSET);
@@ -111,111 +112,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;
-       }
-}
-
-static unsigned char wcnss_fw_status(struct wcn36xx_ctrl_nv_data *data)
-{
-       int len = 0;
-       int rc = 0;
-
-       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;
+struct wcnss_platform_data {
+        struct qcom_smd_channel        *channel;
+        struct completion      ack;
+        struct mutex           lock;
 
-       switch (phdr->msg_type) {
-       case WCNSS_NV_DOWNLOAD_RSP:
-               pr_info("fw_status: %d\n", wcnss_fw_status(data));
-               break;
-       }
-       return;
-}
+       struct work_struct      rx_work;
+       struct work_struct      download_work;
 
-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 struct 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;
+       int ret = 0, i;
        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;
@@ -266,18 +183,12 @@ 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);
-               }
-
-               if (ret < 0) {
+               ret = qcom_smd_send(wcnss_data->channel, pkt, msg->hdr.msg_len);
+               if (ret) {
                        dev_err(dev, "nv download failed\n");
                        goto out;
                }
+
                i++;
                nv_blob_size -= NV_FRAGMENT_SIZE;
                msleep(100);
@@ -289,49 +200,97 @@ 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;
+       const unsigned char *tmp = data;
 
+       memcpy_fromio(&phdr, data, sizeof(struct smd_msg_hdr));
+
+       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(struct smd_msg_hdr)]);
+               break;
+       }
+
+       complete(&wcnss_data->ack);
        return 0;
 }
 
-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->sdev = sdev;
+
+        dev_set_drvdata(&sdev->dev, wcnss_data);
+       wcnss_data->channel = sdev->channel;
+
+       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_wcnss_ctrl_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_wcnss_ctrl",
+               .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;
+        }
+
+       return;
 }
 
 void wcnss_core_deinit(void)
 {
-       platform_driver_unregister(&wcnss_ctrl_driver);
+       qcom_smd_driver_unregister(&qcom_smd_wcnss_ctrl_driver);
 }
-
index 4c3517b99c30379bd7bce9f14870180cd5160ab3..49524c8dddfbb01eae6642a6767d13b6300b90ff 100644 (file)
 
 #define        WCNSS_NV_DOWNLOAD_REQ   0x01000002
 #define        WCNSS_NV_DOWNLOAD_RSP   0x01000003
+#define WCNSS_CBC_COMPLETE_IND  0x0100000C
+
+/*time out 10s for the firmware status ready indicator */
+#define FW_READY_TIMEOUT        (10000)
 
-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;