aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYin, Fengwei <fengwei.yin@linaro.org>2015-07-28 15:21:54 +0800
committerYin, Fengwei <fengwei.yin@linaro.org>2015-07-28 15:22:42 +0800
commitc66734552d2c5c61bf282f6653a66224289ebc90 (patch)
tree4ae5794417020b45b4f37675979117662f4baf89
parentae26616db10ee71757263fc7d068823d21c23689 (diff)
Migrate the wifi driver from old smd driver to new smd driver.
Signed-off-by: Yin, Fengwei <fengwei.yin@linaro.org>
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi53
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c119
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcnss_core.c227
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcnss_core.h9
5 files changed, 216 insertions, 194 deletions
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 55ce92b2fe90..255412853bbd 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -569,5 +569,58 @@
memory-region = <&peripheral_mem>;
};
+
+ qcom,wcn36xx@0a000000 {
+ compatible = "qcom,wcn3620";
+ reg = <0x0a000000 0x280000>,
+ <0xb011008 0x04>,
+ <0x0a21b000 0x3000>,
+ <0x03204000 0x00000100>,
+ <0x03200800 0x00000200>,
+ <0x0A100400 0x00000200>,
+ <0x0A205050 0x00000200>,
+ <0x0A219000 0x00000020>,
+ <0x0A080488 0x00000008>,
+ <0x0A080fb0 0x00000008>,
+ <0x0A08040c 0x00000008>,
+ <0x0A0120a8 0x00000008>,
+ <0x0A012448 0x00000008>,
+ <0x0A080c00 0x00000001>;
+
+ reg-names = "wcnss_mmio", "wcnss_fiq",
+ "pronto_phy_base", "riva_phy_base",
+ "riva_ccu_base", "pronto_a2xb_base",
+ "pronto_ccpu_base", "pronto_saw2_base",
+ "wlan_tx_phy_aborts","wlan_brdg_err_source",
+ "wlan_tx_status", "alarms_txctl",
+ "alarms_tactl", "pronto_mcu_base";
+
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8916_l3>;
+ qcom,pronto-vddcx-supply = <&pm8916_s1_corner>;
+ qcom,pronto-vddpx-supply = <&pm8916_l7>;
+ qcom,iris-vddxo-supply = <&pm8916_l7>;
+ qcom,iris-vddrfa-supply = <&pm8916_s3>;
+ qcom,iris-vddpa-supply = <&pm8916_l9>;
+ qcom,iris-vdddig-supply = <&pm8916_l5>;
+
+ pinctrl-names = "wcnss_default", "wcnss_sleep",
+ "wcnss_gpio_default";
+ pinctrl-0 = <&wcnss_default>;
+ pinctrl-1 = <&wcnss_sleep>;
+ pinctrl-2 = <&wcnss_gpio_default>;
+
+ clocks = <&rpmcc RPM_XO_CLK_SRC>,
+ <&rpmcc RPM_RF_CLK2>;
+ clock-names = "xo", "rf_clk";
+
+ qcom,has-autodetect-xo;
+ qcom,wlan-rx-buff-count = <512>;
+ qcom,is-pronto-vt;
+ qcom,has-pronto-hw;
+ // qcom,wcnss-adc_tm = <&pm8916_adc_tm>;
+ };
};
};
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;