All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jerome Pouiller <Jerome.Pouiller@silabs.com>
To: "devel@driverdev.osuosl.org" <devel@driverdev.osuosl.org>,
	"linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>
Cc: "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Kalle Valo <kvalo@codeaurora.org>,
	"David S . Miller" <davem@davemloft.net>,
	David Le Goff <David.Legoff@silabs.com>,
	Jerome Pouiller <Jerome.Pouiller@silabs.com>
Subject: [PATCH v3 14/20] staging: wfx: setup initial chip configuration
Date: Thu, 19 Sep 2019 14:25:44 +0000	[thread overview]
Message-ID: <20190919142527.31797-15-Jerome.Pouiller@silabs.com> (raw)
In-Reply-To: <20190919142527.31797-1-Jerome.Pouiller@silabs.com>

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

A few tasks remain to be done in order to finish chip initial
configuration:
   - configure chip to use multi-tx confirmation (speed up data
     transfer)
   - configure chip to use wake-up feature (save power consumption
     during runtime)
   - set hardware configuration (clocks, RF, pinout, etc...) using a
     Platform Data Set (PDS) file

On release, driver completely shutdown the chip to save power
consumption.

Documentation about PDS and PDS data for sample boards are available
here[1]. One day, PDS data may find a place in device tree but,
currently, PDS is too much linked with firmware to allowing that.

This patch also add "send_pds" file in debugfs to be able to dynamically
change PDS (only for debug, of course).

[1]: https://github.com/SiliconLabs/wfx-firmware/tree/master/PDS

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/staging/wfx/bus_sdio.c |  1 +
 drivers/staging/wfx/bus_spi.c  |  1 +
 drivers/staging/wfx/debug.c    | 29 +++++++++++
 drivers/staging/wfx/hif_rx.c   | 11 ++++
 drivers/staging/wfx/main.c     | 94 ++++++++++++++++++++++++++++++++++
 drivers/staging/wfx/main.h     |  2 +
 6 files changed, 138 insertions(+)

diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index c0c063c3cfc9..05f02c278782 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -19,6 +19,7 @@
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
 	.file_fw = "wfm_wf200",
+	.file_pds = "wf200.pds",
 };
 
 struct wfx_sdio_priv {
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index b7cd82b4e5e7..f65f7d75e731 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -29,6 +29,7 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for none.");
 
 static const struct wfx_platform_data wfx_spi_pdata = {
 	.file_fw = "wfm_wf200",
+	.file_pds = "wf200.pds",
 	.use_rising_clk = true,
 };
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f79693a4be7f..0619c7d1cf79 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -10,6 +10,7 @@
 
 #include "debug.h"
 #include "wfx.h"
+#include "main.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -54,6 +55,33 @@ const char *get_reg_name(unsigned long id)
 	return get_symbol(id, wfx_reg_print_map);
 }
 
+static ssize_t wfx_send_pds_write(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct wfx_dev *wdev = file->private_data;
+	char *buf;
+	int ret;
+
+	if (*ppos != 0) {
+		dev_dbg(wdev->dev, "PDS data must be written in one transaction");
+		return -EBUSY;
+	}
+	buf = memdup_user(user_buf, count);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+	*ppos = *ppos + count;
+	ret = wfx_send_pds(wdev, buf, count);
+	kfree(buf);
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+static const struct file_operations wfx_send_pds_fops = {
+	.open = simple_open,
+	.write = wfx_send_pds_write,
+};
+
 static ssize_t wfx_burn_slk_key_write(struct file *file,
 				      const char __user *user_buf,
 				      size_t count, loff_t *ppos)
@@ -162,6 +190,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
 	struct dentry *d;
 
 	d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+	debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops);
 	debugfs_create_file("burn_slk_key", 0200, d, wdev, &wfx_burn_slk_key_fops);
 	debugfs_create_file("send_hif_msg", 0600, d, wdev, &wfx_send_hif_msg_fops);
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index dd5f1dea4e85..6b9683d69a3f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -71,6 +71,16 @@ static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi
 	return 0;
 }
 
+static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
+{
+	if (!wdev->pdata.gpio_wakeup
+	    || !gpiod_get_value(wdev->pdata.gpio_wakeup)) {
+		dev_warn(wdev->dev, "unexpected wake-up indication\n");
+		return -EIO;
+	}
+	return 0;
+}
+
 static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
 {
 	struct hif_ind_sl_exchange_pub_keys *body = buf;
@@ -89,6 +99,7 @@ static const struct {
 	int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
 } hif_handlers[] = {
 	{ HIF_IND_ID_STARTUP,              hif_startup_indication },
+	{ HIF_IND_ID_WAKEUP,               hif_wakeup_indication },
 	{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
 };
 
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 0cfd6b2ec8d1..5b04ea5f4353 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -18,6 +18,7 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/spi/spi.h>
 #include <linux/etherdevice.h>
+#include <linux/firmware.h>
 
 #include "main.h"
 #include "wfx.h"
@@ -28,9 +29,12 @@
 #include "sta.h"
 #include "debug.h"
 #include "secure_link.h"
+#include "hif_tx_mib.h"
 #include "hif_api_cmd.h"
 #include "wfx_version.h"
 
+#define WFX_PDS_MAX_SIZE 1500
+
 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
 MODULE_AUTHOR("Jérôme Pouiller <jerome.pouiller@silabs.com>");
 MODULE_LICENSE("GPL");
@@ -112,6 +116,69 @@ static void wfx_fill_sl_key(struct device *dev, struct wfx_platform_data *pdata)
 	dev_err(dev, "secure link is not supported by this driver, ignoring provided key\n");
 }
 
+/* NOTE: wfx_send_pds() destroy buf */
+int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len)
+{
+	int ret;
+	int start, brace_level, i;
+
+	start = 0;
+	brace_level = 0;
+	if (buf[0] != '{') {
+		dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n");
+		return -EINVAL;
+	}
+	for (i = 1; i < len - 1; i++) {
+		if (buf[i] == '{')
+			brace_level++;
+		if (buf[i] == '}')
+			brace_level--;
+		if (buf[i] == '}' && !brace_level) {
+			i++;
+			if (i - start + 1 > WFX_PDS_MAX_SIZE)
+				return -EFBIG;
+			buf[start] = '{';
+			buf[i] = 0;
+			dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start);
+			buf[i] = '}';
+			ret = hif_configuration(wdev, buf + start, i - start + 1);
+			if (ret == HIF_STATUS_FAILURE) {
+				dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", start, i);
+				return -EINVAL;
+			}
+			if (ret == -ETIMEDOUT) {
+				dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", start, i);
+				return ret;
+			}
+			if (ret) {
+				dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", start, i);
+				return -EIO;
+			}
+			buf[i] = ',';
+			start = i;
+		}
+	}
+	return 0;
+}
+
+static int wfx_send_pdata_pds(struct wfx_dev *wdev)
+{
+	int ret = 0;
+	const struct firmware *pds;
+	unsigned char *tmp_buf;
+
+	ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev);
+	if (ret) {
+		dev_err(wdev->dev, "can't load PDS file %s\n", wdev->pdata.file_pds);
+		return ret;
+	}
+	tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL);
+	ret = wfx_send_pds(wdev, tmp_buf, pds->size);
+	kfree(tmp_buf);
+	release_firmware(pds);
+	return ret;
+}
+
 struct wfx_dev *wfx_init_common(struct device *dev,
 				const struct wfx_platform_data *pdata,
 				const struct hwbus_ops *hwbus_ops,
@@ -141,6 +208,8 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 	wdev->hwbus_ops = hwbus_ops;
 	wdev->hwbus_priv = hwbus_priv;
 	memcpy(&wdev->pdata, pdata, sizeof(*pdata));
+	of_property_read_string(dev->of_node, "config-file", &wdev->pdata.file_pds);
+	wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
 	wfx_fill_sl_key(dev, &wdev->pdata);
 
 	init_completion(&wdev->firmware_ready);
@@ -159,6 +228,12 @@ int wfx_probe(struct wfx_dev *wdev)
 	int i;
 	int err;
 	const void *macaddr;
+	struct gpio_desc *gpio_saved;
+
+	// During first part of boot, gpio_wakeup cannot yet been used. So
+	// prevent bh() to touch it.
+	gpio_saved = wdev->pdata.gpio_wakeup;
+	wdev->pdata.gpio_wakeup = NULL;
 
 	wfx_bh_register(wdev);
 
@@ -202,6 +277,24 @@ int wfx_probe(struct wfx_dev *wdev)
 		goto err1;
 	}
 
+	dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds);
+	err = wfx_send_pdata_pds(wdev);
+	if (err < 0)
+		goto err1;
+
+	wdev->pdata.gpio_wakeup = gpio_saved;
+	if (wdev->pdata.gpio_wakeup) {
+		dev_dbg(wdev->dev, "enable 'quiescent' power mode with gpio %d and PDS file %s\n",
+			desc_to_gpio(wdev->pdata.gpio_wakeup), wdev->pdata.file_pds);
+		gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+		control_reg_write(wdev, 0);
+		hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT);
+	} else {
+		hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE);
+	}
+
+	hif_use_multi_tx_conf(wdev, true);
+
 	for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
 		eth_zero_addr(wdev->addresses[i].addr);
 		macaddr = of_get_mac_address(wdev->dev->of_node);
@@ -232,6 +325,7 @@ int wfx_probe(struct wfx_dev *wdev)
 
 void wfx_release(struct wfx_dev *wdev)
 {
+	hif_shutdown(wdev);
 	wfx_bh_unregister(wdev);
 	wfx_sl_deinit(wdev);
 }
diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h
index 2c9c215455ce..f2b07ed1627c 100644
--- a/drivers/staging/wfx/main.h
+++ b/drivers/staging/wfx/main.h
@@ -21,6 +21,7 @@ struct wfx_dev;
 struct wfx_platform_data {
 	/* Keyset and ".sec" extention will appended to this string */
 	const char *file_fw;
+	const char *file_pds;
 	unsigned char slk_key[API_KEY_VALUE_SIZE];
 	struct gpio_desc *gpio_wakeup;
 	/*
@@ -42,5 +43,6 @@ void wfx_release(struct wfx_dev *wdev);
 struct gpio_desc *wfx_get_gpio(struct device *dev, int override,
 			       const char *label);
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor);
+int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len);
 
 #endif
-- 
2.20.1

WARNING: multiple messages have this Message-ID (diff)
From: Jerome Pouiller <Jerome.Pouiller@silabs.com>
To: "devel@driverdev.osuosl.org" <devel@driverdev.osuosl.org>,
	"linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>
Cc: "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	David Le Goff <David.Legoff@silabs.com>,
	"David S . Miller" <davem@davemloft.net>,
	Kalle Valo <kvalo@codeaurora.org>
Subject: [PATCH v3 14/20] staging: wfx: setup initial chip configuration
Date: Thu, 19 Sep 2019 14:25:44 +0000	[thread overview]
Message-ID: <20190919142527.31797-15-Jerome.Pouiller@silabs.com> (raw)
In-Reply-To: <20190919142527.31797-1-Jerome.Pouiller@silabs.com>

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

A few tasks remain to be done in order to finish chip initial
configuration:
   - configure chip to use multi-tx confirmation (speed up data
     transfer)
   - configure chip to use wake-up feature (save power consumption
     during runtime)
   - set hardware configuration (clocks, RF, pinout, etc...) using a
     Platform Data Set (PDS) file

On release, driver completely shutdown the chip to save power
consumption.

Documentation about PDS and PDS data for sample boards are available
here[1]. One day, PDS data may find a place in device tree but,
currently, PDS is too much linked with firmware to allowing that.

This patch also add "send_pds" file in debugfs to be able to dynamically
change PDS (only for debug, of course).

[1]: https://github.com/SiliconLabs/wfx-firmware/tree/master/PDS

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/staging/wfx/bus_sdio.c |  1 +
 drivers/staging/wfx/bus_spi.c  |  1 +
 drivers/staging/wfx/debug.c    | 29 +++++++++++
 drivers/staging/wfx/hif_rx.c   | 11 ++++
 drivers/staging/wfx/main.c     | 94 ++++++++++++++++++++++++++++++++++
 drivers/staging/wfx/main.h     |  2 +
 6 files changed, 138 insertions(+)

diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index c0c063c3cfc9..05f02c278782 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -19,6 +19,7 @@
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
 	.file_fw = "wfm_wf200",
+	.file_pds = "wf200.pds",
 };
 
 struct wfx_sdio_priv {
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index b7cd82b4e5e7..f65f7d75e731 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -29,6 +29,7 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for none.");
 
 static const struct wfx_platform_data wfx_spi_pdata = {
 	.file_fw = "wfm_wf200",
+	.file_pds = "wf200.pds",
 	.use_rising_clk = true,
 };
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f79693a4be7f..0619c7d1cf79 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -10,6 +10,7 @@
 
 #include "debug.h"
 #include "wfx.h"
+#include "main.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -54,6 +55,33 @@ const char *get_reg_name(unsigned long id)
 	return get_symbol(id, wfx_reg_print_map);
 }
 
+static ssize_t wfx_send_pds_write(struct file *file, const char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct wfx_dev *wdev = file->private_data;
+	char *buf;
+	int ret;
+
+	if (*ppos != 0) {
+		dev_dbg(wdev->dev, "PDS data must be written in one transaction");
+		return -EBUSY;
+	}
+	buf = memdup_user(user_buf, count);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+	*ppos = *ppos + count;
+	ret = wfx_send_pds(wdev, buf, count);
+	kfree(buf);
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+static const struct file_operations wfx_send_pds_fops = {
+	.open = simple_open,
+	.write = wfx_send_pds_write,
+};
+
 static ssize_t wfx_burn_slk_key_write(struct file *file,
 				      const char __user *user_buf,
 				      size_t count, loff_t *ppos)
@@ -162,6 +190,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
 	struct dentry *d;
 
 	d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+	debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops);
 	debugfs_create_file("burn_slk_key", 0200, d, wdev, &wfx_burn_slk_key_fops);
 	debugfs_create_file("send_hif_msg", 0600, d, wdev, &wfx_send_hif_msg_fops);
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index dd5f1dea4e85..6b9683d69a3f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -71,6 +71,16 @@ static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi
 	return 0;
 }
 
+static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
+{
+	if (!wdev->pdata.gpio_wakeup
+	    || !gpiod_get_value(wdev->pdata.gpio_wakeup)) {
+		dev_warn(wdev->dev, "unexpected wake-up indication\n");
+		return -EIO;
+	}
+	return 0;
+}
+
 static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
 {
 	struct hif_ind_sl_exchange_pub_keys *body = buf;
@@ -89,6 +99,7 @@ static const struct {
 	int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
 } hif_handlers[] = {
 	{ HIF_IND_ID_STARTUP,              hif_startup_indication },
+	{ HIF_IND_ID_WAKEUP,               hif_wakeup_indication },
 	{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
 };
 
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 0cfd6b2ec8d1..5b04ea5f4353 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -18,6 +18,7 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/spi/spi.h>
 #include <linux/etherdevice.h>
+#include <linux/firmware.h>
 
 #include "main.h"
 #include "wfx.h"
@@ -28,9 +29,12 @@
 #include "sta.h"
 #include "debug.h"
 #include "secure_link.h"
+#include "hif_tx_mib.h"
 #include "hif_api_cmd.h"
 #include "wfx_version.h"
 
+#define WFX_PDS_MAX_SIZE 1500
+
 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
 MODULE_AUTHOR("Jérôme Pouiller <jerome.pouiller@silabs.com>");
 MODULE_LICENSE("GPL");
@@ -112,6 +116,69 @@ static void wfx_fill_sl_key(struct device *dev, struct wfx_platform_data *pdata)
 	dev_err(dev, "secure link is not supported by this driver, ignoring provided key\n");
 }
 
+/* NOTE: wfx_send_pds() destroy buf */
+int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len)
+{
+	int ret;
+	int start, brace_level, i;
+
+	start = 0;
+	brace_level = 0;
+	if (buf[0] != '{') {
+		dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n");
+		return -EINVAL;
+	}
+	for (i = 1; i < len - 1; i++) {
+		if (buf[i] == '{')
+			brace_level++;
+		if (buf[i] == '}')
+			brace_level--;
+		if (buf[i] == '}' && !brace_level) {
+			i++;
+			if (i - start + 1 > WFX_PDS_MAX_SIZE)
+				return -EFBIG;
+			buf[start] = '{';
+			buf[i] = 0;
+			dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start);
+			buf[i] = '}';
+			ret = hif_configuration(wdev, buf + start, i - start + 1);
+			if (ret == HIF_STATUS_FAILURE) {
+				dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", start, i);
+				return -EINVAL;
+			}
+			if (ret == -ETIMEDOUT) {
+				dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", start, i);
+				return ret;
+			}
+			if (ret) {
+				dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", start, i);
+				return -EIO;
+			}
+			buf[i] = ',';
+			start = i;
+		}
+	}
+	return 0;
+}
+
+static int wfx_send_pdata_pds(struct wfx_dev *wdev)
+{
+	int ret = 0;
+	const struct firmware *pds;
+	unsigned char *tmp_buf;
+
+	ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev);
+	if (ret) {
+		dev_err(wdev->dev, "can't load PDS file %s\n", wdev->pdata.file_pds);
+		return ret;
+	}
+	tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL);
+	ret = wfx_send_pds(wdev, tmp_buf, pds->size);
+	kfree(tmp_buf);
+	release_firmware(pds);
+	return ret;
+}
+
 struct wfx_dev *wfx_init_common(struct device *dev,
 				const struct wfx_platform_data *pdata,
 				const struct hwbus_ops *hwbus_ops,
@@ -141,6 +208,8 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 	wdev->hwbus_ops = hwbus_ops;
 	wdev->hwbus_priv = hwbus_priv;
 	memcpy(&wdev->pdata, pdata, sizeof(*pdata));
+	of_property_read_string(dev->of_node, "config-file", &wdev->pdata.file_pds);
+	wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
 	wfx_fill_sl_key(dev, &wdev->pdata);
 
 	init_completion(&wdev->firmware_ready);
@@ -159,6 +228,12 @@ int wfx_probe(struct wfx_dev *wdev)
 	int i;
 	int err;
 	const void *macaddr;
+	struct gpio_desc *gpio_saved;
+
+	// During first part of boot, gpio_wakeup cannot yet been used. So
+	// prevent bh() to touch it.
+	gpio_saved = wdev->pdata.gpio_wakeup;
+	wdev->pdata.gpio_wakeup = NULL;
 
 	wfx_bh_register(wdev);
 
@@ -202,6 +277,24 @@ int wfx_probe(struct wfx_dev *wdev)
 		goto err1;
 	}
 
+	dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds);
+	err = wfx_send_pdata_pds(wdev);
+	if (err < 0)
+		goto err1;
+
+	wdev->pdata.gpio_wakeup = gpio_saved;
+	if (wdev->pdata.gpio_wakeup) {
+		dev_dbg(wdev->dev, "enable 'quiescent' power mode with gpio %d and PDS file %s\n",
+			desc_to_gpio(wdev->pdata.gpio_wakeup), wdev->pdata.file_pds);
+		gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+		control_reg_write(wdev, 0);
+		hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT);
+	} else {
+		hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE);
+	}
+
+	hif_use_multi_tx_conf(wdev, true);
+
 	for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
 		eth_zero_addr(wdev->addresses[i].addr);
 		macaddr = of_get_mac_address(wdev->dev->of_node);
@@ -232,6 +325,7 @@ int wfx_probe(struct wfx_dev *wdev)
 
 void wfx_release(struct wfx_dev *wdev)
 {
+	hif_shutdown(wdev);
 	wfx_bh_unregister(wdev);
 	wfx_sl_deinit(wdev);
 }
diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h
index 2c9c215455ce..f2b07ed1627c 100644
--- a/drivers/staging/wfx/main.h
+++ b/drivers/staging/wfx/main.h
@@ -21,6 +21,7 @@ struct wfx_dev;
 struct wfx_platform_data {
 	/* Keyset and ".sec" extention will appended to this string */
 	const char *file_fw;
+	const char *file_pds;
 	unsigned char slk_key[API_KEY_VALUE_SIZE];
 	struct gpio_desc *gpio_wakeup;
 	/*
@@ -42,5 +43,6 @@ void wfx_release(struct wfx_dev *wdev);
 struct gpio_desc *wfx_get_gpio(struct device *dev, int override,
 			       const char *label);
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor);
+int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len);
 
 #endif
-- 
2.20.1
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

  parent reply	other threads:[~2019-09-19 14:27 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-19 14:25 [PATCH v3 00/20] Add support for Silicon Labs WiFi chip WF200 and further Jerome Pouiller
2019-09-19 14:25 ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 01/20] staging: wfx: add infrastructure for new driver Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-10-04  8:23   ` Greg Kroah-Hartman
2019-10-04  8:23     ` Greg Kroah-Hartman
2019-09-19 14:25 ` [PATCH v3 02/20] staging: wfx: add support for I/O access Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 03/20] staging: wfx: add I/O API Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 05/20] staging: wfx: load firmware Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 04/20] staging: wfx: add tracepoints for I/O access Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 06/20] staging: wfx: import HIF API headers Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 07/20] staging: wfx: add IRQ handling Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 08/20] staging: wfx: add tracepoints for HIF Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 09/20] staging: wfx: add support for start-up indication Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 10/20] staging: wfx: instantiate mac80211 data Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 11/20] staging: wfx: allow to send commands to chip Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 12/20] staging: wfx: add HIF commands helpers Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 13/20] staging: wfx: introduce "secure link" Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` Jerome Pouiller [this message]
2019-09-19 14:25   ` [PATCH v3 14/20] staging: wfx: setup initial chip configuration Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 15/20] staging: wfx: add debug files and trace debug events Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 16/20] staging: wfx: allow to send 802.11 frames Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 17/20] staging: wfx: allow to receive " Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 18/20] staging: wfx: allow to scan networks Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 19/20] staging: wfx: implement 802.11 key handling Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:25 ` [PATCH v3 20/20] staging: wfx: implement the rest of mac80211 API Jerome Pouiller
2019-09-19 14:25   ` Jerome Pouiller
2019-09-19 14:41 ` [PATCH v3 00/20] Add support for Silicon Labs WiFi chip WF200 and further Greg Kroah-Hartman
2019-09-19 14:41   ` Greg Kroah-Hartman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190919142527.31797-15-Jerome.Pouiller@silabs.com \
    --to=jerome.pouiller@silabs.com \
    --cc=David.Legoff@silabs.com \
    --cc=davem@davemloft.net \
    --cc=devel@driverdev.osuosl.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=kvalo@codeaurora.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.