kernel_samsung_a53x/drivers/soc/samsung/exynos-flexpmu-dbg.c
2024-06-15 16:02:09 -03:00

805 lines
19 KiB
C
Executable file

/*
* Exynos regulator support.
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#define EXYNOS_FLEXPMU_DBG_PREFIX "EXYNOS-FLEXPMU-DBG: "
#define DATA_LINE (16)
#define DATA_IDX (8)
#define FLEXPMU_DBG_FUNC_READ(__name) \
exynos_flexpmu_dbg_ ## __name ## _read
#define BUF_MAX_LINE 10
#define BUF_LINE_SIZE 255
#define BUF_SIZE (BUF_MAX_LINE * BUF_LINE_SIZE)
#define DEC_PRINT 1
#define HEX_PRINT 2
/* enum for debugfs files */
enum flexpmu_debugfs_id {
FID_CPU_STATUS,
FID_SEQ_STATUS,
FID_CUR_SEQ,
FID_SW_FLAG,
FID_SEQ_COUNT,
FID_MIF_ALWAYS_ON,
FID_LPM_COUNT,
FID_APM_REQ_INFO,
#if defined(CONFIG_SOC_S5E9925)
FID_MID_DVS_EN,
#endif
FID_MAX
};
char *flexpmu_debugfs_name[FID_MAX] = {
"cpu_status",
"seq_status",
"cur_sequence",
"sw_flag",
"seq_count",
"mif_always_on",
"lpm_count",
"apm_req_info",
#if defined(CONFIG_SOC_S5E9925)
"mid_dvs_en",
#endif
};
/* enum for data lines */
enum data_id {
DID_CPU_STATUS, /* 0 */
DID_SEQ_STATUS,
DID_CUR_SEQ0,
DID_CUR_SEQ1,
DID_PWR_MODE0, /* 4 */
DID_PWR_MODE1,
DID_PWR_MODE2,
DID_PWR_MODE3,
DID_PWR_MODE4,
DID_PWR_MODE5,
DID_SW_FLAG,
DID_IRQ_STATUS, /* 11 */
DID_IRQ_DATA,
DID_IPC_AP_STATUS,
DID_IPC_AP_RXDATA,
DID_IPC_AP_TXDATA,
DID_SOC_COUNT,
DID_MIF_COUNT,
DID_IPC_VTS0,
DID_SLEEP_WAKEUP,
DID_LOCAL_PWR,
DID_MIF_ALWAYS_ON, /* 21 */
DID_AP_COUNT_SLEEP,
DID_MIF_COUNT_SLEEP,
DID_AP_COUNT_SICD,
DID_MIF_COUNT_SICD,
DID_DSUPD_COUNT,
DID_CUR_PMD,
DID_CPU_INFORM01,
DID_CPU_INFORM23,
DID_CPU_INFORM45,
DID_CPU_INFORM67,
DID_INT_REG01,
DID_INT_REG02,
DID_INT_REG03,
DID_INT_REG04,
DID_INT_REG05,
DID_INT_REG06,
DID_INT_REG07,
DID_INT_REG08,
DID_INT_REG09,
DID_INT_REG10,
DID_INT_REG11,
#if defined(CONFIG_SOC_S5E9925)
DID_MIFAP0,
DID_MIFAP1,
DID_MIFAUD0,
DID_MIFAUD1,
DID_MIFVTS0,
DID_MIFVTS1,
DID_MIFCP0,
DID_MIFCP1,
DID_MID_DVS_EN,
#elif defined(CONFIG_SOC_S5E8825)
DID_CMGP_REQ,
DID_LOCAL01,
DID_LOCAL02,
DID_LOCAL03,
DID_RCO_DIV,
DID_MIFAUD0,
DID_MIFAUD1,
DID_MIFAUD2,
DID_MIFVTS0,
DID_MIFVTS1,
DID_MIFVTS2,
DID_MIFCHUB0,
DID_MIFCHUB1,
DID_MIFCHUB2,
DID_MIFCP0,
DID_MIFCP1,
DID_MIFCP2,
DID_MIFGNSS0,
DID_MIFGNSS1,
DID_MIFGNSS2,
DID_MIFWLBT0,
DID_MIFWLBT1,
DID_MIFWLBT2,
DID_MIFAP0,
DID_MIFAP1,
DID_MIFAP2,
DID_TC_CP0,
DID_TC_CP1,
DID_TC_CP2,
DID_TC_GNSS0,
DID_TC_GNSS1,
DID_TC_GNSS2,
DID_TC_WLBT0,
DID_TC_WLBT1,
DID_TC_WLBT2,
DID_PWRCP0,
DID_PWRCP1,
DID_PWRCP2,
DID_PWRGNSS0,
DID_PWRGNSS1,
DID_PWRGNSS2,
DID_PWRWLBT0,
DID_PWRWLBT1,
DID_PWRWLBT2,
DID_pENTIME,
DID_SICD_PHY,
#endif
DID_MAX
};
struct flexpmu_dbg_print_arg {
char prefix[BUF_LINE_SIZE];
int print_type;
};
struct dbgfs_info {
int fid;
struct dentry *den;
struct file_operations fops;
};
struct dbgfs_info *flexpmu_dbg_info;
void __iomem *flexpmu_dbg_base;
static struct dentry *flexpmu_dbg_root;
struct flexpmu_apm_req_info {
unsigned int active_req_tick;
unsigned int last_rel_tick;
unsigned int total_count;
unsigned int total_time_tick;
unsigned long long int active_since_us;
unsigned long long int last_rel_us;
unsigned long long int total_time_us;
bool active_flag;
};
void __iomem *rtc_base;
#if defined(CONFIG_SOC_S5E9925)
#define MIF_MASTER_MAX 4
char *flexpmu_master_name[MIF_MASTER_MAX] = {
"MIF_AP",
"MIF_AUD",
"MIF_VTS",
"MIF_CP",
};
#elif defined(CONFIG_SOC_S5E8825)
#define MIF_MASTER_MAX 7
char *flexpmu_master_name[MIF_MASTER_MAX] = {
"MIF_AUD",
"MIF_VTS",
"MIF_CHUB",
"MIF_CP",
"MIF_GNSS",
"MIF_WLBT",
"MIF_AP",
};
#endif
struct flexpmu_apm_req_info apm_req[MIF_MASTER_MAX];
u32 acpm_get_mifdn_count(void)
{
return __raw_readl(flexpmu_dbg_base + (DATA_LINE * DID_MIF_COUNT_SLEEP) + DATA_IDX + 4);
}
EXPORT_SYMBOL_GPL(acpm_get_mifdn_count);
u32 acpm_get_apsocdn_count(void)
{
return __raw_readl(flexpmu_dbg_base + (DATA_LINE * DID_AP_COUNT_SLEEP) + DATA_IDX + 4);
}
EXPORT_SYMBOL_GPL(acpm_get_apsocdn_count);
u32 acpm_get_early_wakeup_count(void)
{
return __raw_readl(flexpmu_dbg_base + (DATA_LINE * DID_AP_COUNT_SLEEP) + DATA_IDX);
}
EXPORT_SYMBOL_GPL(acpm_get_early_wakeup_count);
/*notify to flexpmu, it is SICD w MIF(is_dsu_cpd=0) or SICD wo MIF(is_dsu_cpd=1).*/
u32 acpm_noti_dsu_cpd(bool is_dsu_cpd)
{
__raw_writel(is_dsu_cpd, flexpmu_dbg_base + (DATA_LINE * DID_MIF_ALWAYS_ON) + DATA_IDX);
return 0;
}
EXPORT_SYMBOL_GPL(acpm_noti_dsu_cpd);
u32 acpm_get_dsu_cpd(void)
{
return __raw_readl(flexpmu_dbg_base + (DATA_LINE * DID_MIF_ALWAYS_ON) + DATA_IDX);
}
EXPORT_SYMBOL_GPL(acpm_get_dsu_cpd);
#define MIF_REQ_MASK (0x00FF0000)
#define MIF_REQ_SHIFT (16)
u32 acpm_get_mif_request(void)
{
u32 reg = __raw_readl(flexpmu_dbg_base + (DATA_LINE * DID_SW_FLAG) + DATA_IDX + 4);
return ((reg & MIF_REQ_MASK) >> MIF_REQ_SHIFT);
}
EXPORT_SYMBOL_GPL(acpm_get_mif_request);
static ssize_t print_dataline_2(int did, struct flexpmu_dbg_print_arg *print_arg,
ssize_t len, char *buf, int *data_count)
{
int data[2];
ssize_t line_len;
int i;
for (i = 0; i < 2; i++) {
if (print_arg[*data_count].print_type == DEC_PRINT) {
data[i] = __raw_readl(flexpmu_dbg_base +
(DATA_LINE * did) + DATA_IDX + i * 4);
line_len = snprintf(buf + len, BUF_SIZE - len, "%s : %d\n",
print_arg[*data_count].prefix, data[i]);
if (line_len > 0)
len += line_len;
} else if (print_arg[*data_count].print_type == HEX_PRINT) {
data[i] = __raw_readl(flexpmu_dbg_base +
(DATA_LINE * did) + DATA_IDX + i * 4);
line_len = snprintf(buf + len, BUF_SIZE - len, "%s : 0x%x\n",
print_arg[*data_count].prefix, data[i]);
if (line_len > 0)
len += line_len;
}
*data_count += 1;
}
return len;
}
static ssize_t print_dataline_8(int did, struct flexpmu_dbg_print_arg *print_arg,
ssize_t len, char *buf, int *data_count)
{
int data[8];
ssize_t line_len;
int i;
for (i = 0; i < 8; i++) {
if (print_arg[*data_count].print_type == DEC_PRINT) {
data[i] = __raw_readb(flexpmu_dbg_base +
(DATA_LINE * did) + DATA_IDX + i);
line_len = snprintf(buf + len, BUF_SIZE - len, "%s : %d\n",
print_arg[*data_count].prefix, data[i]);
if (line_len > 0)
len += line_len;
} else if (print_arg[*data_count].print_type == HEX_PRINT) {
data[i] = __raw_readb(flexpmu_dbg_base +
(DATA_LINE * did) + DATA_IDX + i);
line_len = snprintf(buf + len, BUF_SIZE - len, "%s : 0x%x\n",
print_arg[*data_count].prefix, data[i]);
if (line_len > 0)
len += line_len;
}
*data_count += 1;
}
return len;
}
static struct flexpmu_dbg_print_arg *exynos_flexpmu_dbg_alloc_print_arg(int nargs, ...)
{
struct flexpmu_dbg_print_arg *print_arg;
va_list args;
int i;
if (nargs > BUF_MAX_LINE || nargs <= 0)
return NULL;
print_arg = kzalloc(sizeof(struct flexpmu_dbg_print_arg) * BUF_MAX_LINE, GFP_KERNEL);
va_start(args, nargs);
for (i = 0; i < nargs; i++) {
char *prefix = va_arg(args, char *);
int print_type = va_arg(args, int);
if (prefix != NULL) {
strncpy(print_arg[i].prefix, prefix, strlen(prefix));
print_arg[i].print_type = print_type;
}
}
va_end(args);
return print_arg;
}
static ssize_t exynos_flexpmu_dbg_cpu_status_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(8,
"CL0_CPU0", DEC_PRINT,
"CL0_CPU1", DEC_PRINT,
"CL0_CPU2", DEC_PRINT,
"CL0_CPU3", DEC_PRINT,
"CL1_CPU0", DEC_PRINT,
"CL1_CPU1", DEC_PRINT,
"CL1_CPU2", DEC_PRINT,
"CL1_CPU3", DEC_PRINT
);
ret = print_dataline_8(DID_CPU_STATUS, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
static ssize_t exynos_flexpmu_dbg_seq_status_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(7,
"SOC seq", DEC_PRINT,
"MIF seq", DEC_PRINT,
NULL, 0,
NULL, 0,
"nonCPU CL0", DEC_PRINT,
"nonCPU CL1", DEC_PRINT,
NULL, 0
);
ret = print_dataline_8(DID_SEQ_STATUS, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
static ssize_t exynos_flexpmu_dbg_cur_sequence_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(4,
"UP Sequence", DEC_PRINT,
"DOWN Sequence", DEC_PRINT,
"Access Type", DEC_PRINT,
"Seq Index", DEC_PRINT
);
ret = print_dataline_2(DID_CUR_SEQ0, print_arg, ret, buf, &data_count);
ret = print_dataline_2(DID_CUR_SEQ1, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
static ssize_t exynos_flexpmu_dbg_sw_flag_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(8,
"Hotplug out flag", HEX_PRINT,
"Reset-Release flag", HEX_PRINT,
NULL, 0,
NULL, 0,
"CHUB ref_count", DEC_PRINT,
NULL, 0,
"MIF req_Master", HEX_PRINT,
"MIF req_count", DEC_PRINT
);
ret = print_dataline_8(DID_SW_FLAG, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
static ssize_t exynos_flexpmu_dbg_seq_count_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(4,
"Early Wakeup", DEC_PRINT,
"SOC sequence", DEC_PRINT,
NULL, 0,
"MIF sequence", DEC_PRINT
);
ret = print_dataline_2(DID_SOC_COUNT, print_arg, ret, buf, &data_count);
ret = print_dataline_2(DID_MIF_COUNT, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
static ssize_t exynos_flexpmu_dbg_mif_always_on_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(2,
NULL, 0,
"MIF always on", DEC_PRINT
);
ret = print_dataline_2(DID_MIF_ALWAYS_ON, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
#if defined(CONFIG_SOC_S5E9925)
static ssize_t exynos_flexpmu_dbg_mid_dvs_en_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(2,
"MID DVS states", HEX_PRINT,
"MID DVS enable", DEC_PRINT
);
ret = print_dataline_2(DID_MID_DVS_EN, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
#endif
static ssize_t exynos_flexpmu_dbg_lpm_count_read(int fid, char *buf)
{
ssize_t ret = 0;
int data_count = 0;
struct flexpmu_dbg_print_arg *print_arg = exynos_flexpmu_dbg_alloc_print_arg(10,
"[SLEEP] Early wakeup", DEC_PRINT,
"[SLEEP] SOC seq down", DEC_PRINT,
NULL, 0,
"[SLEEP] MIF seq down", DEC_PRINT,
"[SICD] Early wakeup", DEC_PRINT,
"[SICD] SOC seq down", DEC_PRINT,
NULL, 0,
"[SICD] MIF seq down", DEC_PRINT,
NULL, 0,
"[DSUPD] SOC seq down", DEC_PRINT
);
ret = print_dataline_2(DID_AP_COUNT_SLEEP, print_arg, ret, buf, &data_count);
ret = print_dataline_2(DID_MIF_COUNT_SLEEP, print_arg, ret, buf, &data_count);
ret = print_dataline_2(DID_AP_COUNT_SICD, print_arg, ret, buf, &data_count);
ret = print_dataline_2(DID_MIF_COUNT_SICD, print_arg, ret, buf, &data_count);
ret = print_dataline_2(DID_DSUPD_COUNT, print_arg, ret, buf, &data_count);
kfree(print_arg);
return ret;
}
#define RTC_TICK_TO_US 976 /* 1024 Hz : 1tick = 976.5625us */
#define CURTICCNT_0 0x90
static ssize_t exynos_flexpmu_dbg_apm_req_info_read(int fid, char *buf)
{
size_t ret = 0;
unsigned long long int curr_tick = 0;
int i = 0;
if (!rtc_base) {
ret = snprintf(buf + ret, BUF_SIZE - ret,
"%s\n", "This node is not supported.\n");
return ret;
}
curr_tick = __raw_readl(rtc_base + CURTICCNT_0);
ret += snprintf(buf + ret, BUF_SIZE - ret,
"%s: %lld\n", "curr_time", curr_tick * RTC_TICK_TO_US);
ret += snprintf(buf + ret, BUF_SIZE - ret,
"%8s %32s %32s %32s %32s\n", "Master", "active_since(us ago)",
"last_rel_time(us ago)", "total_req_time(us)", "req_count");
for (i = 0; i < MIF_MASTER_MAX; i++) {
#if defined(CONFIG_SOC_S5E9925)
apm_req[i].active_req_tick = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAP0 + i * 2)) + DATA_IDX);
apm_req[i].last_rel_tick = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAP0 + i * 2)) + DATA_IDX + 4);
apm_req[i].total_count = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAP1 + i * 2)) + DATA_IDX);
apm_req[i].total_time_tick = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAP1 + i * 2)) + DATA_IDX + 4);
#elif defined(CONFIG_SOC_S5E8825)
apm_req[i].active_req_tick = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAUD0 + i * 3)) + DATA_IDX);
apm_req[i].last_rel_tick = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAUD0 + i * 3)) + DATA_IDX + 4);
apm_req[i].total_count = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAUD1 + i * 3)) + DATA_IDX);
apm_req[i].total_time_tick = __raw_readl(flexpmu_dbg_base
+ (DATA_LINE * (DID_MIFAUD1 + i * 3)) + DATA_IDX + 4);
#endif
if (apm_req[i].last_rel_tick > 0) {
apm_req[i].last_rel_us =
(curr_tick - apm_req[i].last_rel_tick) * RTC_TICK_TO_US;
}
apm_req[i].total_time_us =
apm_req[i].total_time_tick * RTC_TICK_TO_US;
if (apm_req[i].active_req_tick == 0) {
apm_req[i].active_flag = false;
apm_req[i].active_since_us = 0;
} else {
apm_req[i].active_flag = true;
apm_req[i].active_since_us =
(curr_tick - apm_req[i].active_req_tick) * RTC_TICK_TO_US;
apm_req[i].total_time_us += apm_req[i].active_since_us;
}
if (BUF_SIZE - (BUF_MAX_LINE * 3) > ret) {
ret += snprintf(buf + ret, BUF_SIZE - ret,
"%8s : %32lld %32lld %32lld %32d\n",
flexpmu_master_name[i],
apm_req[i].active_since_us,
apm_req[i].last_rel_us,
apm_req[i].total_time_us,
apm_req[i].total_count);
}
}
return ret;
}
static ssize_t (*flexpmu_debugfs_read_fptr[FID_MAX])(int, char *) = {
FLEXPMU_DBG_FUNC_READ(cpu_status),
FLEXPMU_DBG_FUNC_READ(seq_status),
FLEXPMU_DBG_FUNC_READ(cur_sequence),
FLEXPMU_DBG_FUNC_READ(sw_flag),
FLEXPMU_DBG_FUNC_READ(seq_count),
FLEXPMU_DBG_FUNC_READ(mif_always_on),
FLEXPMU_DBG_FUNC_READ(lpm_count),
FLEXPMU_DBG_FUNC_READ(apm_req_info),
#if defined(CONFIG_SOC_S5E9925)
FLEXPMU_DBG_FUNC_READ(mid_dvs_en),
#endif
};
static ssize_t exynos_flexpmu_dbg_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct dbgfs_info *d2f = file->private_data;
ssize_t ret;
char *buf = NULL;
buf = kzalloc(sizeof(char) * BUF_SIZE, GFP_KERNEL);
ret = flexpmu_debugfs_read_fptr[d2f->fid](d2f->fid, buf);
if (ret > sizeof(char) * BUF_SIZE)
return ret;
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
return ret;
}
static ssize_t exynos_flexpmu_dbg_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct dbgfs_info *f2d = file->private_data;
ssize_t ret;
char buf[32];
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
switch (f2d->fid) {
case FID_MIF_ALWAYS_ON:
if (buf[0] == '0') {
__raw_writel(0, flexpmu_dbg_base +
(DATA_LINE * DID_MIF_ALWAYS_ON) + 0xC);
}
if (buf[0] == '1') {
__raw_writel(1, flexpmu_dbg_base +
(DATA_LINE * DID_MIF_ALWAYS_ON) + 0xC);
}
break;
#if defined(CONFIG_SOC_S5E9925)
case FID_MID_DVS_EN:
if (buf[0] == '0') {
__raw_writel(0, flexpmu_dbg_base +
(DATA_LINE * DID_MID_DVS_EN) + 0xC);
}
if (buf[0] == '1') {
__raw_writel(1, flexpmu_dbg_base +
(DATA_LINE * DID_MID_DVS_EN) + 0xC);
}
break;
#endif
default:
break;
}
return ret;
}
void exynos_flexpmu_dbg_set_sleep_req(void)
{
__raw_writel(1, flexpmu_dbg_base + (DATA_LINE * DID_SLEEP_WAKEUP) + 0x8);
}
EXPORT_SYMBOL_GPL(exynos_flexpmu_dbg_set_sleep_req);
void exynos_flexpmu_dbg_clr_wakeup_req(void)
{
__raw_writel(0, flexpmu_dbg_base + (DATA_LINE * DID_SLEEP_WAKEUP) + 0xC);
}
EXPORT_SYMBOL_GPL(exynos_flexpmu_dbg_clr_wakeup_req);
static int exynos_flexpmu_dbg_probe(struct platform_device *pdev)
{
int ret = 0;
const __be32 *prop;
unsigned int len = 0;
unsigned int data_base = 0;
unsigned int data_size = 0;
unsigned int disable_mifdown = 0;
int i;
flexpmu_dbg_info = kzalloc(sizeof(struct dbgfs_info) * FID_MAX, GFP_KERNEL);
if (!flexpmu_dbg_info) {
pr_err("%s %s: can not allocate mem for flexpmu_dbg_info\n",
EXYNOS_FLEXPMU_DBG_PREFIX, __func__);
ret = -ENOMEM;
goto err_flexpmu_info;
}
prop = of_get_property(pdev->dev.of_node, "data-base", &len);
if (!prop) {
pr_err("%s %s: can not read data-base in DT\n",
EXYNOS_FLEXPMU_DBG_PREFIX, __func__);
ret = -EINVAL;
goto err_dbgfs_probe;
}
data_base = be32_to_cpup(prop);
prop = of_get_property(pdev->dev.of_node, "data-size", &len);
if (!prop) {
pr_err("%s %s: can not read data-base in DT\n",
EXYNOS_FLEXPMU_DBG_PREFIX, __func__);
ret = -EINVAL;
goto err_dbgfs_probe;
}
data_size = be32_to_cpup(prop);
if (data_base && data_size)
flexpmu_dbg_base = ioremap(data_base, data_size);
flexpmu_dbg_root = debugfs_create_dir("flexpmu-dbg", NULL);
if (!flexpmu_dbg_root) {
pr_err("%s %s: could not create debugfs root dir\n",
EXYNOS_FLEXPMU_DBG_PREFIX, __func__);
ret = -ENOMEM;
goto err_dbgfs_probe;
}
for (i = 0; i < FID_MAX; i++) {
flexpmu_dbg_info[i].fid = i;
flexpmu_dbg_info[i].fops.open = simple_open;
flexpmu_dbg_info[i].fops.read = exynos_flexpmu_dbg_read;
flexpmu_dbg_info[i].fops.write = exynos_flexpmu_dbg_write;
flexpmu_dbg_info[i].fops.llseek = default_llseek;
flexpmu_dbg_info[i].den = debugfs_create_file(flexpmu_debugfs_name[i],
0644, flexpmu_dbg_root, &flexpmu_dbg_info[i],
&flexpmu_dbg_info[i].fops);
}
rtc_base = of_iomap(pdev->dev.of_node, 0);
if (!rtc_base) {
dev_info(&pdev->dev,
"apm_req_info node is not available!\n");
}
of_property_read_u32(pdev->dev.of_node, "disable_mifdown", &disable_mifdown);
if (disable_mifdown)
__raw_writel(0, flexpmu_dbg_base +
(DATA_LINE * DID_MIF_ALWAYS_ON) + 0xC);
platform_set_drvdata(pdev, flexpmu_dbg_info);
return 0;
err_dbgfs_probe:
kfree(flexpmu_dbg_info);
err_flexpmu_info:
return ret;
}
static int exynos_flexpmu_dbg_remove(struct platform_device *pdev)
{
struct dbgfs_info *flexpmu_dbg_info = platform_get_drvdata(pdev);
debugfs_remove_recursive(flexpmu_dbg_root);
kfree(flexpmu_dbg_info);
platform_set_drvdata(pdev, NULL);
return 0;
}
static const struct of_device_id exynos_flexpmu_dbg_match[] = {
{
.compatible = "samsung,exynos-flexpmu-dbg",
},
{},
};
static struct platform_driver exynos_flexpmu_dbg_drv = {
.probe = exynos_flexpmu_dbg_probe,
.remove = exynos_flexpmu_dbg_remove,
.driver = {
.name = "exynos_flexpmu_dbg",
.owner = THIS_MODULE,
.of_match_table = exynos_flexpmu_dbg_match,
},
};
static int exynos_flexpmu_dbg_init(void)
{
return platform_driver_register(&exynos_flexpmu_dbg_drv);
}
late_initcall(exynos_flexpmu_dbg_init);
MODULE_LICENSE("GPL");