6db4831e98
Android 14
1163 lines
28 KiB
C
1163 lines
28 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
* Author: owen.chen <owen.chen@mediatek.com>
|
|
*/
|
|
|
|
/*
|
|
* @file mtk-srclken-rc-hw.c
|
|
* @brief Driver for clock buffer control of each platform
|
|
*
|
|
*/
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/kobject.h>
|
|
|
|
#include <mtk-srclken-bridge.h>
|
|
#include <mtk-srclken-rc-hw.h>
|
|
#include <mtk-srclken-rc-common.h>
|
|
#include <mtk-clkbuf-bridge.h>
|
|
|
|
#define ADDR_NOT_VALID 0xffff
|
|
#define SRCLKEN_REG(ofs) (hw->base[SRCLKEN_BASE] + ofs)
|
|
#define SCP_REG(ofs) (hw->base[SCPDVFS_BASE] + ofs)
|
|
#define GPIO_REG(ofs) (hw->base[GPIO_BASE] + ofs)
|
|
|
|
#if defined(CONFIG_OF)
|
|
#define SRCLKEN_RC_CFG SRCLKEN_REG(hw->val[PWR_CFG])
|
|
#define RC_CENTRAL_CFG1 SRCLKEN_REG(hw->val[CENTRAL_1_CFG])
|
|
#define RC_CENTRAL_CFG2 SRCLKEN_REG(hw->val[CENTRAL_2_CFG])
|
|
#define RC_CMD_ARB_CFG SRCLKEN_REG(hw->val[CMD_ARB_CFG])
|
|
#define RC_PMIC_RCEN_SET_CLR_ADDR SRCLKEN_REG(hw->val[PMIC_SETCLR_CFG])
|
|
#define RC_DCXO_FPM_CFG SRCLKEN_REG(hw->val[DCXO_FPM_CFG])
|
|
#define RC_CENTRAL_CFG3 SRCLKEN_REG(hw->val[CENTRAL_3_CFG])
|
|
#define RC_M00_SRCLKEN_CFG SRCLKEN_REG(hw->val[SUBSYS_CFG])
|
|
#define RC_FSM_STA_0 SRCLKEN_REG(hw->val[FSM_STA])
|
|
#define RC_CMD_STA_0 SRCLKEN_REG(hw->val[CMD_0_STA])
|
|
#define RC_CMD_STA_1 SRCLKEN_REG(hw->val[CMD_1_STA])
|
|
#define RC_SPI_STA_0 SRCLKEN_REG(hw->val[SPI_STA])
|
|
#define RC_PI_PO_STA_0 SRCLKEN_REG(hw->val[PIPO_STA])
|
|
#define RC_M00_REQ_STA_0 SRCLKEN_REG(hw->val[SUBSYS_STA])
|
|
#define RC_MISC_0 SRCLKEN_REG(hw->val[MISC_CFG])
|
|
#define RC_SPM_CTL SRCLKEN_REG(hw->val[SPM_CFG])
|
|
#define SUBSYS_INTF_CFG SRCLKEN_REG(hw->val[SUB_INTF_CFG])
|
|
#define DBG_TRACE_0_LSB SRCLKEN_REG(hw->val[DBG_TRACE_L_STA])
|
|
#define DBG_TRACE_0_MSB SRCLKEN_REG(hw->val[DBG_TRACE_M_STA])
|
|
#endif /* CONFIG_OF */
|
|
|
|
/* TODO: marked this after driver is ready */
|
|
#define SRCLKEN_RC_BRINGUP 0
|
|
/* Pwrap Register */
|
|
#define SRCLKEN_RCINF_STA_0 (0x1C4)
|
|
#define SRCLKEN_RCINF_STA_1 (0x1C8)
|
|
|
|
/* PMIC Register */
|
|
#define PMIC_REG_MASK 0xFFFF
|
|
#define PMIC_REG_SHIFT 0
|
|
|
|
/* SCP Register */
|
|
#define CPU_VREQ_CTRL SCP_REG(0x0)
|
|
#define VREQ_RC_SEL (hw->val[SCP_RC_SEL_BIT])
|
|
#define VREQ_RC_VAL (hw->val[SCP_RC_VAL_BIT])
|
|
|
|
#if RC_GPIO_DBG_ENABLE
|
|
/* GPIO Register */
|
|
#define GPIO_DIR GPIO_REG(hw->val[GPIO_DIR_CFG])
|
|
#define GPIO_DIR_SET GPIO_REG(hw->val[GPIO_DIR_CFG] + 0x4)
|
|
#define GPIO_DIR_CLR GPIO_REG(hw->val[GPIO_DIR_CFG] + 0x8)
|
|
|
|
#define GPIO_DOUT GPIO_REG(hw->val[GPIO_DOUT_CFG])
|
|
#define GPIO_DOUT_SET GPIO_REG(hw->val[GPIO_DOUT_CFG] + 0x4)
|
|
#define GPIO_DOUT_CLR GPIO_REG(hw->val[GPIO_DOUT_CFG] + 0x8)
|
|
|
|
#define GPIO_PULL_SHFT (hw->val[GPIO_PULL_BIT])
|
|
#endif
|
|
|
|
#define TRACE_NUM 8
|
|
|
|
static bool srclken_debug;
|
|
static bool rc_dts_init_done;
|
|
static bool rc_stage_init_done;
|
|
static enum srclken_config rc_stage = SRCLKEN_BRINGUP;
|
|
|
|
static const char *base_n[MAX_BASE_NUM] = {
|
|
[SRCLKEN_BASE] = "srclken",
|
|
[SCPDVFS_BASE] = "scpdvfs",
|
|
[PWRAP_BASE] = "pwrap",
|
|
[GPIO_BASE] = "gpio",
|
|
};
|
|
|
|
static const char *subsys_n[MAX_SYS_NUM] = {
|
|
[SYS_SUSPEND] = "SUSPEND",
|
|
[SYS_RF] = "RF",
|
|
[SYS_DPIDLE] = "DPIDLE",
|
|
[SYS_MD] = "MD",
|
|
[SYS_GPS] = "GPS",
|
|
[SYS_BT] = "BT",
|
|
[SYS_WIFI] = "WIFI",
|
|
[SYS_MCU] = "MCU",
|
|
[SYS_COANT] = "COANT",
|
|
[SYS_NFC] = "NFC",
|
|
[SYS_UFS] = "UFS",
|
|
[SYS_SCP] = "SCP",
|
|
[SYS_RSV] = "RSV",
|
|
};
|
|
|
|
static struct rc_dts_predef srclken_dts[DTS_NUM] = {
|
|
[PWR_CFG] = {"srclken", "rst", "cfg", 0},
|
|
[CENTRAL_1_CFG] = {"srclken", "central", "cfg", 0},
|
|
[CENTRAL_2_CFG] = {"srclken", "central", "cfg", 1},
|
|
[CMD_ARB_CFG] = {"srclken", "cmd", "cfg", 0},
|
|
[PMIC_CFG] = {"srclken", "pmic", "cfg", 0},
|
|
[PMIC_SETCLR_CFG] = {"srclken", "pmic", "cfg", 1},
|
|
[DCXO_FPM_CFG] = {"srclken", "dcxo-fpm", "cfg", 0},
|
|
[CENTRAL_3_CFG] = {"srclken", "central", "cfg", 2},
|
|
[SUBSYS_CFG] = {"srclken", "subsys", "cfg", 0},
|
|
[SW_CON_CFG] = {"srclken", "sw-con", "cfg", 0},
|
|
[CENTRAL_4_CFG] = {"srclken", "central", "cfg", 3},
|
|
[PROTOCOL_CHK_CFG] = {"srclken", "protocol", "cfg", 0},
|
|
[DBG_CFG] = {"srclken", "dbg", "cfg", 0},
|
|
[MISC_CFG] = {"srclken", "misc", "cfg", 0},
|
|
[SPM_CFG] = {"srclken", "spm", "cfg", 0},
|
|
[SUB_INTF_CFG] = {"srclken", "subsys-if", "cfg", 0},
|
|
[FSM_STA] = {"srclken", "fsm", "sta", 0},
|
|
[CMD_0_STA] = {"srclken", "cmd", "sta", 0},
|
|
[CMD_1_STA] = {"srclken", "cmd", "sta", 1},
|
|
[SPI_STA] = {"srclken", "spi", "sta", 0},
|
|
[PIPO_STA] = {"srclken", "pipo", "sta", 0},
|
|
[SUBSYS_STA] = {"srclken", "subsys", "sta", 0},
|
|
[DBG_TRACE_L_STA] = {"srclken", "dbg-trace", "sta", 0},
|
|
[DBG_TRACE_M_STA] = {"srclken", "dbg-trace", "sta", 1},
|
|
[SCP_VREQ_CFG] = {"scp", "vreq", "cfg", 0},
|
|
[SCP_RC_SEL_BIT] = {"scp", "rc-vreq", "bit", 0},
|
|
[SCP_RC_VAL_BIT] = {"scp", "rc-vreq", "bit", 1},
|
|
[GPIO_DIR_CFG] = {"gpio", "dir", "cfg", 0},
|
|
[GPIO_DOUT_CFG] = {"gpio", "dout", "cfg", 0},
|
|
[GPIO_PULL_BIT] = {"gpio", "pull", "bit", 0},
|
|
};
|
|
|
|
static struct srclken_hw *hw;
|
|
|
|
#if RC_GPIO_DBG_ENABLE
|
|
static void __srclken_gpio_pull(bool enable)
|
|
{
|
|
srclken_write(GPIO_DIR_SET, 0x1 << GPIO_PULL_SHFT);
|
|
|
|
if (enable)
|
|
srclken_write(GPIO_DOUT_SET, 0x1 << GPIO_PULL_SHFT);
|
|
else
|
|
srclken_write(GPIO_DOUT_CLR, 0x1 << GPIO_PULL_SHFT);
|
|
|
|
pr_info("gpio: dir(0x%x) out(0x%x)\n", srclken_read(GPIO_DIR),
|
|
srclken_read(GPIO_DOUT));
|
|
}
|
|
#endif
|
|
|
|
static int __srclken_switch_subsys_ctrl(enum sys_id id,
|
|
enum rc_ctrl_m mode, enum rc_ctrl_r req)
|
|
{
|
|
u32 bit_mask = SW_SRCLKEN_RC_MSK << SW_SRCLKEN_RC_SHFT;
|
|
|
|
if (id >= MAX_SYS_NUM || id < 0) {
|
|
pr_notice("req_subsys is not available\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((mode != HW_MODE) && (mode != SW_MODE)) {
|
|
pr_notice("req_mode is not allowed\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((req != OFF_REQ) && (req != NO_REQ) &&
|
|
(req != FPM_REQ) && (req != BBLPM_REQ)) {
|
|
pr_notice("req_type is not allowed\n");
|
|
return -1;
|
|
}
|
|
|
|
if (req == NO_REQ)
|
|
req = (srclken_read(RC_M00_SRCLKEN_CFG + 4 * id) &
|
|
(FPM_REQ | BBLPM_REQ));
|
|
|
|
srclken_write(RC_M00_SRCLKEN_CFG + 4 * id,
|
|
(srclken_read(RC_M00_SRCLKEN_CFG + 4 * id)
|
|
& ~(bit_mask)) | req | mode);
|
|
|
|
if ((srclken_read(RC_M00_SRCLKEN_CFG + 4 * id) & bit_mask)
|
|
== (mode | req))
|
|
return 0;
|
|
|
|
pr_info("read back value err.(0x%x)",
|
|
srclken_read(RC_M00_SRCLKEN_CFG + 4 * id));
|
|
return -1;
|
|
|
|
}
|
|
|
|
static ssize_t __subsys_ctl_store(const char *buf, enum sys_id id)
|
|
{
|
|
char mode[10];
|
|
|
|
if ((sscanf(buf, "%9s", mode) != 1))
|
|
return -EPERM;
|
|
|
|
if (!strcmp(mode, "HW"))
|
|
__srclken_switch_subsys_ctrl(id, HW_MODE, NO_REQ);
|
|
else if (!strcmp(mode, "SW")) {
|
|
#if RC_GPIO_DBG_ENABLE
|
|
__srclken_gpio_pull(false);
|
|
#endif
|
|
__srclken_switch_subsys_ctrl(id, SW_MODE, NO_REQ);
|
|
} else if (!strcmp(mode, "SW_OFF")) {
|
|
#if RC_GPIO_DBG_ENABLE
|
|
__srclken_gpio_pull(false);
|
|
#endif
|
|
__srclken_switch_subsys_ctrl(id, SW_MODE, OFF_REQ);
|
|
} else if (!strcmp(mode, "SW_FPM")) {
|
|
__srclken_switch_subsys_ctrl(id, SW_MODE, FPM_REQ);
|
|
#if RC_GPIO_DBG_ENABLE
|
|
__srclken_gpio_pull(true);
|
|
#endif
|
|
} else if (!strcmp(mode, "SW_BBLPM")) {
|
|
__srclken_switch_subsys_ctrl(id, SW_MODE, BBLPM_REQ);
|
|
#if RC_GPIO_DBG_ENABLE
|
|
__srclken_gpio_pull(true);
|
|
#endif
|
|
} else {
|
|
pr_info("bad argument!! please follow correct format\n");
|
|
pr_info("echo $mode > proc/srclken_rc/$subsys\n");
|
|
pr_info("mode = {HW, SW_OFF, SW_FPM, SW_BBLPM}\n");
|
|
|
|
return -EPERM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t __subsys_ctl_show(char *buf, enum sys_id id)
|
|
{
|
|
u32 sys_sta;
|
|
u32 filter;
|
|
u32 cmd_ok;
|
|
int len = 0;
|
|
|
|
sys_sta = srclken_read(RC_M00_REQ_STA_0 + (id * 4));
|
|
filter = (sys_sta >> REQ_FILT_SHFT) & REQ_FILT_MSK;
|
|
cmd_ok = (sys_sta >> CMD_OK_SHFT) & CMD_OK_MSK;
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"[%s] -\n", subsys_n[id]);
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(req / ack) - FPM(%d/%d), BBLPM(%d/%d)\n",
|
|
(sys_sta >> FPM_SHFT) & FPM_MSK,
|
|
(sys_sta >> FPM_ACK_SHFT) & FPM_ACK_MSK,
|
|
(sys_sta >> BBLPM_SHFT) & BBLPM_MSK,
|
|
(sys_sta >> BBLPM_ACK_SHFT) & BBLPM_ACK_MSK);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(cur / target / chg) - DCXO(%x/%x/%d)\n",
|
|
(sys_sta >> CUR_DCXO_SHFT) & CUR_DCXO_MSK,
|
|
(sys_sta >> TAR_DCXO_SHFT) & TAR_DCXO_MSK,
|
|
((sys_sta >> DCXO_CHG_SHFT) & DCXO_CHG_MSK) ?
|
|
(((sys_sta >> DCXO_EQ_SHFT) & DCXO_EQ_MSK) ?
|
|
0 : 1) : 0);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(done / ongo / filt / cur / cmd) - REQ(%d/%d/%s/%x/%s)\n",
|
|
(sys_sta >> ALLOW_REQ_SHFT) & ALLOW_REQ_MSK,
|
|
(sys_sta >> REQ_ONGO_SHFT) & REQ_ONGO_MSK,
|
|
(filter & 0x1) ? "bys" : (filter & 0x2) ? "dcxo" :
|
|
(filter & 0x4) ? "nd" : "none",
|
|
(sys_sta >> CUR_REQ_STA_SHFT) & CUR_REQ_STA_MSK,
|
|
(cmd_ok & 0x3) == 0x3 ? "cmd_ok" : "cmd_not_ok");
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\tcur_pmic_bit(%d)\n", (sys_sta >> CUR_RC_SHFT) & CUR_RC_MSK);
|
|
return len;
|
|
}
|
|
|
|
bool srclken_get_debug_cfg(void)
|
|
{
|
|
#if SRCLKEN_RC_BRINGUP
|
|
return false;
|
|
#endif
|
|
|
|
#if SRCLKEN_DBG
|
|
return true;
|
|
#else
|
|
return srclken_debug;
|
|
#endif
|
|
}
|
|
|
|
static u32 __srclken_dump_sta(char *buf, u8 id)
|
|
{
|
|
u32 len = 0;
|
|
|
|
switch (id) {
|
|
case XO_SOC:
|
|
len = __subsys_ctl_show(buf, SYS_SUSPEND);
|
|
len += __subsys_ctl_show(buf + len, SYS_DPIDLE);
|
|
break;
|
|
case XO_WCN:
|
|
len = __subsys_ctl_show(buf, SYS_GPS);
|
|
len += __subsys_ctl_show(buf + len, SYS_BT);
|
|
len += __subsys_ctl_show(buf + len, SYS_WIFI);
|
|
len += __subsys_ctl_show(buf + len, SYS_MCU);
|
|
len += __subsys_ctl_show(buf + len, SYS_COANT);
|
|
break;
|
|
case XO_NFC:
|
|
len = __subsys_ctl_show(buf, SYS_NFC);
|
|
break;
|
|
case XO_CEL:
|
|
len = __subsys_ctl_show(buf, SYS_RF);
|
|
len += __subsys_ctl_show(buf + len, SYS_MD);
|
|
break;
|
|
case XO_EXT:
|
|
len = __subsys_ctl_show(buf, SYS_UFS);
|
|
break;
|
|
default:
|
|
pr_notice("Not valid xo_buf id\n");
|
|
break;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
void srclken_hw_dump_sta_log(void)
|
|
{
|
|
char buf[1024];
|
|
u32 len = 0;
|
|
u8 sta = 0;
|
|
u8 id = 0;
|
|
|
|
clk_buf_dump_clkbuf_log();
|
|
pr_notice("%s:\n", __func__);
|
|
for (id = 0; id < XO_NUMBER; id++) {
|
|
sta = clk_buf_get_xo_en_sta(id);
|
|
if (sta) {
|
|
len = __srclken_dump_sta(buf, id);
|
|
if (len)
|
|
pr_notice("%s\n", buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int __srclken_dump_cfg(char *buf)
|
|
{
|
|
int len = 0;
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"rc cfg : 0x%x\n", srclken_read(SRCLKEN_RC_CFG));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"centrol 1: 0x%x\n", srclken_read(RC_CENTRAL_CFG1));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"centrol 2: 0x%x\n", srclken_read(RC_CENTRAL_CFG2));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"centrol 3: 0x%x\n", srclken_read(RC_CENTRAL_CFG3));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"cmd cfg: 0x%x\n", srclken_read(RC_CMD_ARB_CFG));
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"subsys cfg: = 0x%x\n", srclken_read(SUBSYS_INTF_CFG));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"pmrc setclr: 0x%x\n",
|
|
srclken_read(RC_PMIC_RCEN_SET_CLR_ADDR));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"fpm cfg: 0x%x\n", srclken_read(RC_DCXO_FPM_CFG));
|
|
|
|
return len;
|
|
}
|
|
|
|
void srclken_hw_dump_cfg_log(void)
|
|
{
|
|
char buf[256];
|
|
|
|
__srclken_dump_cfg(buf);
|
|
|
|
pr_notice("%s: %s\n", __func__, buf);
|
|
}
|
|
|
|
static int __srclken_dump_last_sta(char *buf, u8 idx)
|
|
{
|
|
int len = 0;
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"TRACE%d LSB : 0x%x, ", idx,
|
|
srclken_read(DBG_TRACE_0_LSB + (idx * 8)));
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"TRACE%d MSB : 0x%x\n", idx,
|
|
srclken_read(DBG_TRACE_0_MSB + (idx * 8)));
|
|
|
|
return len;
|
|
}
|
|
|
|
void srclken_hw_dump_last_sta_log(void)
|
|
{
|
|
char buf[1024];
|
|
u8 i;
|
|
|
|
pr_notice("%s:\n", __func__);
|
|
|
|
for (i = 0; i < TRACE_NUM; i++) {
|
|
__srclken_dump_last_sta(buf, i);
|
|
|
|
pr_notice("%s", buf);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
static ssize_t cfg_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
|
|
len = __srclken_dump_cfg(buf);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t trace_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
u8 i;
|
|
|
|
for (i = 0; i < TRACE_NUM; i++)
|
|
len += __srclken_dump_last_sta(buf, i);
|
|
|
|
srclken_dump_sta_log();
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t suspend_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_SUSPEND);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t suspend_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_SUSPEND);
|
|
}
|
|
|
|
static ssize_t rf_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_RF);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t rf_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_RF);
|
|
}
|
|
|
|
static ssize_t dpidle_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_DPIDLE);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t dpidle_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_DPIDLE);
|
|
}
|
|
|
|
static ssize_t md_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_MD);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t md_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_MD);
|
|
}
|
|
|
|
static ssize_t gps_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_GPS);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t gps_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_GPS);
|
|
}
|
|
|
|
static ssize_t bt_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_BT);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t bt_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_BT);
|
|
}
|
|
|
|
static ssize_t wifi_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_WIFI);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t wifi_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_WIFI);
|
|
}
|
|
|
|
static ssize_t mcu_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_MCU);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t mcu_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_MCU);
|
|
}
|
|
|
|
static ssize_t coant_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_COANT);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t coant_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_COANT);
|
|
}
|
|
|
|
static ssize_t nfc_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_NFC);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t nfc_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_NFC);
|
|
}
|
|
|
|
static ssize_t ufs_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_UFS);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ufs_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_UFS);
|
|
}
|
|
|
|
static ssize_t scp_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_SCP);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t scp_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_SCP);
|
|
}
|
|
|
|
static ssize_t rsv_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
ret = __subsys_ctl_store(buf, SYS_RSV);
|
|
if (ret)
|
|
return ret;
|
|
return count;
|
|
}
|
|
|
|
static ssize_t rsv_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return __subsys_ctl_show(buf, SYS_RSV);
|
|
}
|
|
|
|
static ssize_t all_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_SYS_NUM; i++)
|
|
len += __subsys_ctl_show(buf, i);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t spi_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
u32 spi_sta;
|
|
int len = 0;
|
|
|
|
spi_sta = srclken_read(RC_SPI_STA_0);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"[SPI] -\n");
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(req / ack / addr / data) - (%d/%d/%x/%x)\n",
|
|
(spi_sta & SPI_CMD_REQ) == SPI_CMD_REQ,
|
|
(spi_sta & SPI_CMD_REQ_ACK) == SPI_CMD_REQ_ACK,
|
|
(spi_sta >> SPI_CMD_ADDR_SHFT) & SPI_CMD_ADDR_MSK,
|
|
(spi_sta >> SPI_CMD_DATA_SHFT) & SPI_CMD_DATA_MSK);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t cmd_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
u32 cmd_sta_0, cmd_sta_1;
|
|
int len = 0;
|
|
|
|
cmd_sta_0 = srclken_read(RC_CMD_STA_0);
|
|
cmd_sta_1 = srclken_read(RC_CMD_STA_1);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"[CMD] -\n");
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(xo / dcxo / target) - PMIC (0x%x/0%x/0x%x)\n",
|
|
(cmd_sta_0 >> PMIC_PMRC_EN_SHFT) & PMIC_PMRC_EN_MSK,
|
|
(cmd_sta_0 >> PMIC_DCXO_SHFT) & PMIC_DCXO_MSK,
|
|
(cmd_sta_0 >> TAR_CMD_ARB_SHFT) & TAR_CMD_ARB_MSK);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(xo / dcxo) - SUBSYS (0x%x/0x%x)\n",
|
|
(cmd_sta_1 >> TAR_XO_REQ_SHFT) & TAR_XO_REQ_MSK,
|
|
(cmd_sta_1 >> TAR_DCXO_REQ_SHFT) & TAR_DCXO_REQ_MSK);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t fsm_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
u32 fsm_sta;
|
|
int len = 0;
|
|
|
|
fsm_sta = srclken_read(RC_FSM_STA_0);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"[FSM] -\n");
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\tRC Request (%s)\n",
|
|
((fsm_sta & ANY_REQ_32K) != ANY_REQ_32K) ? "none" :
|
|
((fsm_sta & ANY_BYS_REQ) == ANY_BYS_REQ) ? "bys" :
|
|
((fsm_sta & ANY_ND_REQ) == ANY_ND_REQ) ? "nd" :
|
|
((fsm_sta & ANY_ND_REQ) == ANY_ND_REQ) ? "dcxo" : "err");
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(vcore/wrap_c/wrap_s/ulposc/spi) = (%x/%x/%x/%x/%x)\n",
|
|
(fsm_sta >> VCORE_ULPOSC_STA_SHFT) & VCORE_ULPOSC_STA_MSK,
|
|
(fsm_sta >> WRAP_CMD_STA_SHFT) & WRAP_CMD_STA_MSK,
|
|
(fsm_sta >> WRAP_SLP_STA_SHFT) & WRAP_SLP_STA_MSK,
|
|
(fsm_sta >> ULPOSC_STA_SHFT) & ULPOSC_STA_MSK,
|
|
(fsm_sta >> SPI_STA_SHFT) & SPI_STA_MSK);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t popi_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
u32 popi_sta;
|
|
int len = 0;
|
|
|
|
popi_sta = srclken_read(RC_PI_PO_STA_0);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"[POPI] -\n");
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(o0 / vreq_msk / xo_soc) = spm input : (%d/%d/%d)\n",
|
|
(popi_sta & SPM_O0) == SPM_O0,
|
|
(popi_sta & SPM_VREQ_MASK_B) == SPM_VREQ_MASK_B,
|
|
(popi_sta & AP_26M_RDY) == AP_26M_RDY);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(o0) = output spm : (%d)\n",
|
|
(popi_sta & SPM_O0_ACK) == SPM_O0_ACK);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(vreq/pwrap/pwrap_slp) = scp input1: (%d/%d/%d)\n",
|
|
(popi_sta & SCP_VREQ) == SCP_VREQ,
|
|
(popi_sta & SCP_VREQ_WRAP) == SCP_VREQ_WRAP,
|
|
(popi_sta & SCP_WRAP_SLP) == SCP_WRAP_SLP);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(ck/rst/en) = scp input2: (%d/%d/%d)\n",
|
|
(popi_sta & SCP_ULPOSC_CK) == SCP_ULPOSC_CK,
|
|
(popi_sta & SCP_ULPOSC_RST) == SCP_ULPOSC_RST,
|
|
(popi_sta & SCP_ULPOSC_EN) == SCP_ULPOSC_EN);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(vreq/pwrap_slp) = output scp1: (%d/%d)\n",
|
|
(popi_sta & SCP_VREQ_ACK) == SCP_VREQ_ACK,
|
|
(popi_sta & SCP_WRAP_SLP_ACK) == SCP_WRAP_SLP_ACK);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(ck/rst/en) = output scp2: (%d/%d/%d)\n",
|
|
(popi_sta & SCP_ULPOSC_CK_ACK) == SCP_ULPOSC_CK_ACK,
|
|
(popi_sta & SCP_ULPOSC_RST_ACK) == SCP_ULPOSC_RST_ACK,
|
|
(popi_sta & SCP_ULPOSC_EN_ACK) == SCP_ULPOSC_EN_ACK);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(o0/vreq/pwrap/pwrap_slp) = rc output: (%d/%d/%d/%d)\n",
|
|
(popi_sta & RC_O0) == RC_O0,
|
|
(popi_sta & RC_VREQ) == RC_VREQ,
|
|
(popi_sta & RC_VREQ_WRAP) == RC_VREQ_WRAP,
|
|
(popi_sta & RC_WRAP_SLP) == RC_WRAP_SLP);
|
|
|
|
len += snprintf(buf+len, PAGE_SIZE-len,
|
|
"\t(pwrap_slp) = input rc: (%d)\n",
|
|
(popi_sta & RC_WRAP_SLP_ACK) == RC_WRAP_SLP_ACK);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t debug_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
u32 onoff;
|
|
|
|
if (kstrtouint(buf, 10, &onoff))
|
|
return -EPERM;
|
|
|
|
if (onoff == 0)
|
|
srclken_debug = false;
|
|
else if (onoff == 1)
|
|
srclken_debug = true;
|
|
else
|
|
goto ERROR_CMD;
|
|
|
|
return count;
|
|
ERROR_CMD:
|
|
pr_info("bad argument!! please follow correct format\n");
|
|
return -EPERM;
|
|
}
|
|
|
|
static ssize_t debug_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
|
|
len += snprintf(buf, PAGE_SIZE-len, "debug_cfg : %d\n", srclken_debug);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t scp_sw_ctl_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
char mode[8];
|
|
|
|
if (sscanf(buf, "%7s", mode) != 1)
|
|
return -EPERM;
|
|
|
|
if (!strcmp(mode, "HW")) {
|
|
srclken_write(CPU_VREQ_CTRL,
|
|
srclken_read(CPU_VREQ_CTRL) | (1 << VREQ_RC_SEL));
|
|
} else if (!strcmp(mode, "SW_ON")) {
|
|
srclken_write(CPU_VREQ_CTRL,
|
|
(srclken_read(CPU_VREQ_CTRL) & ~(0x1 << VREQ_RC_SEL))
|
|
| (1 << VREQ_RC_VAL));
|
|
} else if (!strcmp(mode, "SW_OFF")) {
|
|
srclken_write(CPU_VREQ_CTRL,
|
|
srclken_read(CPU_VREQ_CTRL) &
|
|
~(0x1 << VREQ_RC_SEL | 0x1 << VREQ_RC_VAL));
|
|
} else
|
|
goto ERROR_CMD;
|
|
|
|
return count;
|
|
ERROR_CMD:
|
|
pr_info("bad argument!! please follow correct format\n");
|
|
return -EPERM;
|
|
}
|
|
|
|
static ssize_t scp_sw_ctl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
int len = 0;
|
|
|
|
len += snprintf(buf, PAGE_SIZE-len, "cpu vreq ctrl : 0x%x(addr:0x%p)\n",
|
|
srclken_read(CPU_VREQ_CTRL), CPU_VREQ_CTRL);
|
|
|
|
return len;
|
|
}
|
|
|
|
DEFINE_ATTR_RO(cfg_ctl);
|
|
DEFINE_ATTR_RO(trace_ctl);
|
|
DEFINE_ATTR_RW(suspend_ctl);
|
|
DEFINE_ATTR_RW(rf_ctl);
|
|
DEFINE_ATTR_RW(dpidle_ctl);
|
|
DEFINE_ATTR_RW(md_ctl);
|
|
DEFINE_ATTR_RW(gps_ctl);
|
|
DEFINE_ATTR_RW(bt_ctl);
|
|
DEFINE_ATTR_RW(wifi_ctl);
|
|
DEFINE_ATTR_RW(mcu_ctl);
|
|
DEFINE_ATTR_RW(coant_ctl);
|
|
DEFINE_ATTR_RW(nfc_ctl);
|
|
DEFINE_ATTR_RW(ufs_ctl);
|
|
DEFINE_ATTR_RW(scp_ctl);
|
|
DEFINE_ATTR_RW(rsv_ctl);
|
|
DEFINE_ATTR_RO(all_ctl);
|
|
DEFINE_ATTR_RO(spi_ctl);
|
|
DEFINE_ATTR_RO(cmd_ctl);
|
|
DEFINE_ATTR_RO(fsm_ctl);
|
|
DEFINE_ATTR_RO(popi_ctl);
|
|
DEFINE_ATTR_RW(debug_ctl);
|
|
DEFINE_ATTR_RW(scp_sw_ctl);
|
|
|
|
static struct attribute *srclken_attrs[] = {
|
|
/* for srclken rc control */
|
|
__ATTR_OF(cfg_ctl),
|
|
__ATTR_OF(trace_ctl),
|
|
__ATTR_OF(suspend_ctl),
|
|
__ATTR_OF(rf_ctl),
|
|
__ATTR_OF(dpidle_ctl),
|
|
__ATTR_OF(md_ctl),
|
|
__ATTR_OF(gps_ctl),
|
|
__ATTR_OF(bt_ctl),
|
|
__ATTR_OF(wifi_ctl),
|
|
__ATTR_OF(mcu_ctl),
|
|
__ATTR_OF(coant_ctl),
|
|
__ATTR_OF(nfc_ctl),
|
|
__ATTR_OF(ufs_ctl),
|
|
__ATTR_OF(scp_ctl),
|
|
__ATTR_OF(rsv_ctl),
|
|
__ATTR_OF(all_ctl),
|
|
__ATTR_OF(spi_ctl),
|
|
__ATTR_OF(cmd_ctl),
|
|
__ATTR_OF(fsm_ctl),
|
|
__ATTR_OF(popi_ctl),
|
|
__ATTR_OF(debug_ctl),
|
|
__ATTR_OF(scp_sw_ctl),
|
|
|
|
/* must */
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group srclken_attr_group = {
|
|
.name = "srclken",
|
|
.attrs = srclken_attrs,
|
|
};
|
|
|
|
int srclken_fs_init(void)
|
|
{
|
|
int r;
|
|
|
|
/* create /sys/kernel/srclken/xxx */
|
|
r = sysfs_create_group(kernel_kobj, &srclken_attr_group);
|
|
if (r)
|
|
pr_err("FAILED TO CREATE /sys/kernel/srclken (%d)\n", r);
|
|
|
|
return r;
|
|
}
|
|
#else /* !CONFIG_PM */
|
|
int srclken_fs_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_PM */
|
|
|
|
#if defined(CONFIG_OF)
|
|
int _srclken_dts_map_internal(struct device_node *node, int idx)
|
|
{
|
|
char *buf;
|
|
int ret;
|
|
|
|
buf = kzalloc(sizeof(char)*25, GFP_KERNEL);
|
|
if (!buf)
|
|
goto no_mem;
|
|
|
|
snprintf(buf, 25, "%s-%s-%s", srclken_dts[idx].base_n,
|
|
srclken_dts[idx].match, srclken_dts[idx].flag);
|
|
|
|
ret = of_property_read_u32_index(node, buf,
|
|
srclken_dts[idx].idx, &hw->val[idx]);
|
|
if (ret)
|
|
goto no_property;
|
|
|
|
pr_info("%s-[%d]0x%x\n", buf, idx, hw->val[idx]);
|
|
|
|
kfree(buf);
|
|
|
|
return ret;
|
|
|
|
no_mem:
|
|
pr_err("%s can't allocate memory %d\n",
|
|
__func__, ret);
|
|
return -ENOMEM;
|
|
no_property:
|
|
kfree(buf);
|
|
pr_err("%s can't find property %d\n",
|
|
__func__, ret);
|
|
return 0;
|
|
}
|
|
|
|
int srclken_dts_map(struct platform_device *pdev)
|
|
{
|
|
struct device_node *node;
|
|
struct resource *res;
|
|
int ret;
|
|
int i, j;
|
|
int cnt = 0;
|
|
|
|
if (rc_dts_init_done)
|
|
return 0;
|
|
|
|
node = of_find_compatible_node(NULL, NULL,
|
|
"mediatek,srclken");
|
|
if (!node) {
|
|
pr_err("%s can't find compatible node %ld\n",
|
|
__func__, PTR_ERR(node));
|
|
return PTR_ERR(node);
|
|
}
|
|
|
|
hw = kzalloc(sizeof(hw), GFP_KERNEL);
|
|
if (!hw)
|
|
goto hw_no_mem;
|
|
hw->base = kzalloc(sizeof(void __iomem *) * MAX_BASE_NUM, GFP_KERNEL);
|
|
if (!hw->base)
|
|
goto base_no_mem;
|
|
hw->val = kzalloc(sizeof(u32) * DTS_NUM, GFP_KERNEL);
|
|
if (!hw->val)
|
|
goto val_no_mem;
|
|
|
|
for (i = 0; i < MAX_BASE_NUM; i++) {
|
|
int start[] = {RC_START, SCP_START, PWRAP_START, GPIO_START};
|
|
int end[] = {RC_END, SCP_END, PWRAP_END, GPIO_END};
|
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
|
base_n[i]);
|
|
if (!res) {
|
|
hw->base[i] = NULL;
|
|
pr_info("missing IO resource %s\n", base_n[i]);
|
|
continue;
|
|
}
|
|
|
|
hw->base[i] = of_iomap(node, cnt);
|
|
cnt++;
|
|
pr_info("base[%d]0x%pR\n", i, hw->base[i]);
|
|
if (IS_ERR(hw->base[i]))
|
|
return PTR_ERR(hw->base[i]);
|
|
|
|
for (j = start[i]; j < end[i]; j++) {
|
|
ret = _srclken_dts_map_internal(node, j);
|
|
if (ret)
|
|
goto no_property;
|
|
}
|
|
}
|
|
|
|
rc_dts_init_done = true;
|
|
|
|
return 0;
|
|
|
|
val_no_mem:
|
|
kfree(hw->base);
|
|
base_no_mem:
|
|
kfree(hw);
|
|
hw_no_mem:
|
|
pr_err("%s can't allocate memory %d\n",
|
|
__func__, ret);
|
|
return -ENOMEM;
|
|
no_property:
|
|
pr_err("%s can't find property %d\n",
|
|
__func__, ret);
|
|
return 0;
|
|
}
|
|
#else /* !CONFIG_OF */
|
|
int srclken_dts_map(struct platform_device *pdev)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void srclken_stage_init(void)
|
|
{
|
|
#if SRCLKEN_RC_BRINGUP
|
|
pr_info("%s: skipped for bring up\n", __func__);
|
|
return;
|
|
#else
|
|
u32 cfg;
|
|
int i;
|
|
|
|
if (rc_stage_init_done)
|
|
return;
|
|
|
|
for (i = 0; i < DTS_NUM; i++)
|
|
pr_info("[%d]0x%x\n", i, hw->val[i]);
|
|
if ((srclken_read(RC_CENTRAL_CFG1)
|
|
& (1 << SRCLKEN_RC_EN_SHFT)) == 0) {
|
|
rc_stage = SRCLKEN_NOT_SUPPORT;
|
|
goto RC_STAGE_DONE;
|
|
}
|
|
|
|
for (i = 0; i < MAX_SYS_NUM; i++) {
|
|
cfg = srclken_read(RC_M00_SRCLKEN_CFG + i * 4);
|
|
|
|
pr_info("cfg[%d]: 0x%x\n", i, cfg);
|
|
if (i == SYS_BT) {
|
|
if ((cfg & (SW_MODE | BBLPM_REQ))
|
|
!= (SW_MODE | BBLPM_REQ))
|
|
break;
|
|
} else {
|
|
if ((cfg & (SW_MODE | OFF_REQ))
|
|
!= (SW_MODE | OFF_REQ)) {
|
|
srclken_dbg("%s: [BT-Only]M-%d check fail.\n",
|
|
__func__, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == (MAX_SYS_NUM - 1)) {
|
|
srclken_dbg("%s: rc bt only mode\n", __func__);
|
|
rc_stage = SRCLKEN_BT_ONLY;
|
|
goto RC_STAGE_DONE;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_SYS_NUM; i++) {
|
|
cfg = srclken_read(RC_M00_SRCLKEN_CFG + i * 4);
|
|
|
|
if (i == SYS_COANT) {
|
|
if ((cfg & (0x7 << SW_SRCLKEN_RC_SHFT)) != 0)
|
|
break;
|
|
} else {
|
|
if ((cfg & (SW_MODE | OFF_REQ))
|
|
!= (SW_MODE | OFF_REQ)) {
|
|
srclken_dbg("%s: [COANT-Only]M-%d check fail.\n",
|
|
__func__, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == (MAX_SYS_NUM - 1)) {
|
|
srclken_dbg("%s: rc coant only mode\n", __func__);
|
|
rc_stage = SRCLKEN_BT_ONLY;
|
|
goto RC_STAGE_DONE;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_SYS_NUM; i++) {
|
|
cfg = srclken_read(RC_M00_SRCLKEN_CFG + i * 4);
|
|
|
|
if (i == SYS_BT) {
|
|
if ((cfg & (SW_MODE | BBLPM_REQ))
|
|
!= (SW_MODE | BBLPM_REQ))
|
|
break;
|
|
} else if ((cfg & (1 << SW_SRCLKEN_RC_SHFT)) != 0) {
|
|
srclken_dbg("%s: [Full-Set] M-%d check fail.\n",
|
|
__func__, i);
|
|
break;
|
|
}
|
|
|
|
if (i == (MAX_SYS_NUM - 1)) {
|
|
srclken_dbg("%s: rc full set mode\n", __func__);
|
|
rc_stage = SRCLKEN_FULL_SET;
|
|
goto RC_STAGE_DONE;
|
|
}
|
|
}
|
|
|
|
pr_err("%s: rc went wrong, need to check\n", __func__);
|
|
rc_stage = SRCLKEN_ERR;
|
|
|
|
RC_STAGE_DONE:
|
|
rc_stage_init_done = true;
|
|
#endif
|
|
}
|
|
|
|
enum srclken_config srclken_hw_get_stage(void)
|
|
{
|
|
if (!rc_stage_init_done)
|
|
srclken_stage_init();
|
|
|
|
return rc_stage;
|
|
}
|
|
|