From patchwork Sun Jan 18 05:16:45 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: warmcat X-Patchwork-Id: 43278 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f199.google.com (mail-wi0-f199.google.com [209.85.212.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id C8798240BA for ; Sun, 18 Jan 2015 05:16:59 +0000 (UTC) Received: by mail-wi0-f199.google.com with SMTP id r20sf445714wiv.2 for ; Sat, 17 Jan 2015 21:16:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:subject:from:to:cc:date:message-id :in-reply-to:references:user-agent:mime-version:content-type :content-transfer-encoding:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=GezuqDAf1W74XGXTCHvH2GfmYLqAsdpzxgS2JTTN+dE=; b=YsBzEf2seaDcveoih+/XhP3NJ2MnjY1CYrXwlabuDUWv6t8oaGzIJFVLrBd8etlDri CIbhnI5tW7OE3vZfLCwmucSCXneAPA96h6uE5mRKC45alpzAqkADx29eI0OEMndJomk+ +I6+5fW+4iA0sn0jCHuZyV1Zk4oIH3Vu4vJFpQLyIjgtDD6J5wDIf3rA7SzCkrDUsuD6 n3MOuiEeKd6D4eaNrieLCAfxUWl86aCi6Xzk1K+y3swplZaUZ7/qxkdOfSsuxQTI/8v0 yBgiC3ii1cNS/JillbNor7XL+tw3MiALIlnWKLIi6Gt9LkzRmtoIef2cr0G/AmYu8mkm XQJA== X-Gm-Message-State: ALoCoQnVlXdou9CJXFPWdYjR+fIwVLEGZkhl1oaWWYitto8G/qzQIf3kjjaSFv9fvkXzLiVT1gUH X-Received: by 10.152.3.234 with SMTP id f10mr1176257laf.1.1421558219071; Sat, 17 Jan 2015 21:16:59 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.43.97 with SMTP id v1ls511269lal.29.gmail; Sat, 17 Jan 2015 21:16:58 -0800 (PST) X-Received: by 10.112.160.33 with SMTP id xh1mr23614809lbb.60.1421558218478; Sat, 17 Jan 2015 21:16:58 -0800 (PST) Received: from mail-la0-x22b.google.com (mail-la0-x22b.google.com. [2a00:1450:4010:c03::22b]) by mx.google.com with ESMTPS id f10si7172387lbs.123.2015.01.17.21.16.58 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 17 Jan 2015 21:16:58 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2a00:1450:4010:c03::22b as permitted sender) client-ip=2a00:1450:4010:c03::22b; Received: by mail-la0-f43.google.com with SMTP id q1so8897939lam.2 for ; Sat, 17 Jan 2015 21:16:58 -0800 (PST) X-Received: by 10.152.43.103 with SMTP id v7mr23464659lal.29.1421558218362; Sat, 17 Jan 2015 21:16:58 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.9.200 with SMTP id c8csp741251lbb; Sat, 17 Jan 2015 21:16:57 -0800 (PST) X-Received: by 10.68.231.71 with SMTP id te7mr34169325pbc.129.1421558216271; Sat, 17 Jan 2015 21:16:56 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id la4si11231268pbc.14.2015.01.17.21.16.55; Sat, 17 Jan 2015 21:16:56 -0800 (PST) Received-SPF: none (google.com: linux-wireless-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751317AbbARFQy (ORCPT + 1 other); Sun, 18 Jan 2015 00:16:54 -0500 Received: from mail-pd0-f177.google.com ([209.85.192.177]:54770 "EHLO mail-pd0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751104AbbARFQv (ORCPT ); Sun, 18 Jan 2015 00:16:51 -0500 Received: by mail-pd0-f177.google.com with SMTP id y13so5389279pdi.8; Sat, 17 Jan 2015 21:16:50 -0800 (PST) X-Received: by 10.66.249.39 with SMTP id yr7mr7644448pac.43.1421558210539; Sat, 17 Jan 2015 21:16:50 -0800 (PST) Received: from warmcat.com (114-36-241-182.dynamic.hinet.net. [114.36.241.182]) by mx.google.com with ESMTPSA id fu17sm8090686pdb.5.2015.01.17.21.16.48 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 17 Jan 2015 21:16:49 -0800 (PST) Subject: [PATCH 1/2] net wireless wcn36xx add wcnss platform code From: Andy Green To: Kalle Valo , Eugene Krasnikov Cc: wcn36xx@lists.infradead.org, linux-wireless@vger.kernel.org, netdev@vger.kernel.org Date: Sun, 18 Jan 2015 13:16:45 +0800 Message-ID: <20150118051644.32019.65489.stgit@114-36-241-182.dynamic.hinet.net> In-Reply-To: <20150118051222.32019.32719.stgit@114-36-241-182.dynamic.hinet.net> References: <20150118051222.32019.32719.stgit@114-36-241-182.dynamic.hinet.net> User-Agent: StGit/0.17-dirty MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Original-Sender: andy.green@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2a00:1450:4010:c03::22b as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org; dkim=neutral (body hash did not verify) header.i=@ Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Eugene Krasnikov AG modified to remove regulator handling not needed on msm8916-qrd Signed-off-by: Eugene Krasnikov Signed-off-by: Andy Green --- drivers/net/wireless/ath/wcn36xx/Makefile | 2 drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c | 357 ++++++++++++++++++++++++ 2 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c -- 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 --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile index 50c43b4..e889f2c 100644 --- a/drivers/net/wireless/ath/wcn36xx/Makefile +++ b/drivers/net/wireless/ath/wcn36xx/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_WCN36XX) := wcn36xx.o +obj-$(CONFIG_WCN36XX) := wcn36xx.o wcn36xx-msm.o wcn36xx-y += main.o \ dxe.o \ txrx.o \ diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c new file mode 100644 index 0000000..f6f6c83 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wcn36xx.h" + +#include +#include + +#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; +} 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); +} + +static int wcn36xx_msm_get_hw_mac(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}; + + status = request_firmware(&addr_file, files, &wmsm.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); + memcpy(addr, qcom_oui, 3); + get_random_bytes(addr + 3, 3); + } else { + memset(tmp, 0, sizeof(tmp)); + memcpy(tmp, addr_file->data, sizeof(tmp) - 1); + sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &addr[0], + &addr[1], + &addr[2], + &addr[3], + &addr[4], + &addr[5]); + + release_firmware(addr_file); + } + + return 0; +} + +static int wcn36xx_msm_smd_send_and_wait(char *buf, size_t len) +{ + int avail; + int ret = 0; + + 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; + } + +out: + return ret; +} + +static void wcn36xx_msm_smd_notify(void *data, unsigned event) +{ + 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; + } +} + +static void wcn36xx_msm_smd_work(struct work_struct *work) +{ + 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; + } + + 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); + } +} + +int wcn36xx_msm_smd_open(void *drv_priv, void *rsp_cb) +{ + 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; + } + + 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; + } + + 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; + } + + /* Not to receive INT until the whole buf from SMD is read */ + smd_disable_read_intr(wmsm.smd_ch); + + return 0; +} + +void wcn36xx_msm_smd_close(void) +{ + smd_close(wmsm.smd_ch); + flush_workqueue(wmsm.wq); + destroy_workqueue(wmsm.wq); +} + +int wcn36xx_msm_shutdown(const struct subsys_desc *desc, bool force_stop) +{ + return 0; +} +int wcn36xx_msm_powerup(const struct subsys_desc *desc) +{ + return 0; +} + +static int wcn36xx_msm_probe(struct platform_device *pdev) +{ + int ret; + struct resource *wcnss_memory; + struct resource *tx_irq; + struct resource *rx_irq; + struct resource res[3]; + struct pinctrl_state *ps; + + wmsm.pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(wmsm.pinctrl)) + return PTR_ERR(wmsm.pinctrl); + + ps = pinctrl_lookup_state(wmsm.pinctrl, "wcnss_default"); + if (IS_ERR_OR_NULL(ps)) + return PTR_ERR(ps); + + ret = pinctrl_select_state(wmsm.pinctrl, ps); + if (ret) + return ret; + + if (IS_ERR_OR_NULL(pil)) + pil = subsystem_get("wcnss"); + if (IS_ERR_OR_NULL(pil)) + return PTR_ERR(pil); + + wmsm.core = platform_device_alloc("wcn36xx", -1); + + //dev_err(&pdev->dev, "%s starting\n", __func__); + + memset(res, 0x00, sizeof(res)); + wmsm.ctrl_ops.open = wcn36xx_msm_smd_open; + wmsm.ctrl_ops.close = wcn36xx_msm_smd_close; + wmsm.ctrl_ops.tx = wcn36xx_msm_smd_send_and_wait; + wmsm.ctrl_ops.get_hw_mac = wcn36xx_msm_get_hw_mac; + wmsm.ctrl_ops.smsm_change_state = wcn36xx_msm_smsm_change_state; + wcnss_memory = + platform_get_resource_byname(pdev, + IORESOURCE_MEM, + "wcnss_mmio"); + if (wcnss_memory == NULL) { + dev_err(&wmsm.core->dev, + "Failed to get wcnss wlan memory map.\n"); + ret = -ENOMEM; + return ret; + } + memcpy(&res[0], wcnss_memory, sizeof(*wcnss_memory)); + + tx_irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, + "wcnss_wlantx_irq"); + if (tx_irq == NULL) { + dev_err(&wmsm.core->dev, "Failed to get wcnss tx_irq"); + ret = -ENOMEM; + return ret; + } + memcpy(&res[1], tx_irq, sizeof(*tx_irq)); + + rx_irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, + "wcnss_wlanrx_irq"); + if (rx_irq == NULL) { + dev_err(&wmsm.core->dev, "Failed to get wcnss rx_irq"); + ret = -ENOMEM; + return ret; + } + memcpy(&res[2], rx_irq, sizeof(*rx_irq)); + + platform_device_add_resources(wmsm.core, res, ARRAY_SIZE(res)); + + 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); + + dev_info(&pdev->dev, "%s initialized\n", __func__); + + return 0; +} +static int wcn36xx_msm_remove(struct platform_device *pdev) +{ + struct pinctrl_state *ps; + + 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); + } + + return 0; +} + +static const struct of_device_id wcn36xx_msm_match_table[] = { + { .compatible = "qcom,wcn36xx" }, + { } +}; +MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table); + +static struct platform_driver wcn36xx_msm_driver = { + .probe = wcn36xx_msm_probe, + .remove = wcn36xx_msm_remove, + .driver = { + .name = "wcn36xx-msm", + .owner = THIS_MODULE, + .of_match_table = wcn36xx_msm_match_table, + }, +}; + +static int __init wcn36xx_msm_init(void) +{ + return platform_driver_register(&wcn36xx_msm_driver); +} +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); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com"); +MODULE_FIRMWARE(MAC_ADDR_0); +