/*
|
* Copyright (C) 2017 Spreadtrum Communications Inc.
|
*
|
* This software is licensed under the terms of the GNU General Public
|
* License version 2, as published by the Free Software Foundation, and
|
* may be copied, distributed, and modified under those terms.
|
*
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
*/
|
#include "wcn_glb.h"
|
#include "wcn_glb_reg.h"
|
#include "wcn_procfs.h"
|
|
#define WCN_CLK_EN 0xc0
|
#define WCN_LDO_EN 0x1000
|
#define WCN_FASTCHARGE_EN 0x100
|
|
#define MARLIN_USE_FORCE_SHUTDOWN (0xabcd250)
|
#define MARLIN_FORCE_SHUTDOWN_OK (0x6B6B6B6B)
|
|
static int wcn_open_module;
|
static int wcn_module_state_change;
|
char functionmask[8];
|
marlin_reset_callback marlin_reset_func;
|
void *marlin_callback_para;
|
struct platform_chip_id g_platform_chip_id;
|
static u32 g_platform_chip_type;
|
static const struct wcn_chip_type wcn_chip_type[] = {
|
{0x96360000, WCN_SHARKLE_CHIP_AA_OR_AB},
|
{0x96360002, WCN_SHARKLE_CHIP_AC},
|
{0x96360003, WCN_SHARKLE_CHIP_AD},
|
/* WCN_PIKE2_CHIP_AA and WCN_PIKE2_CHIP_AB is the same */
|
{0x96330000, WCN_PIKE2_CHIP},
|
};
|
|
struct wcn_special_share_mem *s_wssm_phy_offset_p =
|
(struct wcn_special_share_mem *)WCN_SPECIAL_SHARME_MEM_ADDR;
|
|
enum wcn_aon_chip_id wcn_get_aon_chip_id(void)
|
{
|
u32 aon_chip_id;
|
u32 version_id;
|
int i;
|
struct regmap *regmap;
|
|
if (unlikely(!s_wcn_device.btwf_device))
|
return WCN_AON_CHIP_ID_INVALID;
|
|
regmap = wcn_get_btwf_regmap(REGMAP_AON_APB);
|
wcn_regmap_read(regmap, WCN_AON_CHIP_ID, &aon_chip_id);
|
WCN_INFO("aon_chip_id=0x%08x\n", aon_chip_id);
|
for (i = 0; i < ARRAY_SIZE(wcn_chip_type); i++) {
|
if (wcn_chip_type[i].chipid == aon_chip_id) {
|
if (wcn_chip_type[i].chiptype != WCN_PIKE2_CHIP)
|
return wcn_chip_type[i].chiptype;
|
wcn_regmap_read(regmap, WCN_AON_VERSION_ID,
|
&version_id);
|
WCN_INFO("aon_version_id=0x%08x\n", version_id);
|
/* version_id:
|
* 0 for WCN_PIKE2_CHIP_AA
|
* others for WCN_PIKE2_CHIP_AB
|
*/
|
return (version_id == 0) ?
|
WCN_PIKE2_CHIP_AA : WCN_PIKE2_CHIP_AB;
|
}
|
}
|
|
return WCN_AON_CHIP_ID_INVALID;
|
}
|
EXPORT_SYMBOL_GPL(wcn_get_aon_chip_id);
|
|
#define WCN_VMAP_RETRY_CNT (20)
|
static void *wcn_mem_ram_vmap(phys_addr_t start, size_t size,
|
int noncached, unsigned int *count)
|
{
|
struct page **pages;
|
phys_addr_t page_start;
|
unsigned int page_count;
|
pgprot_t prot;
|
unsigned int i;
|
void *vaddr;
|
phys_addr_t addr;
|
int retry = 0;
|
|
page_start = start - offset_in_page(start);
|
page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
|
*count = page_count;
|
if (noncached)
|
prot = pgprot_noncached(PAGE_KERNEL);
|
else
|
prot = PAGE_KERNEL;
|
|
retry1:
|
pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
|
if (!pages) {
|
if (retry++ < WCN_VMAP_RETRY_CNT) {
|
usleep_range(8000, 10000);
|
goto retry1;
|
} else {
|
WCN_ERR("malloc err\n");
|
return NULL;
|
}
|
}
|
|
for (i = 0; i < page_count; i++) {
|
addr = page_start + i * PAGE_SIZE;
|
pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
|
}
|
retry2:
|
vaddr = vm_map_ram(pages, page_count, -1, prot);
|
if (!vaddr) {
|
if (retry++ < WCN_VMAP_RETRY_CNT) {
|
usleep_range(8000, 10000);
|
goto retry2;
|
} else {
|
WCN_ERR("vmap err\n");
|
goto out;
|
}
|
} else {
|
vaddr += offset_in_page(start);
|
}
|
out:
|
kfree(pages);
|
|
return vaddr;
|
}
|
|
void wcn_mem_ram_unmap(const void *mem, unsigned int count)
|
{
|
vm_unmap_ram(mem - offset_in_page(mem), count);
|
}
|
|
void *wcn_mem_ram_vmap_nocache(phys_addr_t start, size_t size,
|
unsigned int *count)
|
{
|
return wcn_mem_ram_vmap(start, size, 1, count);
|
}
|
|
int wcn_write_data_to_phy_addr(phys_addr_t phy_addr,
|
void *src_data, u32 size)
|
{
|
int i;
|
char *virt_addr, *src;
|
unsigned int cnt;
|
|
src = (char *)src_data;
|
virt_addr = (char *)wcn_mem_ram_vmap_nocache(phy_addr, size, &cnt);
|
if (virt_addr) {
|
/* crash so remove the memcpy */
|
for (i = 0; i < size; i++)
|
virt_addr[i] = src[i];
|
wcn_mem_ram_unmap(virt_addr, cnt);
|
return 0;
|
}
|
|
WCN_ERR("wcn_mem_ram_vmap_nocache fail\n");
|
return -1;
|
}
|
|
int wcn_read_data_from_phy_addr(phys_addr_t phy_addr,
|
void *tar_data, u32 size)
|
{
|
int i;
|
char *virt_addr, *tar;
|
unsigned int cnt;
|
|
tar = (char *)tar_data;
|
virt_addr = wcn_mem_ram_vmap_nocache(phy_addr, size, &cnt);
|
if (virt_addr) {
|
/* crash so remove the memcpy */
|
for (i = 0; i < size; i++)
|
tar[i] = virt_addr[i];
|
wcn_mem_ram_unmap(virt_addr, cnt);
|
return 0;
|
}
|
|
WCN_ERR("wcn_mem_ram_vmap_nocache fail\n");
|
return -1;
|
}
|
|
u32 wcn_platform_chip_id(void)
|
{
|
return g_platform_chip_id.aon_chip_id;
|
}
|
|
u32 wcn_platform_chip_type(void)
|
{
|
return g_platform_chip_type;
|
}
|
|
u32 wcn_get_cp2_comm_rx_count(void)
|
{
|
u32 rx_count;
|
phys_addr_t phy_addr;
|
|
phy_addr = s_wcn_device.btwf_device->base_addr +
|
(phys_addr_t)&s_wssm_phy_offset_p->marlin.loopcheck_cnt;
|
wcn_read_data_from_phy_addr(phy_addr,
|
&rx_count, sizeof(u32));
|
WCN_INFO("cp2 comm rx count :%d\n", rx_count);
|
|
return rx_count;
|
}
|
|
phys_addr_t wcn_get_btwf_base_addr(void)
|
{
|
return s_wcn_device.btwf_device->base_addr;
|
}
|
|
int wcn_get_btwf_power_status(void)
|
{
|
WCN_INFO("btwf_device power_state:%d\n",
|
s_wcn_device.btwf_device->power_state);
|
return s_wcn_device.btwf_device->power_state;
|
}
|
|
phys_addr_t wcn_get_btwf_init_status_addr(void)
|
{
|
return s_wcn_device.btwf_device->base_addr +
|
(phys_addr_t)&s_wssm_phy_offset_p->marlin.init_status;
|
}
|
|
phys_addr_t wcn_get_btwf_sleep_addr(void)
|
{
|
return s_wcn_device.btwf_device->base_addr +
|
(phys_addr_t)&s_wssm_phy_offset_p->cp2_sleep_status;
|
}
|
|
struct regmap *wcn_get_btwf_regmap(u32 regmap_type)
|
{
|
return s_wcn_device.btwf_device->rmap[regmap_type];
|
}
|
|
struct regmap *wcn_get_gnss_regmap(u32 regmap_type)
|
{
|
return s_wcn_device.gnss_device->rmap[regmap_type];
|
}
|
|
phys_addr_t wcn_get_gnss_base_addr(void)
|
{
|
return s_wcn_device.gnss_device->base_addr;
|
}
|
|
bool wcn_get_download_status(void)
|
{
|
return s_wcn_device.btwf_device->download_status;
|
}
|
|
void wcn_set_download_status(bool status)
|
{
|
s_wcn_device.btwf_device->download_status = status;
|
}
|
|
u32 gnss_get_boot_status(void)
|
{
|
return s_wcn_device.gnss_device->boot_cp_status;
|
}
|
|
void gnss_set_boot_status(u32 status)
|
{
|
s_wcn_device.gnss_device->boot_cp_status = status;
|
}
|
|
int wcn_get_module_status_changed(void)
|
{
|
return wcn_module_state_change;
|
}
|
EXPORT_SYMBOL_GPL(wcn_get_module_status_changed);
|
|
void wcn_set_module_status_changed(bool status)
|
{
|
wcn_module_state_change = status;
|
}
|
|
int marlin_get_module_status(void)
|
{
|
return wcn_open_module;
|
}
|
EXPORT_SYMBOL_GPL(marlin_get_module_status);
|
|
int marlin_reset_register_notify(void *callback_func, void *para)
|
{
|
marlin_reset_func = (marlin_reset_callback)callback_func;
|
marlin_callback_para = para;
|
|
return 0;
|
}
|
EXPORT_SYMBOL_GPL(marlin_reset_register_notify);
|
|
int marlin_reset_unregister_notify(void)
|
{
|
marlin_reset_func = NULL;
|
marlin_callback_para = NULL;
|
|
return 0;
|
}
|
EXPORT_SYMBOL_GPL(marlin_reset_unregister_notify);
|
|
void wcn_set_module_state(bool status)
|
{
|
if (s_wcn_device.btwf_device->wcn_open_status & WCN_MARLIN_MASK)
|
wcn_open_module = 1;
|
else
|
wcn_open_module = 0;
|
wcn_module_state_change = 1;
|
if (status)
|
loopcheck_first_boot_set();
|
wcn_set_download_status(status);
|
WCN_INFO("cp2 power status:%d\n", status);
|
wakeup_loopcheck_int();
|
}
|
|
|
#if REGMAP_UPDATE_BITS_ENABLE
|
static void wcn_regmap_update_bit(struct wcn_device *ctrl,
|
u32 index,
|
u32 mask,
|
u32 val)
|
{
|
u32 type;
|
u32 reg;
|
int ret;
|
|
type = ctrl->ctrl_type[index];
|
reg = ctrl->ctrl_reg[index];
|
|
ret = regmap_update_bits(ctrl->rmap[type],
|
reg,
|
mask,
|
val);
|
if (ret)
|
WCN_ERR("regmap_update_bits ret=%d\n", ret);
|
}
|
|
static void wcn_regmap_write_bit(struct wcn_device *ctrl,
|
u32 index,
|
u32 mask,
|
u32 val)
|
{
|
u32 type;
|
u32 reg;
|
int ret;
|
|
type = ctrl->ctrl_type[index];
|
reg = ctrl->ctrl_reg[index];
|
|
ret = regmap_write_bits(ctrl->rmap[type],
|
reg,
|
mask,
|
val);
|
if (ret)
|
WCN_ERR("regmap_write_bits ret=%d\n", ret);
|
}
|
#endif
|
|
void wcn_regmap_raw_write_bit(struct regmap *cur_regmap,
|
u32 reg,
|
unsigned int val)
|
{
|
int ret;
|
u32 val_tmp = val;
|
|
ret = regmap_raw_write(cur_regmap, reg, (const void *)&val_tmp, 4);
|
if (ret)
|
WCN_ERR("regmap_raw_write ret=%d\n", ret);
|
}
|
|
/* addr_offset:some REGs has twice group, one read and another write */
|
void wcn_regmap_read(struct regmap *cur_regmap,
|
u32 reg,
|
unsigned int *val)
|
{
|
(void)regmap_read(cur_regmap, reg, val);
|
}
|
|
/* return val: 1 for send the cmd to CP2 */
|
int wcn_send_force_sleep_cmd(struct wcn_device *wcn_dev)
|
{
|
u32 val;
|
phys_addr_t phy_addr;
|
|
phy_addr = wcn_dev->base_addr +
|
(phys_addr_t)&s_wssm_phy_offset_p->sleep_flag_addr;
|
wcn_read_data_from_phy_addr(phy_addr, &val, sizeof(val));
|
if (val == MARLIN_USE_FORCE_SHUTDOWN) {
|
mdbg_send("at+sleep_switch=2\r",
|
strlen("at+sleep_switch=2\r"), MDBG_SUBTYPE_AT);
|
WCN_INFO("send sleep_switch=2\n");
|
return 1;
|
}
|
|
return 0;
|
}
|
|
/*
|
* WCN SYS include BTWF and GNSS sys, ret: 0 is sleep, else is not
|
* force_sleep: 0 for old way, others for send CP2 shutdown cmd way.
|
*/
|
u32 wcn_get_sleep_status(struct wcn_device *wcn_dev, int force_sleep)
|
{
|
u32 sleep_status = 0;
|
u32 wcn_sleep_status_mask = 0xf000;
|
u32 val;
|
phys_addr_t phy_addr;
|
|
if (wcn_dev_is_marlin(wcn_dev) && force_sleep) {
|
phy_addr = wcn_dev->base_addr +
|
(phys_addr_t)&s_wssm_phy_offset_p->cp2_sleep_status;
|
wcn_read_data_from_phy_addr(phy_addr, &val, sizeof(val));
|
WCN_INFO("foce shut down val:0x%x\n", val);
|
if (val == MARLIN_FORCE_SHUTDOWN_OK) {
|
usleep_range(10000, 12000);
|
return 0;
|
}
|
return 1;
|
}
|
|
wcn_regmap_read(wcn_dev->rmap[REGMAP_PMU_APB],
|
0xd4, &sleep_status);
|
|
return (sleep_status & wcn_sleep_status_mask);
|
}
|
|
void wcn_power_domain_set(struct wcn_device *wcn_dev, u32 set_type)
|
{
|
u32 offset0 = 0, offset1 = 0;
|
u32 bitmap0 = 0, bitmap1 = 0;
|
|
if (wcn_platform_chip_type() == WCN_PLATFORM_TYPE_PIKE2) {
|
if (set_type == 1) {
|
offset0 = 0X2050;
|
offset1 = 0X1050;
|
bitmap0 = 1 << 24;
|
bitmap1 = 1 << 25;
|
} else {
|
offset0 = 0X2050;
|
offset1 = 0X2050;
|
bitmap0 = 1 << 24;
|
bitmap1 = 1 << 25;
|
}
|
} else {
|
if (set_type == 1) {
|
offset0 = 0X2100;
|
offset1 = 0X1100;
|
bitmap0 = 1 << 24;
|
bitmap1 = 1 << 25;
|
} else {
|
offset0 = 0X2100;
|
offset1 = 0X2100;
|
bitmap0 = 1 << 24;
|
bitmap1 = 1 << 25;
|
}
|
}
|
wcn_regmap_raw_write_bit(wcn_dev->rmap[REGMAP_PMU_APB],
|
offset0, bitmap0);
|
wcn_regmap_raw_write_bit(wcn_dev->rmap[REGMAP_PMU_APB],
|
offset1, bitmap1);
|
}
|
|
void wcn_xtl_auto_sel(bool enable)
|
{
|
struct regmap *regmap;
|
u32 value;
|
|
regmap = wcn_get_btwf_regmap(REGMAP_PMU_APB);
|
wcn_regmap_read(regmap, 0x338, &value);
|
|
if (enable) {
|
value |= 1 << 4;
|
wcn_regmap_raw_write_bit(regmap, 0x338, value);
|
} else {
|
value &= ~(1 << 4);
|
wcn_regmap_raw_write_bit(regmap, 0X338, value);
|
}
|
}
|
|
int wcn_power_enable_sys_domain(bool enable)
|
{
|
int ret = 0;
|
u32 btwf_open = false;
|
u32 gnss_open = false;
|
static u32 sys_domain;
|
|
if (s_wcn_device.btwf_device &&
|
s_wcn_device.btwf_device->wcn_open_status & WCN_MARLIN_MASK)
|
btwf_open = true;
|
if (s_wcn_device.gnss_device &&
|
s_wcn_device.gnss_device->wcn_open_status & WCN_GNSS_ALL_MASK)
|
gnss_open = true;
|
|
if (enable && (sys_domain == false)) {
|
if (wcn_platform_chip_type() == WCN_PLATFORM_TYPE_PIKE2)
|
wcn_xtl_auto_sel(false);
|
wcn_power_domain_set(s_wcn_device.btwf_device, 0);
|
if (wcn_platform_chip_type() == WCN_PLATFORM_TYPE_PIKE2)
|
wcn_xtl_auto_sel(true);
|
sys_domain = true;
|
WCN_INFO("clear WCN SYS TOP PD\n");
|
} else if ((!btwf_open) && (!gnss_open) && sys_domain) {
|
if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_PIKE2)
|
wcn_xtl_auto_sel(false);
|
wcn_power_domain_set(s_wcn_device.btwf_device, 1);
|
sys_domain = false;
|
WCN_INFO("set WCN SYS TOP PD\n");
|
}
|
WCN_INFO("enable = %d, ret = %d, btwf_open=%d, gnss_open=%d\n",
|
enable, ret, btwf_open, gnss_open);
|
|
return ret;
|
}
|
|
#define WCN_CP_SOFT_RST_MIN_TIME (5000) /* us */
|
#define WCN_CP_SOFT_RST_MAX_TIME (6000) /* us */
|
|
/*
|
* wcn_sys_soft_reset was used by BTWF and GNSS together
|
* both BTWF and GNSS not work, we should set it.
|
*/
|
void wcn_sys_soft_reset(void)
|
{
|
u32 offset;
|
u32 bitmap;
|
u32 btwf_open = false;
|
u32 gnss_open = false;
|
struct wcn_device *wcn_dev;
|
|
wcn_dev = s_wcn_device.btwf_device ?
|
s_wcn_device.btwf_device : s_wcn_device.gnss_device;
|
if (!wcn_dev)
|
return;
|
|
if (s_wcn_device.btwf_device &&
|
s_wcn_device.btwf_device->wcn_open_status)
|
btwf_open = true;
|
if (s_wcn_device.gnss_device &&
|
s_wcn_device.gnss_device->wcn_open_status)
|
gnss_open = true;
|
|
if (!btwf_open && !gnss_open) {
|
if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_PIKE2) {
|
bitmap = 1 << 7;
|
} else if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKLE) {
|
bitmap = 1 << 9;
|
} else if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKL3) {
|
bitmap = 1 << 16;
|
} else {
|
WCN_ERR("chip type err\n");
|
return;
|
}
|
offset = 0X10b0;
|
wcn_regmap_raw_write_bit(wcn_dev->rmap[REGMAP_PMU_APB],
|
offset, bitmap);
|
WCN_INFO("finish\n");
|
usleep_range(WCN_CP_SOFT_RST_MIN_TIME,
|
WCN_CP_SOFT_RST_MAX_TIME);
|
}
|
}
|
|
void wcn_sys_ctrl_26m(bool enable)
|
{
|
struct regmap *regmap;
|
u32 value;
|
|
regmap = wcn_get_btwf_regmap(REGMAP_ANLG_PHY_G6);
|
wcn_regmap_read(regmap, 0x28, &value);
|
|
if (enable) {
|
value &= ~(1 << 2);
|
wcn_regmap_raw_write_bit(regmap, 0X28, value);
|
} else {
|
value |= 1 << 2;
|
wcn_regmap_raw_write_bit(regmap, 0X28, value);
|
}
|
}
|
|
void wcn_clock_ctrl(bool enable)
|
{
|
struct regmap *regmap;
|
u32 value;
|
|
regmap = wcn_get_btwf_regmap(REGMAP_ANLG_PHY_G5);
|
if (IS_ERR(regmap)) {
|
WCN_ERR("failed to get REGMAP_ANLG_PHY_G5\n");
|
return;
|
}
|
if (enable) {
|
value = WCN_LDO_EN;
|
wcn_regmap_raw_write_bit(regmap, 0x1044, value);
|
value = WCN_FASTCHARGE_EN;
|
wcn_regmap_raw_write_bit(regmap, 0x1044, value);
|
usleep_range(10, 20);
|
wcn_regmap_raw_write_bit(regmap, 0x2044, value);
|
value = WCN_CLK_EN;
|
wcn_regmap_raw_write_bit(regmap, 0x1044, value);
|
} else {
|
value = WCN_CLK_EN;
|
wcn_regmap_raw_write_bit(regmap, 0x2044, value);
|
value = WCN_LDO_EN;
|
wcn_regmap_raw_write_bit(regmap, 0x2044, value);
|
}
|
}
|
|
/*
|
* wcn_sys_soft_release was used by BTWF and GNSS together
|
* both BTWF and GNSS not work, we should set it.
|
*/
|
void wcn_sys_soft_release(void)
|
{
|
u32 offset;
|
u32 bitmap;
|
u32 btwf_open = false;
|
u32 gnss_open = false;
|
struct wcn_device *wcn_dev;
|
|
wcn_dev = s_wcn_device.btwf_device ?
|
s_wcn_device.btwf_device : s_wcn_device.gnss_device;
|
if (!wcn_dev)
|
return;
|
|
if (s_wcn_device.btwf_device &&
|
s_wcn_device.btwf_device->wcn_open_status)
|
btwf_open = true;
|
if (s_wcn_device.gnss_device &&
|
s_wcn_device.gnss_device->wcn_open_status)
|
gnss_open = true;
|
|
if (!btwf_open && !gnss_open) {
|
if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_PIKE2) {
|
bitmap = 1 << 7;
|
} else if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKLE) {
|
bitmap = 1 << 9;
|
} else if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKL3) {
|
bitmap = 1 << 16;
|
} else {
|
WCN_ERR("chip type err\n");
|
return;
|
}
|
offset = 0X20b0;
|
wcn_regmap_raw_write_bit(wcn_dev->rmap[REGMAP_PMU_APB],
|
offset, bitmap);
|
WCN_INFO("finish!\n");
|
usleep_range(WCN_CP_SOFT_RST_MIN_TIME,
|
WCN_CP_SOFT_RST_MAX_TIME);
|
}
|
}
|
|
/*
|
* wcn_sys_deep_sleep_en was used by BTWF and GNSS together
|
* both BTWF and GNSS not work, we should set it.
|
*/
|
void wcn_sys_deep_sleep_en(void)
|
{
|
struct regmap *rmap = NULL;
|
|
if (wcn_platform_chip_type() != WCN_PLATFORM_TYPE_PIKE2) {
|
if (s_wcn_device.btwf_device) {
|
rmap = s_wcn_device.btwf_device->rmap[REGMAP_PMU_APB];
|
} else if (s_wcn_device.gnss_device) {
|
rmap = s_wcn_device.gnss_device->rmap[REGMAP_PMU_APB];
|
} else {
|
WCN_ERR("no devices\n");
|
return;
|
}
|
wcn_regmap_raw_write_bit(rmap, 0x1244, 1 << 0);
|
WCN_INFO("finish!\n");
|
}
|
}
|
|
/* The VDDCON default value is 1.6V, we should set it to 1.2v */
|
void wcn_power_set_vddcon(u32 value)
|
{
|
if (s_wcn_device.vddwcn != NULL)
|
regulator_set_voltage(s_wcn_device.vddwcn,
|
value, value);
|
}
|
|
/*
|
* NOTES:regulator function has compute-counter
|
* We needn't judge GNSS and BTWF coxist case now.
|
* But we should reserve the open status to debug.
|
*/
|
int wcn_power_enable_vddcon(bool enable)
|
{
|
int ret = 0;
|
u32 btwf_open = false;
|
u32 gnss_open = false;
|
|
if (s_wcn_device.btwf_device &&
|
s_wcn_device.btwf_device->wcn_open_status & WCN_MARLIN_MASK)
|
btwf_open = true;
|
if (s_wcn_device.gnss_device &&
|
s_wcn_device.gnss_device->wcn_open_status & WCN_GNSS_ALL_MASK)
|
gnss_open = true;
|
|
mutex_lock(&(s_wcn_device.vddwcn_lock));
|
if (s_wcn_device.vddwcn != NULL) {
|
if (enable) {
|
ret = regulator_enable(s_wcn_device.vddwcn);
|
s_wcn_device.vddwcn_en_count++;
|
if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKLE)
|
wcn_sys_ctrl_26m(true);
|
if (wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKL3)
|
wcn_clock_ctrl(true);
|
} else if (regulator_is_enabled(s_wcn_device.vddwcn)) {
|
ret = regulator_disable(s_wcn_device.vddwcn);
|
s_wcn_device.vddwcn_en_count--;
|
if ((wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKLE)
|
&& (s_wcn_device.vddwcn_en_count == 0)) {
|
wcn_sys_ctrl_26m(false);
|
}
|
if ((wcn_platform_chip_type() ==
|
WCN_PLATFORM_TYPE_SHARKL3) &&
|
(s_wcn_device.vddwcn_en_count == 0)) {
|
wcn_clock_ctrl(false);
|
}
|
}
|
|
WCN_INFO("enable=%d,en_count=%d,ret=%d,btwf=%d,gnss=%d\n",
|
enable, s_wcn_device.vddwcn_en_count,
|
ret, btwf_open, gnss_open);
|
if (s_wcn_device.vddwcn_en_count > 2 ||
|
s_wcn_device.vddwcn_en_count < 0)
|
WCN_ERR("vddwcn_en_count=%d",
|
s_wcn_device.vddwcn_en_count);
|
}
|
mutex_unlock(&(s_wcn_device.vddwcn_lock));
|
|
return ret;
|
}
|
|
/* The VDDCON default value is 1.6V, we should set it to 1.2v */
|
void wcn_power_set_vddwifipa(u32 value)
|
{
|
struct wcn_device *btwf_device = s_wcn_device.btwf_device;
|
|
if (btwf_device->vddwifipa != NULL)
|
regulator_set_voltage(btwf_device->vddwifipa,
|
value, value);
|
WCN_INFO("value %d\n", value);
|
}
|
|
/* NOTES: wifipa: only used by WIFI module */
|
int wcn_marlin_power_enable_vddwifipa(bool enable)
|
{
|
int ret = 0;
|
struct wcn_device *btwf_device = s_wcn_device.btwf_device;
|
|
mutex_lock(&(btwf_device->vddwifipa_lock));
|
if (btwf_device->vddwifipa != NULL) {
|
if (enable)
|
ret = regulator_enable(btwf_device->vddwifipa);
|
else if (regulator_is_enabled(btwf_device->vddwifipa))
|
ret = regulator_disable(btwf_device->vddwifipa);
|
|
WCN_INFO("enable = %d, ret = %d\n", enable, ret);
|
}
|
mutex_unlock(&(btwf_device->vddwifipa_lock));
|
|
return ret;
|
}
|
|
u32 wcn_parse_platform_chip_id(struct wcn_device *wcn_dev)
|
{
|
wcn_regmap_read(wcn_dev->rmap[REGMAP_AON_APB],
|
WCN_AON_CHIP_ID0,
|
&g_platform_chip_id.aon_chip_id0);
|
wcn_regmap_read(wcn_dev->rmap[REGMAP_AON_APB],
|
WCN_AON_CHIP_ID1,
|
&g_platform_chip_id.aon_chip_id1);
|
wcn_regmap_read(wcn_dev->rmap[REGMAP_AON_APB],
|
WCN_AON_PLATFORM_ID0,
|
&g_platform_chip_id.aon_platform_id0);
|
wcn_regmap_read(wcn_dev->rmap[REGMAP_AON_APB],
|
WCN_AON_PLATFORM_ID1,
|
&g_platform_chip_id.aon_platform_id1);
|
wcn_regmap_read(wcn_dev->rmap[REGMAP_AON_APB],
|
WCN_AON_CHIP_ID,
|
&g_platform_chip_id.aon_chip_id);
|
|
if (g_platform_chip_id.aon_chip_id0 == PIKE2_CHIP_ID0 &&
|
g_platform_chip_id.aon_chip_id1 == PIKE2_CHIP_ID1)
|
g_platform_chip_type = WCN_PLATFORM_TYPE_PIKE2;
|
else if (g_platform_chip_id.aon_chip_id0 == SHARKLE_CHIP_ID0 &&
|
g_platform_chip_id.aon_chip_id1 == SHARKLE_CHIP_ID1)
|
g_platform_chip_type = WCN_PLATFORM_TYPE_SHARKLE;
|
else if (g_platform_chip_id.aon_chip_id0 == SHARKL3_CHIP_ID0 &&
|
g_platform_chip_id.aon_chip_id1 == SHARKL3_CHIP_ID1)
|
g_platform_chip_type = WCN_PLATFORM_TYPE_SHARKL3;
|
else
|
WCN_ERR("aon_chip_id0:[%d],id1[%d]\n",
|
g_platform_chip_id.aon_chip_id0,
|
g_platform_chip_id.aon_chip_id1);
|
|
WCN_INFO("platform chip type: [%d]\n",
|
g_platform_chip_type);
|
|
return 0;
|
}
|
|
void mdbg_hold_cpu(void)
|
{
|
struct regmap *regmap;
|
u32 value;
|
phys_addr_t init_addr;
|
|
if (wcn_platform_chip_type() == WCN_PLATFORM_TYPE_SHARKL3)
|
regmap = wcn_get_btwf_regmap(REGMAP_WCN_REG);
|
else
|
regmap = wcn_get_btwf_regmap(REGMAP_ANLG_WRAP_WCN);
|
wcn_regmap_read(regmap, 0X20, &value);
|
value |= 1 << 3;
|
wcn_regmap_raw_write_bit(regmap, 0X20, value);
|
|
wcn_regmap_read(regmap, 0X24, &value);
|
value |= 1 << 2;
|
wcn_regmap_raw_write_bit(regmap, 0X24, value);
|
|
value = MDBG_CACHE_FLAG_VALUE;
|
init_addr = wcn_get_btwf_init_status_addr();
|
wcn_write_data_to_phy_addr(init_addr, (void *)&value, 4);
|
value = 0;
|
wcn_regmap_raw_write_bit(regmap, 0X20, value);
|
wcn_regmap_raw_write_bit(regmap, 0X24, value);
|
msleep(200);
|
}
|