Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4f60d81 authored by Liangwei Dong's avatar Liangwei Dong
Browse files

Net: CNSS_SDIO: add sdio wlan driver registration



Move sdio wlan func driver interface(includes Suspend
and Resume)registration from wlan cld driver to cnss_sdio
driver. wlan cld driver provides callback functions
to cnss_sdio driver by cnss_sdio_wlan_register_driver API.

CRs-Fixed: 944931
Change-Id: If9cec25024c5840e043fc652a7f0c7df4d83f4e9
Signed-off-by: default avatarLiangwei Dong <liangwei@codeaurora.org>
parent c9c17af0
Loading
Loading
Loading
Loading
+236 −5
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <net/cnss.h>

#define WLAN_VREG_NAME		"vdd-wlan"
#define WLAN_VREG_DSRC_NAME	"vdd-wlan-dsrc"
@@ -31,8 +34,6 @@
#define WLAN_VREG_XTAL_MIN	1800000
#define POWER_ON_DELAY		4

#define CNSS_MAX_CH_NUM 100

struct cnss_unsafe_channel_list {
	u16 unsafe_ch_count;
	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
@@ -50,13 +51,62 @@ struct cnss_sdio_regulator {
	struct regulator *wlan_vreg_dsrc;
};

struct cnss_sdio_info {
	struct cnss_sdio_wlan_driver *wdrv;
	struct sdio_func *func;
	const struct sdio_device_id *id;
};

static struct cnss_sdio_data {
	struct cnss_sdio_regulator regulator;
	struct platform_device *pdev;
	struct cnss_dfs_nol_info dfs_info;
	struct cnss_unsafe_channel_list unsafe_list;
	struct cnss_sdio_info cnss_sdio_info;
} *cnss_pdata;

/* SDIO manufacturer ID and Codes */
#define MANUFACTURER_ID_AR6320_BASE        0x500
#define MANUFACTURER_ID_QCA9377_BASE       0x700
#define MANUFACTURER_CODE                  0x271

static const struct sdio_device_id ar6k_id_table[] = {
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))},
	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))},
	{},
};
MODULE_DEVICE_TABLE(sdio, ar6k_id_table);

int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
{
	struct cnss_unsafe_channel_list *unsafe_list;
@@ -103,7 +153,7 @@ int cnss_get_wlan_unsafe_channel(
}
EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel);

int cnss_wlan_set_dfs_nol(void *info, u16 info_len)
int cnss_wlan_set_dfs_nol(const void *info, u16 info_len)
{
	void *temp;
	struct cnss_dfs_nol_info *dfs_info;
@@ -153,6 +203,176 @@ int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
}
EXPORT_SYMBOL(cnss_wlan_get_dfs_nol);

static int cnss_sdio_wlan_inserted(
				struct sdio_func *func,
				const struct sdio_device_id *id)
{
	if (!cnss_pdata)
		return -ENODEV;

	cnss_pdata->cnss_sdio_info.func = func;
	cnss_pdata->cnss_sdio_info.id = id;
	return 0;
}

static void cnss_sdio_wlan_removed(struct sdio_func *func)
{
	if (!cnss_pdata)
		return;

	cnss_pdata->cnss_sdio_info.func = NULL;
	cnss_pdata->cnss_sdio_info.id = NULL;
}

#if defined(CONFIG_PM)
static int cnss_sdio_wlan_suspend(struct device *dev)
{
	struct cnss_sdio_wlan_driver *wdrv;
	int error = 0;

	if (!cnss_pdata)
		return -ENODEV;

	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
	if (!wdrv) {
		/* This can happen when no wlan driver loaded (no register to
		 * platform driver).
		 */
		pr_debug("wlan driver not registered\n");
		return 0;
	}
	if (wdrv->suspend) {
		error = wdrv->suspend(dev);
		if (error)
			pr_err("wlan suspend failed error=%d\n", error);
	}

	return error;
}

static int cnss_sdio_wlan_resume(struct device *dev)
{
	struct cnss_sdio_wlan_driver *wdrv;
	int error = 0;

	if (!cnss_pdata)
		return -ENODEV;

	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
	if (!wdrv) {
		/* This can happen when no wlan driver loaded (no register to
		 * platform driver).
		 */
		pr_debug("wlan driver not registered\n");
		return 0;
	}
	if (wdrv->resume) {
		error = wdrv->resume(dev);
		if (error)
			pr_err("wlan resume failed error=%d\n", error);
	}
	return error;
}
#endif

#if defined(CONFIG_PM)
static const struct dev_pm_ops cnss_ar6k_device_pm_ops = {
	.suspend = cnss_sdio_wlan_suspend,
	.resume = cnss_sdio_wlan_resume,
};
#endif /* CONFIG_PM */

static const struct sdio_driver cnss_ar6k_driver = {
	.name = "cnss_ar6k_wlan",
	.id_table = ar6k_id_table,
	.probe = cnss_sdio_wlan_inserted,
	.remove = cnss_sdio_wlan_removed,
#if defined(CONFIG_PM)
	.drv = {
		.pm = &cnss_ar6k_device_pm_ops,
	}
#endif
};

/**
 * cnss_sdio_wlan_register_driver() - cnss wlan register API
 * @driver: sdio wlan driver interface from wlan driver.
 *
 * wlan sdio function driver uses this API to register callback
 * functions to cnss_sido platform driver. The callback will
 * be invoked by corresponding wrapper function of this cnss
 * platform driver.
 */
int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver)
{
	struct cnss_sdio_info *cnss_info;
	int error = 0;

	if (!cnss_pdata)
		return -ENODEV;

	cnss_info = &cnss_pdata->cnss_sdio_info;
	if (cnss_info->wdrv)
		pr_debug("%s:wdrv already exists wdrv(%p)\n", __func__,
			 cnss_info->wdrv);

	cnss_info->wdrv = driver;
	if (driver->probe) {
		error = driver->probe(cnss_info->func, cnss_info->id);
		if (error)
			pr_err("%s: wlan probe failed error=%d\n", __func__,
			       error);
	}
	return error;
}
EXPORT_SYMBOL(cnss_sdio_wlan_register_driver);

/**
 * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API
 * @driver: sdio wlan driver interface from wlan driver.
 *
 * wlan sdio function driver uses this API to detach it from cnss_sido
 * platform driver.
 */
void
cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver)
{
	struct cnss_sdio_info *cnss_info;

	if (!cnss_pdata)
		return;

	cnss_info = &cnss_pdata->cnss_sdio_info;
	if (!cnss_info->wdrv) {
		pr_err("%s: driver not registered\n", __func__);
		return;
	}
	if (cnss_info->wdrv->remove)
		cnss_info->wdrv->remove(cnss_info->func);
	cnss_info->wdrv = NULL;
}
EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver);

static int cnss_sdio_wlan_init(void)
{
	int error = 0;

	error = sdio_register_driver(&cnss_ar6k_driver);
	if (error)
		pr_err("%s: registered fail error=%d\n", __func__, error);
	else
		pr_debug("%s: registered succ\n", __func__);
	return error;
}

static void cnss_sdio_wlan_exit(void)
{
	if (!cnss_pdata)
		return;

	sdio_unregister_driver(&cnss_ar6k_driver);
}

static int cnss_sdio_configure_wlan_enable_regulator(void)
{
	int error;
@@ -318,7 +538,8 @@ static int cnss_sdio_probe(struct platform_device *pdev)
	cnss_pdata->pdev = pdev;
	error = cnss_sdio_configure_regulator();
	if (error) {
		dev_err(&pdev->dev, "Failed to config voltage regulator\n");
		dev_err(&pdev->dev, "Failed to configure voltage regulator error=%d\n",
			error);
		return error;
	}

@@ -328,7 +549,8 @@ static int cnss_sdio_probe(struct platform_device *pdev)
		error = cnss_sdio_configure_wlan_enable_regulator();
		if (error) {
			dev_err(&pdev->dev,
				"Failed to enable wlan enable regulator\n");
				"Failed to enable wlan enable regulator error=%d\n",
				error);
			goto err_wlan_enable_regulator;
		}
	}
@@ -344,6 +566,12 @@ static int cnss_sdio_probe(struct platform_device *pdev)
		}
	}

	error = cnss_sdio_wlan_init();
	if (error) {
		dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error);
		goto err_wlan_dsrc_enable_regulator;
	}

	dev_info(&pdev->dev, "CNSS SDIO Driver registered");
	return 0;

@@ -352,6 +580,7 @@ err_wlan_dsrc_enable_regulator:
err_wlan_enable_regulator:
	regulator_put(cnss_pdata->regulator.wlan_xtal);
	regulator_put(cnss_pdata->regulator.wlan_io);
	cnss_pdata = NULL;
	return error;
}

@@ -362,6 +591,8 @@ static int cnss_sdio_remove(struct platform_device *pdev)
	if (!cnss_pdata)
		return -ENODEV;

	cnss_sdio_wlan_exit();

	dfs_info = &cnss_pdata->dfs_info;
	kfree(dfs_info->dfs_nol_info);

+22 −3
Original line number Diff line number Diff line
@@ -15,11 +15,11 @@
#include <linux/device.h>
#include <linux/skbuff.h>
#include <linux/pci.h>
#ifdef CONFIG_CNSS_SDIO
#include <linux/mmc/sdio_func.h>
#endif

#ifdef CONFIG_CNSS
/* max 20mhz channel count */
#define CNSS_MAX_CH_NUM       45

#define CNSS_MAX_FILE_NAME	  20

#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
@@ -165,6 +165,9 @@ extern int cnss_is_auto_suspend_allowed(const char *caller_func);
extern int cnss_pm_runtime_request(struct device *dev, enum
		cnss_runtime_request request);
#endif
/* max 20mhz channel count */
#define CNSS_MAX_CH_NUM       45

extern void cnss_init_work(struct work_struct *work, work_func_t func);
extern void cnss_flush_work(void *work);
extern void cnss_flush_delayed_work(void *dwork);
@@ -185,4 +188,20 @@ extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
		u16 *ch_count, u16 buf_len);
extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);

#ifdef CONFIG_CNSS_SDIO
struct cnss_sdio_wlan_driver {
	const char *name;
	const struct sdio_device_id *id_table;
	int (*probe)(struct sdio_func *, const struct sdio_device_id *);
	void (*remove)(struct sdio_func *);
	int (*suspend)(struct device *);
	int (*resume)(struct device *);
};

extern int cnss_sdio_wlan_register_driver(
	struct cnss_sdio_wlan_driver *driver);
extern void cnss_sdio_wlan_unregister_driver(
	struct cnss_sdio_wlan_driver *driver);
#endif
#endif /* _NET_CNSS_H_ */