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: Liangwei Dong <liangwei@codeaurora.org>
This commit is contained in:
Liangwei Dong 2015-12-04 02:32:55 -05:00 committed by David Keitel
parent 1b10409872
commit fa7db29c1f
2 changed files with 258 additions and 8 deletions

View file

@ -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);

View file

@ -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_ */