/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2021 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #include "include/pmic.h" #include "include/pmic_debugfs.h" #include "include/pmic_irq.h" #include "include/pmic_throttling_dlpt.h" #include "include/pmic_lbat_service.h" /*-------pmic_dbg_level global variable-------*/ unsigned int gPMICDbgLvl; unsigned int gPMICHKDbgLvl; unsigned int gPMICIRQDbgLvl; unsigned int gPMICREGDbgLvl; unsigned int gPMICCOMDbgLvl; /* so far no used */ #define DUMP_ALL_REG 0 int pmic_pre_wdt_reset(void) { int ret = 0; /* remove dump exception status before wdt, since we will recore * it at next boot preloader */ #if 0 preempt_disable(); local_irq_disable(); pr_info(PMICTAG "[%s][pmic_boot_status]\n", __func__); pmic_dump_exception_reg(); #if DUMP_ALL_REG pmic_dump_register(); #endif #endif return ret; } int pmic_pre_condition1(void) { return 0; } int pmic_pre_condition2(void) { return 0; } int pmic_pre_condition3(void) { return 0; } int pmic_post_condition1(void) { return 0; } int pmic_post_condition2(void) { return 0; } int pmic_post_condition3(void) { return 0; } /***************************************************************************** * mt-pmic dev_attr APIs ******************************************************************************/ unsigned int g_reg_value; static ssize_t show_pmic_access(struct device *dev, struct device_attribute *attr, char *buf) { pr_info("[%s] 0x%x\n", __func__, g_reg_value); return sprintf(buf, "0x%x\n", g_reg_value); } static ssize_t store_pmic_access(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret = 0; char *pvalue = NULL, *addr = NULL, *val = NULL; unsigned int reg_value = 0; unsigned int reg_address = 0; pr_info("[%s]\n", __func__); if (buf != NULL && size != 0) { pr_info("[%s] size is %d, buf is %s\n" , __func__, (int)size, buf); pvalue = (char *)buf; addr = strsep(&pvalue, " "); val = strsep(&pvalue, " "); if (addr) ret = kstrtou32(addr, 16, (unsigned int *)®_address); if (val) { ret = kstrtou32(val, 16, (unsigned int *)®_value); pr_info("[%s] write PMU reg 0x%x with value 0x%x !\n" , __func__, reg_address, reg_value); ret = pmic_config_interface( reg_address, reg_value, 0xFFFF, 0x0); } else { ret = pmic_read_interface( reg_address, &g_reg_value, 0xFFFF, 0x0); pr_info("[%s] read PMU reg 0x%x with value 0x%x !\n" , __func__, reg_address, g_reg_value); pr_info("[%s] use \"cat pmic_access\" to get value\n" , __func__); } } return size; } /*664*/ static DEVICE_ATTR(pmic_access, 0664, show_pmic_access, store_pmic_access); /* * PMIC dump exception */ static int pmic_dump_exception_show(struct seq_file *s, void *unused) { both_dump_exception_reg(s); return 0; } static int pmic_dump_exception_open(struct inode *inode, struct file *file) { return single_open(file, pmic_dump_exception_show, NULL); } const struct file_operations pmic_dump_exception_operations = { .open = pmic_dump_exception_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; /* * PMIC debug level */ /*-------pmic_dbg_level-------*/ static ssize_t pmic_dbg_level_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) { char info[10]; unsigned int value = 0; int ret = 0; memset(info, 0, 10); ret = simple_write_to_buffer(info, sizeof(info) - 1, ppos, buf, size); if (ret < 0) return ret; ret = kstrtou32(info, 16, (unsigned int *)&value); if (ret) return ret; pr_info("[%s] value=0x%x\n", __func__, value); if (value != 0xFFFF) { pmic_dbg_level_set(value); pr_info("D %d, HK %d, IRQ %d, REG %d, COM %d\n", gPMICDbgLvl, gPMICHKDbgLvl, gPMICIRQDbgLvl, gPMICREGDbgLvl, gPMICCOMDbgLvl); } return size; } static int pmic_dbg_level_show(struct seq_file *s, void *unused) { seq_puts(s, "4:PMIC_LOG_DBG\n"); seq_puts(s, "3:PMIC_LOG_INFO\n"); seq_puts(s, "2:PMIC_LOG_NOT\n"); seq_puts(s, "1:PMIC_LOG_WARN\n"); seq_puts(s, "0:PMIC_LOG_ERR\n"); seq_printf(s, "PMIC_Dbg_Lvl = %d\n", gPMICDbgLvl); seq_printf(s, "PMIC_HK_Dbg_Lvl = %d\n", gPMICHKDbgLvl); seq_printf(s, "PMIC_IRQ_Dbg_Lvl = %d\n", gPMICIRQDbgLvl); seq_printf(s, "PMIC_REG_Dbg_Lvl = %d\n", gPMICREGDbgLvl); seq_printf(s, "PMIC_COM_Dbg_Lvl = %d\n", gPMICCOMDbgLvl); return 0; } static int pmic_dbg_level_open(struct inode *inode, struct file *file) { return single_open(file, pmic_dbg_level_show, NULL); } static const struct file_operations pmic_dbg_level_operations = { .open = pmic_dbg_level_open, .read = seq_read, .write = pmic_dbg_level_write, .llseek = seq_lseek, .release = single_release, }; /* * PMIC reg cmp log */ /*----------------pmic reg cmp machanism-----------------------*/ void __attribute__ ((weak)) pmic_cmp_register(struct seq_file *m) { } static int proc_cmp_register_show(struct seq_file *m, void *v) { seq_puts(m, "*****Compare PMIC registers with initial setting*****\n"); pmic_cmp_register(m); return 0; } static int proc_cmp_register_open(struct inode *inode, struct file *file) { return single_open(file, proc_cmp_register_show, NULL); } static const struct file_operations pmic_cmp_register_proc_fops = { .open = proc_cmp_register_open, .read = seq_read, }; /* * PMIC reg dump log */ /*----------------pmic reg dump machanism-----------------------*/ static int proc_dump_register_show(struct seq_file *m, void *v) { seq_puts(m, "********** dump PMIC registers**********\n"); pmic_dump_register(m); return 0; } static int proc_dump_register_open(struct inode *inode, struct file *file) { return single_open(file, proc_dump_register_show, NULL); } static const struct file_operations pmic_dump_register_proc_fops = { .open = proc_dump_register_open, .read = seq_read, }; int __attribute__ ((weak)) pmic_irq_debug_init(struct dentry *debug_dir) { return 0; } int pmic_debug_init(struct platform_device *dev) { struct dentry *mtk_pmic_dir; int ret_device_file = 0; mtk_pmic_dir = debugfs_create_dir("mtk_pmic", NULL); if (!mtk_pmic_dir) { pr_notice(PMICTAG "fail to mkdir /sys/kernel/debug/mtk_pmic\n"); return -ENOMEM; } /*--/sys/kernel/debug/mtk_pmic--*/ debugfs_create_file("dump_pmic_reg", 0644, mtk_pmic_dir, NULL, &pmic_dump_register_proc_fops); debugfs_create_file("cmp_pmic_reg", 0644, mtk_pmic_dir, NULL, &pmic_cmp_register_proc_fops); debugfs_create_file("pmic_dump_exception", (S_IFREG | 0444), mtk_pmic_dir, NULL, &pmic_dump_exception_operations); debugfs_create_file("pmic_dbg_level", (S_IFREG | 0444), mtk_pmic_dir, NULL, &pmic_dbg_level_operations); pmic_regulator_debug_init(dev, mtk_pmic_dir); pmic_throttling_dlpt_debug_init(dev, mtk_pmic_dir); pmic_irq_debug_init(mtk_pmic_dir); lbat_debug_init(mtk_pmic_dir); PMICLOG("%s debugfs done\n", __func__); /*--/sys/devices/platform/mt-pmic/ --*/ ret_device_file = device_create_file(&(dev->dev), &dev_attr_pmic_access); PMICLOG("%s dev attr done\n", __func__); return 0; } MODULE_AUTHOR("Jimmy-YJ Huang"); MODULE_DESCRIPTION("MT PMIC DEBUGFS Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0.0_M");