diff mbox

[3/4] wcn36xx: Transition driver to SMD client

Message ID 1451266467-15377-4-git-send-email-bjorn.andersson@sonymobile.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Bjorn Andersson Dec. 28, 2015, 1:34 a.m. UTC
The wcn36xx wifi driver follows the life cycle of the WLAN_CTRL SMD
channel, as such it should be a SMD client. This patch makes this
transition, now that we have the necessary frameworks available.

Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
---
 drivers/net/wireless/ath/wcn36xx/Kconfig   |   2 +-
 drivers/net/wireless/ath/wcn36xx/dxe.c     |  16 +++--
 drivers/net/wireless/ath/wcn36xx/main.c    | 111 +++++++++++++++++------------
 drivers/net/wireless/ath/wcn36xx/smd.c     |  26 ++++---
 drivers/net/wireless/ath/wcn36xx/smd.h     |   4 ++
 drivers/net/wireless/ath/wcn36xx/wcn36xx.h |  21 ++----
 6 files changed, 99 insertions(+), 81 deletions(-)

Comments

Eugene Krasnikov Jan. 11, 2016, 9:02 a.m. UTC | #1
Better late than never! Looks good to me.

2015-12-28 1:34 GMT+00:00 Bjorn Andersson <bjorn@kryo.se>:
> The wcn36xx wifi driver follows the life cycle of the WLAN_CTRL SMD
> channel, as such it should be a SMD client. This patch makes this
> transition, now that we have the necessary frameworks available.
>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
> ---
>  drivers/net/wireless/ath/wcn36xx/Kconfig   |   2 +-
>  drivers/net/wireless/ath/wcn36xx/dxe.c     |  16 +++--
>  drivers/net/wireless/ath/wcn36xx/main.c    | 111 +++++++++++++++++------------
>  drivers/net/wireless/ath/wcn36xx/smd.c     |  26 ++++---
>  drivers/net/wireless/ath/wcn36xx/smd.h     |   4 ++
>  drivers/net/wireless/ath/wcn36xx/wcn36xx.h |  21 ++----
>  6 files changed, 99 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig
> index 591ebaea8265..394fe5b77c90 100644
> --- a/drivers/net/wireless/ath/wcn36xx/Kconfig
> +++ b/drivers/net/wireless/ath/wcn36xx/Kconfig
> @@ -1,6 +1,6 @@
>  config WCN36XX
>         tristate "Qualcomm Atheros WCN3660/3680 support"
> -       depends on MAC80211 && HAS_DMA
> +       depends on MAC80211 && HAS_DMA && QCOM_SMD
>         ---help---
>           This module adds support for wireless adapters based on
>           Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
> diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
> index f8dfa05b290a..47f3937a7ab9 100644
> --- a/drivers/net/wireless/ath/wcn36xx/dxe.c
> +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
> @@ -23,6 +23,7 @@
>  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
>  #include <linux/interrupt.h>
> +#include <linux/soc/qcom/smem_state.h>
>  #include "wcn36xx.h"
>  #include "txrx.h"
>
> @@ -150,9 +151,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
>                 goto out_err;
>
>         /* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */
> -       ret = wcn->ctrl_ops->smsm_change_state(
> -               WCN36XX_SMSM_WLAN_TX_ENABLE,
> -               WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
> +       ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
> +                                         WCN36XX_SMSM_WLAN_TX_ENABLE |
> +                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
> +                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
> +       if (ret)
> +               goto out_err;
>
>         return 0;
>
> @@ -676,9 +680,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
>          * notify chip about new frame through SMSM bus.
>          */
>         if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) {
> -               wcn->ctrl_ops->smsm_change_state(
> -                                 0,
> -                                 WCN36XX_SMSM_WLAN_TX_ENABLE);
> +               qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
> +                                           WCN36XX_SMSM_WLAN_TX_ENABLE,
> +                                           WCN36XX_SMSM_WLAN_TX_ENABLE);
>         } else {
>                 /* indicate End Of Packet and generate interrupt on descriptor
>                  * done.
> diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
> index 7c169abdbafe..8659e3f997d2 100644
> --- a/drivers/net/wireless/ath/wcn36xx/main.c
> +++ b/drivers/net/wireless/ath/wcn36xx/main.c
> @@ -19,6 +19,9 @@
>  #include <linux/module.h>
>  #include <linux/firmware.h>
>  #include <linux/platform_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/soc/qcom/smd.h>
> +#include <linux/soc/qcom/smem_state.h>
>  #include "wcn36xx.h"
>
>  unsigned int wcn36xx_dbg_mask;
> @@ -981,48 +984,63 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
>  }
>
>  static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
> -                                         struct platform_device *pdev)
> +                                         struct device *dev)
>  {
> -       struct resource *res;
> +       u32 mmio[2];
> +       int ret;
> +
>         /* Set TX IRQ */
> -       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
> -                                          "wcnss_wlantx_irq");
> -       if (!res) {
> +       wcn->tx_irq = irq_of_parse_and_map(dev->of_node, 0);
> +       if (!wcn->tx_irq) {
>                 wcn36xx_err("failed to get tx_irq\n");
>                 return -ENOENT;
>         }
> -       wcn->tx_irq = res->start;
>
>         /* Set RX IRQ */
> -       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
> -                                          "wcnss_wlanrx_irq");
> -       if (!res) {
> +       wcn->rx_irq = irq_of_parse_and_map(dev->of_node, 1);
> +       if (!wcn->rx_irq) {
>                 wcn36xx_err("failed to get rx_irq\n");
>                 return -ENOENT;
>         }
> -       wcn->rx_irq = res->start;
> +
> +       /* Acquire SMSM tx enable handle */
> +       wcn->tx_enable_state = qcom_smem_state_get(dev, "tx-enable",
> +                       &wcn->tx_enable_state_bit);
> +       if (IS_ERR(wcn->tx_enable_state)) {
> +               wcn36xx_err("failed to get tx-enable state\n");
> +               return -ENOENT;
> +       }
> +
> +       /* Acquire SMSM tx rings empty handle */
> +       wcn->tx_rings_empty_state = qcom_smem_state_get(dev, "tx-rings-empty",
> +                       &wcn->tx_rings_empty_state_bit);
> +       if (IS_ERR(wcn->tx_rings_empty_state)) {
> +               wcn36xx_err("failed to get tx-rings-empty state\n");
> +               return -ENOENT;
> +       }
>
>         /* Map the memory */
> -       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> -                                                "wcnss_mmio");
> -       if (!res) {
> -               wcn36xx_err("failed to get mmio\n");
> +       ret = of_property_read_u32_array(dev->of_node, "qcom,wcnss-mmio", mmio, 2);
> +       if (ret) {
> +               wcn36xx_err("failed to get qcom,wcnss-mmio\n");
>                 return -ENOENT;
>         }
> -       wcn->mmio = ioremap(res->start, resource_size(res));
> +
> +       wcn->mmio = ioremap(mmio[0], mmio[1]);
>         if (!wcn->mmio) {
>                 wcn36xx_err("failed to map io memory\n");
>                 return -ENOMEM;
>         }
> +
>         return 0;
>  }
>
> -static int wcn36xx_probe(struct platform_device *pdev)
> +static int wcn36xx_probe(struct qcom_smd_device *sdev)
>  {
>         struct ieee80211_hw *hw;
>         struct wcn36xx *wcn;
>         int ret;
> -       u8 addr[ETH_ALEN];
> +       const u8 *addr;
>
>         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
>
> @@ -1032,20 +1050,27 @@ static int wcn36xx_probe(struct platform_device *pdev)
>                 ret = -ENOMEM;
>                 goto out_err;
>         }
> -       platform_set_drvdata(pdev, hw);
> +       dev_set_drvdata(&sdev->dev, hw);
>         wcn = hw->priv;
>         wcn->hw = hw;
> -       wcn->dev = &pdev->dev;
> -       wcn->ctrl_ops = pdev->dev.platform_data;
> +       wcn->dev = &sdev->dev;
> +       wcn->smd_channel = sdev->channel;
>
>         mutex_init(&wcn->hal_mutex);
>
> -       if (!wcn->ctrl_ops->get_hw_mac(addr)) {
> +       sdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> +       addr = of_get_property(sdev->dev.of_node, "local-mac-address", &ret);
> +       if (addr && ret != ETH_ALEN) {
> +               wcn36xx_err("invalid local-mac-address\n");
> +               ret = -EINVAL;
> +               goto out_err;
> +       } else if (addr) {
>                 wcn36xx_info("mac address: %pM\n", addr);
>                 SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
>         }
>
> -       ret = wcn36xx_platform_get_resources(wcn, pdev);
> +       ret = wcn36xx_platform_get_resources(wcn, &sdev->dev);
>         if (ret)
>                 goto out_wq;
>
> @@ -1063,9 +1088,10 @@ out_wq:
>  out_err:
>         return ret;
>  }
> -static int wcn36xx_remove(struct platform_device *pdev)
> +
> +static void wcn36xx_remove(struct qcom_smd_device *sdev)
>  {
> -       struct ieee80211_hw *hw = platform_get_drvdata(pdev);
> +       struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
>         struct wcn36xx *wcn = hw->priv;
>         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
>
> @@ -1073,41 +1099,34 @@ static int wcn36xx_remove(struct platform_device *pdev)
>         mutex_destroy(&wcn->hal_mutex);
>
>         ieee80211_unregister_hw(hw);
> +
> +       qcom_smem_state_put(wcn->tx_enable_state);
> +       qcom_smem_state_put(wcn->tx_rings_empty_state);
> +
>         iounmap(wcn->mmio);
>         ieee80211_free_hw(hw);
> -
> -       return 0;
>  }
> -static const struct platform_device_id wcn36xx_platform_id_table[] = {
> -       {
> -               .name = "wcn36xx",
> -               .driver_data = 0
> -       },
> +
> +static const struct of_device_id wcn36xx_of_match[] = {
> +       { .compatible = "qcom,wcn3620-wlan" },
> +       { .compatible = "qcom,wcn3660-wlan" },
> +       { .compatible = "qcom,wcn3680-wlan" },
>         {}
>  };
> -MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
> +MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
>
> -static struct platform_driver wcn36xx_driver = {
> +static struct qcom_smd_driver wcn36xx_driver = {
>         .probe      = wcn36xx_probe,
>         .remove     = wcn36xx_remove,
> +       .callback = wcn36xx_smd_rsp_process,
>         .driver         = {
>                 .name   = "wcn36xx",
> +               .of_match_table = wcn36xx_of_match,
> +               .owner  = THIS_MODULE,
>         },
> -       .id_table    = wcn36xx_platform_id_table,
>  };
>
> -static int __init wcn36xx_init(void)
> -{
> -       platform_driver_register(&wcn36xx_driver);
> -       return 0;
> -}
> -module_init(wcn36xx_init);
> -
> -static void __exit wcn36xx_exit(void)
> -{
> -       platform_driver_unregister(&wcn36xx_driver);
> -}
> -module_exit(wcn36xx_exit);
> +module_qcom_smd_driver(wcn36xx_driver);
>
>  MODULE_LICENSE("Dual BSD/GPL");
>  MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
> index 4307429740a9..2bf42787a4af 100644
> --- a/drivers/net/wireless/ath/wcn36xx/smd.c
> +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
> @@ -19,6 +19,7 @@
>  #include <linux/etherdevice.h>
>  #include <linux/firmware.h>
>  #include <linux/bitops.h>
> +#include <linux/soc/qcom/smd.h>
>  #include "smd.h"
>
>  struct wcn36xx_cfg_val {
> @@ -253,7 +254,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 = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
>         if (ret) {
>                 wcn36xx_err("HAL TX failed\n");
>                 goto out;
> @@ -2100,9 +2101,13 @@ out:
>         mutex_unlock(&wcn->hal_mutex);
>         return ret;
>  }
> -static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
> +
> +int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
> +                           const void *buf, size_t len)
>  {
> -       struct wcn36xx_hal_msg_header *msg_header = buf;
> +       const struct wcn36xx_hal_msg_header *msg_header = buf;
> +       struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
> +       struct wcn36xx *wcn = hw->priv;
>         struct wcn36xx_hal_ind_msg *msg_ind;
>         wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
>
> @@ -2151,7 +2156,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
>         case WCN36XX_HAL_OTA_TX_COMPL_IND:
>         case WCN36XX_HAL_MISSED_BEACON_IND:
>         case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
> -               msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
> +               msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
>                 if (!msg_ind) {
>                         /*
>                          * FIXME: Do something smarter then just
> @@ -2175,6 +2180,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
>                 wcn36xx_err("SMD_EVENT (%d) not supported\n",
>                               msg_header->msg_type);
>         }
> +
> +       return 0;
>  }
>  static void wcn36xx_ind_smd_work(struct work_struct *work)
>  {
> @@ -2232,22 +2239,13 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
>         INIT_LIST_HEAD(&wcn->hal_ind_queue);
>         spin_lock_init(&wcn->hal_ind_lock);
>
> -       ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
> -       if (ret) {
> -               wcn36xx_err("failed to open control channel\n");
> -               goto free_wq;
> -       }
> -
> -       return ret;
> +       return 0;
>
> -free_wq:
> -       destroy_workqueue(wcn->hal_ind_wq);
>  out:
>         return ret;
>  }
>
>  void wcn36xx_smd_close(struct wcn36xx *wcn)
>  {
> -       wcn->ctrl_ops->close();
>         destroy_workqueue(wcn->hal_ind_wq);
>  }
> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
> index 21cc4ac7b5ca..4d96d56d266f 100644
> --- a/drivers/net/wireless/ath/wcn36xx/smd.h
> +++ b/drivers/net/wireless/ath/wcn36xx/smd.h
> @@ -60,6 +60,7 @@ struct wcn36xx_hal_ind_msg {
>  };
>
>  struct wcn36xx;
> +struct qcom_smd_device;
>
>  int wcn36xx_smd_open(struct wcn36xx *wcn);
>  void wcn36xx_smd_close(struct wcn36xx *wcn);
> @@ -136,4 +137,7 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
>  int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
>
>  int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
> +
> +int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
> +                           const void *buf, size_t len);
>  #endif /* _SMD_H_ */
> diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
> index 7997cc1312ee..4be81f66e167 100644
> --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
> +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
> @@ -103,19 +103,6 @@ struct nv_data {
>         u8      table;
>  };
>
> -/* Interface for platform control path
> - *
> - * @open: hook must be called when wcn36xx wants to open control channel.
> - * @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 (*smsm_change_state)(u32 clear_mask, u32 set_mask);
> -};
> -
>  /**
>   * struct wcn36xx_vif - holds VIF related fields
>   *
> @@ -204,7 +191,13 @@ struct wcn36xx {
>         int                     rx_irq;
>         void __iomem            *mmio;
>
> -       struct wcn36xx_platform_ctrl_ops *ctrl_ops;
> +       struct qcom_smd_channel *smd_channel;
> +
> +       struct qcom_smem_state  *tx_enable_state;
> +       unsigned                tx_enable_state_bit;
> +       struct qcom_smem_state  *tx_rings_empty_state;
> +       unsigned                tx_rings_empty_state_bit;
> +
>         /*
>          * smd_buf must be protected with smd_mutex to garantee
>          * that all messages are sent one after another
> --
> 2.5.0
>
Bjorn Andersson March 29, 2016, 4:39 a.m. UTC | #2
On Mon, Jan 11, 2016 at 1:02 AM, Eugene Krasnikov <k.eugene.e@gmail.com> wrote:
> Better late than never! Looks good to me.
>

Unfortunately I ran into an issue with ordering of operations between
the WiFi driver and the wcnss_ctrl driver. So an updated series is on
the way, but this depends on changes to the wcnss_ctrl driver, which
are being reviewed right now.

Regards,
Bjorn

> 2015-12-28 1:34 GMT+00:00 Bjorn Andersson <bjorn@kryo.se>:
>> The wcn36xx wifi driver follows the life cycle of the WLAN_CTRL SMD
>> channel, as such it should be a SMD client. This patch makes this
>> transition, now that we have the necessary frameworks available.
>>
>> Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
>> ---
>>  drivers/net/wireless/ath/wcn36xx/Kconfig   |   2 +-
>>  drivers/net/wireless/ath/wcn36xx/dxe.c     |  16 +++--
>>  drivers/net/wireless/ath/wcn36xx/main.c    | 111 +++++++++++++++++------------
>>  drivers/net/wireless/ath/wcn36xx/smd.c     |  26 ++++---
>>  drivers/net/wireless/ath/wcn36xx/smd.h     |   4 ++
>>  drivers/net/wireless/ath/wcn36xx/wcn36xx.h |  21 ++----
>>  6 files changed, 99 insertions(+), 81 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig
>> index 591ebaea8265..394fe5b77c90 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/Kconfig
>> +++ b/drivers/net/wireless/ath/wcn36xx/Kconfig
>> @@ -1,6 +1,6 @@
>>  config WCN36XX
>>         tristate "Qualcomm Atheros WCN3660/3680 support"
>> -       depends on MAC80211 && HAS_DMA
>> +       depends on MAC80211 && HAS_DMA && QCOM_SMD
>>         ---help---
>>           This module adds support for wireless adapters based on
>>           Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
>> diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
>> index f8dfa05b290a..47f3937a7ab9 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/dxe.c
>> +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
>> @@ -23,6 +23,7 @@
>>  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>
>>  #include <linux/interrupt.h>
>> +#include <linux/soc/qcom/smem_state.h>
>>  #include "wcn36xx.h"
>>  #include "txrx.h"
>>
>> @@ -150,9 +151,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
>>                 goto out_err;
>>
>>         /* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */
>> -       ret = wcn->ctrl_ops->smsm_change_state(
>> -               WCN36XX_SMSM_WLAN_TX_ENABLE,
>> -               WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
>> +       ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
>> +                                         WCN36XX_SMSM_WLAN_TX_ENABLE |
>> +                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
>> +                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
>> +       if (ret)
>> +               goto out_err;
>>
>>         return 0;
>>
>> @@ -676,9 +680,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
>>          * notify chip about new frame through SMSM bus.
>>          */
>>         if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) {
>> -               wcn->ctrl_ops->smsm_change_state(
>> -                                 0,
>> -                                 WCN36XX_SMSM_WLAN_TX_ENABLE);
>> +               qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
>> +                                           WCN36XX_SMSM_WLAN_TX_ENABLE,
>> +                                           WCN36XX_SMSM_WLAN_TX_ENABLE);
>>         } else {
>>                 /* indicate End Of Packet and generate interrupt on descriptor
>>                  * done.
>> diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
>> index 7c169abdbafe..8659e3f997d2 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/main.c
>> +++ b/drivers/net/wireless/ath/wcn36xx/main.c
>> @@ -19,6 +19,9 @@
>>  #include <linux/module.h>
>>  #include <linux/firmware.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/soc/qcom/smd.h>
>> +#include <linux/soc/qcom/smem_state.h>
>>  #include "wcn36xx.h"
>>
>>  unsigned int wcn36xx_dbg_mask;
>> @@ -981,48 +984,63 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
>>  }
>>
>>  static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
>> -                                         struct platform_device *pdev)
>> +                                         struct device *dev)
>>  {
>> -       struct resource *res;
>> +       u32 mmio[2];
>> +       int ret;
>> +
>>         /* Set TX IRQ */
>> -       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> -                                          "wcnss_wlantx_irq");
>> -       if (!res) {
>> +       wcn->tx_irq = irq_of_parse_and_map(dev->of_node, 0);
>> +       if (!wcn->tx_irq) {
>>                 wcn36xx_err("failed to get tx_irq\n");
>>                 return -ENOENT;
>>         }
>> -       wcn->tx_irq = res->start;
>>
>>         /* Set RX IRQ */
>> -       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> -                                          "wcnss_wlanrx_irq");
>> -       if (!res) {
>> +       wcn->rx_irq = irq_of_parse_and_map(dev->of_node, 1);
>> +       if (!wcn->rx_irq) {
>>                 wcn36xx_err("failed to get rx_irq\n");
>>                 return -ENOENT;
>>         }
>> -       wcn->rx_irq = res->start;
>> +
>> +       /* Acquire SMSM tx enable handle */
>> +       wcn->tx_enable_state = qcom_smem_state_get(dev, "tx-enable",
>> +                       &wcn->tx_enable_state_bit);
>> +       if (IS_ERR(wcn->tx_enable_state)) {
>> +               wcn36xx_err("failed to get tx-enable state\n");
>> +               return -ENOENT;
>> +       }
>> +
>> +       /* Acquire SMSM tx rings empty handle */
>> +       wcn->tx_rings_empty_state = qcom_smem_state_get(dev, "tx-rings-empty",
>> +                       &wcn->tx_rings_empty_state_bit);
>> +       if (IS_ERR(wcn->tx_rings_empty_state)) {
>> +               wcn36xx_err("failed to get tx-rings-empty state\n");
>> +               return -ENOENT;
>> +       }
>>
>>         /* Map the memory */
>> -       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>> -                                                "wcnss_mmio");
>> -       if (!res) {
>> -               wcn36xx_err("failed to get mmio\n");
>> +       ret = of_property_read_u32_array(dev->of_node, "qcom,wcnss-mmio", mmio, 2);
>> +       if (ret) {
>> +               wcn36xx_err("failed to get qcom,wcnss-mmio\n");
>>                 return -ENOENT;
>>         }
>> -       wcn->mmio = ioremap(res->start, resource_size(res));
>> +
>> +       wcn->mmio = ioremap(mmio[0], mmio[1]);
>>         if (!wcn->mmio) {
>>                 wcn36xx_err("failed to map io memory\n");
>>                 return -ENOMEM;
>>         }
>> +
>>         return 0;
>>  }
>>
>> -static int wcn36xx_probe(struct platform_device *pdev)
>> +static int wcn36xx_probe(struct qcom_smd_device *sdev)
>>  {
>>         struct ieee80211_hw *hw;
>>         struct wcn36xx *wcn;
>>         int ret;
>> -       u8 addr[ETH_ALEN];
>> +       const u8 *addr;
>>
>>         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
>>
>> @@ -1032,20 +1050,27 @@ static int wcn36xx_probe(struct platform_device *pdev)
>>                 ret = -ENOMEM;
>>                 goto out_err;
>>         }
>> -       platform_set_drvdata(pdev, hw);
>> +       dev_set_drvdata(&sdev->dev, hw);
>>         wcn = hw->priv;
>>         wcn->hw = hw;
>> -       wcn->dev = &pdev->dev;
>> -       wcn->ctrl_ops = pdev->dev.platform_data;
>> +       wcn->dev = &sdev->dev;
>> +       wcn->smd_channel = sdev->channel;
>>
>>         mutex_init(&wcn->hal_mutex);
>>
>> -       if (!wcn->ctrl_ops->get_hw_mac(addr)) {
>> +       sdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
>> +
>> +       addr = of_get_property(sdev->dev.of_node, "local-mac-address", &ret);
>> +       if (addr && ret != ETH_ALEN) {
>> +               wcn36xx_err("invalid local-mac-address\n");
>> +               ret = -EINVAL;
>> +               goto out_err;
>> +       } else if (addr) {
>>                 wcn36xx_info("mac address: %pM\n", addr);
>>                 SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
>>         }
>>
>> -       ret = wcn36xx_platform_get_resources(wcn, pdev);
>> +       ret = wcn36xx_platform_get_resources(wcn, &sdev->dev);
>>         if (ret)
>>                 goto out_wq;
>>
>> @@ -1063,9 +1088,10 @@ out_wq:
>>  out_err:
>>         return ret;
>>  }
>> -static int wcn36xx_remove(struct platform_device *pdev)
>> +
>> +static void wcn36xx_remove(struct qcom_smd_device *sdev)
>>  {
>> -       struct ieee80211_hw *hw = platform_get_drvdata(pdev);
>> +       struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
>>         struct wcn36xx *wcn = hw->priv;
>>         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
>>
>> @@ -1073,41 +1099,34 @@ static int wcn36xx_remove(struct platform_device *pdev)
>>         mutex_destroy(&wcn->hal_mutex);
>>
>>         ieee80211_unregister_hw(hw);
>> +
>> +       qcom_smem_state_put(wcn->tx_enable_state);
>> +       qcom_smem_state_put(wcn->tx_rings_empty_state);
>> +
>>         iounmap(wcn->mmio);
>>         ieee80211_free_hw(hw);
>> -
>> -       return 0;
>>  }
>> -static const struct platform_device_id wcn36xx_platform_id_table[] = {
>> -       {
>> -               .name = "wcn36xx",
>> -               .driver_data = 0
>> -       },
>> +
>> +static const struct of_device_id wcn36xx_of_match[] = {
>> +       { .compatible = "qcom,wcn3620-wlan" },
>> +       { .compatible = "qcom,wcn3660-wlan" },
>> +       { .compatible = "qcom,wcn3680-wlan" },
>>         {}
>>  };
>> -MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
>> +MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
>>
>> -static struct platform_driver wcn36xx_driver = {
>> +static struct qcom_smd_driver wcn36xx_driver = {
>>         .probe      = wcn36xx_probe,
>>         .remove     = wcn36xx_remove,
>> +       .callback = wcn36xx_smd_rsp_process,
>>         .driver         = {
>>                 .name   = "wcn36xx",
>> +               .of_match_table = wcn36xx_of_match,
>> +               .owner  = THIS_MODULE,
>>         },
>> -       .id_table    = wcn36xx_platform_id_table,
>>  };
>>
>> -static int __init wcn36xx_init(void)
>> -{
>> -       platform_driver_register(&wcn36xx_driver);
>> -       return 0;
>> -}
>> -module_init(wcn36xx_init);
>> -
>> -static void __exit wcn36xx_exit(void)
>> -{
>> -       platform_driver_unregister(&wcn36xx_driver);
>> -}
>> -module_exit(wcn36xx_exit);
>> +module_qcom_smd_driver(wcn36xx_driver);
>>
>>  MODULE_LICENSE("Dual BSD/GPL");
>>  MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
>> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
>> index 4307429740a9..2bf42787a4af 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/smd.c
>> +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
>> @@ -19,6 +19,7 @@
>>  #include <linux/etherdevice.h>
>>  #include <linux/firmware.h>
>>  #include <linux/bitops.h>
>> +#include <linux/soc/qcom/smd.h>
>>  #include "smd.h"
>>
>>  struct wcn36xx_cfg_val {
>> @@ -253,7 +254,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 = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
>>         if (ret) {
>>                 wcn36xx_err("HAL TX failed\n");
>>                 goto out;
>> @@ -2100,9 +2101,13 @@ out:
>>         mutex_unlock(&wcn->hal_mutex);
>>         return ret;
>>  }
>> -static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
>> +
>> +int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
>> +                           const void *buf, size_t len)
>>  {
>> -       struct wcn36xx_hal_msg_header *msg_header = buf;
>> +       const struct wcn36xx_hal_msg_header *msg_header = buf;
>> +       struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
>> +       struct wcn36xx *wcn = hw->priv;
>>         struct wcn36xx_hal_ind_msg *msg_ind;
>>         wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
>>
>> @@ -2151,7 +2156,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
>>         case WCN36XX_HAL_OTA_TX_COMPL_IND:
>>         case WCN36XX_HAL_MISSED_BEACON_IND:
>>         case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
>> -               msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
>> +               msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
>>                 if (!msg_ind) {
>>                         /*
>>                          * FIXME: Do something smarter then just
>> @@ -2175,6 +2180,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
>>                 wcn36xx_err("SMD_EVENT (%d) not supported\n",
>>                               msg_header->msg_type);
>>         }
>> +
>> +       return 0;
>>  }
>>  static void wcn36xx_ind_smd_work(struct work_struct *work)
>>  {
>> @@ -2232,22 +2239,13 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
>>         INIT_LIST_HEAD(&wcn->hal_ind_queue);
>>         spin_lock_init(&wcn->hal_ind_lock);
>>
>> -       ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
>> -       if (ret) {
>> -               wcn36xx_err("failed to open control channel\n");
>> -               goto free_wq;
>> -       }
>> -
>> -       return ret;
>> +       return 0;
>>
>> -free_wq:
>> -       destroy_workqueue(wcn->hal_ind_wq);
>>  out:
>>         return ret;
>>  }
>>
>>  void wcn36xx_smd_close(struct wcn36xx *wcn)
>>  {
>> -       wcn->ctrl_ops->close();
>>         destroy_workqueue(wcn->hal_ind_wq);
>>  }
>> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
>> index 21cc4ac7b5ca..4d96d56d266f 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/smd.h
>> +++ b/drivers/net/wireless/ath/wcn36xx/smd.h
>> @@ -60,6 +60,7 @@ struct wcn36xx_hal_ind_msg {
>>  };
>>
>>  struct wcn36xx;
>> +struct qcom_smd_device;
>>
>>  int wcn36xx_smd_open(struct wcn36xx *wcn);
>>  void wcn36xx_smd_close(struct wcn36xx *wcn);
>> @@ -136,4 +137,7 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
>>  int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
>>
>>  int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
>> +
>> +int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
>> +                           const void *buf, size_t len);
>>  #endif /* _SMD_H_ */
>> diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
>> index 7997cc1312ee..4be81f66e167 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
>> +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
>> @@ -103,19 +103,6 @@ struct nv_data {
>>         u8      table;
>>  };
>>
>> -/* Interface for platform control path
>> - *
>> - * @open: hook must be called when wcn36xx wants to open control channel.
>> - * @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 (*smsm_change_state)(u32 clear_mask, u32 set_mask);
>> -};
>> -
>>  /**
>>   * struct wcn36xx_vif - holds VIF related fields
>>   *
>> @@ -204,7 +191,13 @@ struct wcn36xx {
>>         int                     rx_irq;
>>         void __iomem            *mmio;
>>
>> -       struct wcn36xx_platform_ctrl_ops *ctrl_ops;
>> +       struct qcom_smd_channel *smd_channel;
>> +
>> +       struct qcom_smem_state  *tx_enable_state;
>> +       unsigned                tx_enable_state_bit;
>> +       struct qcom_smem_state  *tx_rings_empty_state;
>> +       unsigned                tx_rings_empty_state_bit;
>> +
>>         /*
>>          * smd_buf must be protected with smd_mutex to garantee
>>          * that all messages are sent one after another
>> --
>> 2.5.0
>>
>
>
>
> --
> Best regards,
> Eugene
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig
index 591ebaea8265..394fe5b77c90 100644
--- a/drivers/net/wireless/ath/wcn36xx/Kconfig
+++ b/drivers/net/wireless/ath/wcn36xx/Kconfig
@@ -1,6 +1,6 @@ 
 config WCN36XX
 	tristate "Qualcomm Atheros WCN3660/3680 support"
-	depends on MAC80211 && HAS_DMA
+	depends on MAC80211 && HAS_DMA && QCOM_SMD
 	---help---
 	  This module adds support for wireless adapters based on
 	  Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index f8dfa05b290a..47f3937a7ab9 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -23,6 +23,7 @@ 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
 #include "wcn36xx.h"
 #include "txrx.h"
 
@@ -150,9 +151,12 @@  int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
 		goto out_err;
 
 	/* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */
-	ret = wcn->ctrl_ops->smsm_change_state(
-		WCN36XX_SMSM_WLAN_TX_ENABLE,
-		WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+	ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
+					  WCN36XX_SMSM_WLAN_TX_ENABLE |
+					  WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
+					  WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+	if (ret)
+		goto out_err;
 
 	return 0;
 
@@ -676,9 +680,9 @@  int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
 	 * notify chip about new frame through SMSM bus.
 	 */
 	if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) {
-		wcn->ctrl_ops->smsm_change_state(
-				  0,
-				  WCN36XX_SMSM_WLAN_TX_ENABLE);
+		qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
+					    WCN36XX_SMSM_WLAN_TX_ENABLE,
+					    WCN36XX_SMSM_WLAN_TX_ENABLE);
 	} else {
 		/* indicate End Of Packet and generate interrupt on descriptor
 		 * done.
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 7c169abdbafe..8659e3f997d2 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -19,6 +19,9 @@ 
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/smem_state.h>
 #include "wcn36xx.h"
 
 unsigned int wcn36xx_dbg_mask;
@@ -981,48 +984,63 @@  static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
 }
 
 static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
-					  struct platform_device *pdev)
+					  struct device *dev)
 {
-	struct resource *res;
+	u32 mmio[2];
+	int ret;
+
 	/* Set TX IRQ */
-	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-					   "wcnss_wlantx_irq");
-	if (!res) {
+	wcn->tx_irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (!wcn->tx_irq) {
 		wcn36xx_err("failed to get tx_irq\n");
 		return -ENOENT;
 	}
-	wcn->tx_irq = res->start;
 
 	/* Set RX IRQ */
-	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-					   "wcnss_wlanrx_irq");
-	if (!res) {
+	wcn->rx_irq = irq_of_parse_and_map(dev->of_node, 1);
+	if (!wcn->rx_irq) {
 		wcn36xx_err("failed to get rx_irq\n");
 		return -ENOENT;
 	}
-	wcn->rx_irq = res->start;
+
+	/* Acquire SMSM tx enable handle */
+	wcn->tx_enable_state = qcom_smem_state_get(dev, "tx-enable",
+			&wcn->tx_enable_state_bit);
+	if (IS_ERR(wcn->tx_enable_state)) {
+		wcn36xx_err("failed to get tx-enable state\n");
+		return -ENOENT;
+	}
+
+	/* Acquire SMSM tx rings empty handle */
+	wcn->tx_rings_empty_state = qcom_smem_state_get(dev, "tx-rings-empty",
+			&wcn->tx_rings_empty_state_bit);
+	if (IS_ERR(wcn->tx_rings_empty_state)) {
+		wcn36xx_err("failed to get tx-rings-empty state\n");
+		return -ENOENT;
+	}
 
 	/* Map the memory */
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-						 "wcnss_mmio");
-	if (!res) {
-		wcn36xx_err("failed to get mmio\n");
+	ret = of_property_read_u32_array(dev->of_node, "qcom,wcnss-mmio", mmio, 2);
+	if (ret) {
+		wcn36xx_err("failed to get qcom,wcnss-mmio\n");
 		return -ENOENT;
 	}
-	wcn->mmio = ioremap(res->start, resource_size(res));
+
+	wcn->mmio = ioremap(mmio[0], mmio[1]);
 	if (!wcn->mmio) {
 		wcn36xx_err("failed to map io memory\n");
 		return -ENOMEM;
 	}
+
 	return 0;
 }
 
-static int wcn36xx_probe(struct platform_device *pdev)
+static int wcn36xx_probe(struct qcom_smd_device *sdev)
 {
 	struct ieee80211_hw *hw;
 	struct wcn36xx *wcn;
 	int ret;
-	u8 addr[ETH_ALEN];
+	const u8 *addr;
 
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
 
@@ -1032,20 +1050,27 @@  static int wcn36xx_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		goto out_err;
 	}
-	platform_set_drvdata(pdev, hw);
+	dev_set_drvdata(&sdev->dev, hw);
 	wcn = hw->priv;
 	wcn->hw = hw;
-	wcn->dev = &pdev->dev;
-	wcn->ctrl_ops = pdev->dev.platform_data;
+	wcn->dev = &sdev->dev;
+	wcn->smd_channel = sdev->channel;
 
 	mutex_init(&wcn->hal_mutex);
 
-	if (!wcn->ctrl_ops->get_hw_mac(addr)) {
+	sdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	addr = of_get_property(sdev->dev.of_node, "local-mac-address", &ret);
+	if (addr && ret != ETH_ALEN) {
+		wcn36xx_err("invalid local-mac-address\n");
+		ret = -EINVAL;
+		goto out_err;
+	} else if (addr) {
 		wcn36xx_info("mac address: %pM\n", addr);
 		SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
 	}
 
-	ret = wcn36xx_platform_get_resources(wcn, pdev);
+	ret = wcn36xx_platform_get_resources(wcn, &sdev->dev);
 	if (ret)
 		goto out_wq;
 
@@ -1063,9 +1088,10 @@  out_wq:
 out_err:
 	return ret;
 }
-static int wcn36xx_remove(struct platform_device *pdev)
+
+static void wcn36xx_remove(struct qcom_smd_device *sdev)
 {
-	struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+	struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
 	struct wcn36xx *wcn = hw->priv;
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
 
@@ -1073,41 +1099,34 @@  static int wcn36xx_remove(struct platform_device *pdev)
 	mutex_destroy(&wcn->hal_mutex);
 
 	ieee80211_unregister_hw(hw);
+
+	qcom_smem_state_put(wcn->tx_enable_state);
+	qcom_smem_state_put(wcn->tx_rings_empty_state);
+
 	iounmap(wcn->mmio);
 	ieee80211_free_hw(hw);
-
-	return 0;
 }
-static const struct platform_device_id wcn36xx_platform_id_table[] = {
-	{
-		.name = "wcn36xx",
-		.driver_data = 0
-	},
+
+static const struct of_device_id wcn36xx_of_match[] = {
+	{ .compatible = "qcom,wcn3620-wlan" },
+	{ .compatible = "qcom,wcn3660-wlan" },
+	{ .compatible = "qcom,wcn3680-wlan" },
 	{}
 };
-MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
 
-static struct platform_driver wcn36xx_driver = {
+static struct qcom_smd_driver wcn36xx_driver = {
 	.probe      = wcn36xx_probe,
 	.remove     = wcn36xx_remove,
+	.callback = wcn36xx_smd_rsp_process,
 	.driver         = {
 		.name   = "wcn36xx",
+		.of_match_table = wcn36xx_of_match,
+		.owner  = THIS_MODULE,
 	},
-	.id_table    = wcn36xx_platform_id_table,
 };
 
-static int __init wcn36xx_init(void)
-{
-	platform_driver_register(&wcn36xx_driver);
-	return 0;
-}
-module_init(wcn36xx_init);
-
-static void __exit wcn36xx_exit(void)
-{
-	platform_driver_unregister(&wcn36xx_driver);
-}
-module_exit(wcn36xx_exit);
+module_qcom_smd_driver(wcn36xx_driver);
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 4307429740a9..2bf42787a4af 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -19,6 +19,7 @@ 
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
 #include <linux/bitops.h>
+#include <linux/soc/qcom/smd.h>
 #include "smd.h"
 
 struct wcn36xx_cfg_val {
@@ -253,7 +254,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 = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
 	if (ret) {
 		wcn36xx_err("HAL TX failed\n");
 		goto out;
@@ -2100,9 +2101,13 @@  out:
 	mutex_unlock(&wcn->hal_mutex);
 	return ret;
 }
-static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
+			    const void *buf, size_t len)
 {
-	struct wcn36xx_hal_msg_header *msg_header = buf;
+	const struct wcn36xx_hal_msg_header *msg_header = buf;
+	struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
+	struct wcn36xx *wcn = hw->priv;
 	struct wcn36xx_hal_ind_msg *msg_ind;
 	wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
 
@@ -2151,7 +2156,7 @@  static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
 	case WCN36XX_HAL_OTA_TX_COMPL_IND:
 	case WCN36XX_HAL_MISSED_BEACON_IND:
 	case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
-		msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
+		msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
 		if (!msg_ind) {
 			/*
 			 * FIXME: Do something smarter then just
@@ -2175,6 +2180,8 @@  static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
 		wcn36xx_err("SMD_EVENT (%d) not supported\n",
 			      msg_header->msg_type);
 	}
+
+	return 0;
 }
 static void wcn36xx_ind_smd_work(struct work_struct *work)
 {
@@ -2232,22 +2239,13 @@  int wcn36xx_smd_open(struct wcn36xx *wcn)
 	INIT_LIST_HEAD(&wcn->hal_ind_queue);
 	spin_lock_init(&wcn->hal_ind_lock);
 
-	ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
-	if (ret) {
-		wcn36xx_err("failed to open control channel\n");
-		goto free_wq;
-	}
-
-	return ret;
+	return 0;
 
-free_wq:
-	destroy_workqueue(wcn->hal_ind_wq);
 out:
 	return ret;
 }
 
 void wcn36xx_smd_close(struct wcn36xx *wcn)
 {
-	wcn->ctrl_ops->close();
 	destroy_workqueue(wcn->hal_ind_wq);
 }
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 21cc4ac7b5ca..4d96d56d266f 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -60,6 +60,7 @@  struct wcn36xx_hal_ind_msg {
 };
 
 struct wcn36xx;
+struct qcom_smd_device;
 
 int wcn36xx_smd_open(struct wcn36xx *wcn);
 void wcn36xx_smd_close(struct wcn36xx *wcn);
@@ -136,4 +137,7 @@  int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
 
 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
+			    const void *buf, size_t len);
 #endif	/* _SMD_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 7997cc1312ee..4be81f66e167 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -103,19 +103,6 @@  struct nv_data {
 	u8	table;
 };
 
-/* Interface for platform control path
- *
- * @open: hook must be called when wcn36xx wants to open control channel.
- * @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 (*smsm_change_state)(u32 clear_mask, u32 set_mask);
-};
-
 /**
  * struct wcn36xx_vif - holds VIF related fields
  *
@@ -204,7 +191,13 @@  struct wcn36xx {
 	int			rx_irq;
 	void __iomem		*mmio;
 
-	struct wcn36xx_platform_ctrl_ops *ctrl_ops;
+	struct qcom_smd_channel *smd_channel;
+
+	struct qcom_smem_state  *tx_enable_state;
+	unsigned		tx_enable_state_bit;
+	struct qcom_smem_state	*tx_rings_empty_state;
+	unsigned		tx_rings_empty_state_bit;
+
 	/*
 	 * smd_buf must be protected with smd_mutex to garantee
 	 * that all messages are sent one after another