Charger Warning Message

本文介绍了一种使用PMIC_RGS_VCDT_HV_DET来判断充电器是否具有过压保护(ovp)的方法。LV_VTH电压阈值设定为4.15V,此技术应用于电源管理和电池充电保护领域。

1070734-20170426133906022-1961912723.png
使用 PMIC_RGS_VCDT_HV_DET 判斷 charger 是否有 ovp。
LV_VTH : 4.15V

转载于:https://www.cnblogs.com/youchihwang/p/6768146.html

#include <linux/module.h> #include <linux/device.h> #include <linux/err.h> #include <linux/slab.h> #include <linux/kdev_t.h> #include <linux/idr.h> #include <linux/thermal.h> #include <linux/reboot.h> #include <linux/string.h> #include <linux/of.h> #include <net/netlink.h> #include <net/genetlink.h> #include <linux/suspend.h> #include <linux/cpu_cooling.h> #include <linux/soc/qcom/panel_event_notifier.h> #include <linux/pm_qos.h> #include <linux/cpufreq.h> #include <linux/kobject.h> #include <linux/kernfs.h> #include <linux/workqueue.h> #include <linux/power_supply.h> #include "../base/base.h" #include "thermal_core.h" #if defined(CONFIG_DRM_PANEL) static struct drm_panel *prim_panel; #endif #define BOOST_BUFFER_SIZE 128 #define BOARD__BUFFER_SIZE 128 #define TEMP_AWARE_MAX 10 #define TEMP_AWARE_MIN 0 static struct class *power_debug_class; static uint8_t temp_aware_mode = TEMP_AWARE_MAX; struct mi_thermal_device { struct device *dev; struct class *class; struct attribute_group attrs; }; struct freq_table { u32 frequency; }; struct cpufreq_device { int id; unsigned int cpufreq_state; unsigned int max_level; struct freq_table *freq_table; /* In descending order */ struct cpufreq_policy *policy; struct list_head node; struct freq_qos_request *qos_req; }; #ifdef CONFIG_MI_THERMAL_MULTI_CHARGE struct usb_monitor { struct notifier_block psy_nb; struct work_struct usb_state_work; int usb_online; }; static struct usb_monitor usb_state; static atomic_t charger_mode = ATOMIC_INIT(-1); #endif static struct mi_thermal_device mi_thermal_dev; static int screen_state = 0; static int screen_light = 0; #if IS_ENABLED(CONFIG_HAVE_MULTI_SCREEN) static void *cookie_sec = NULL; static struct drm_panel *sec_panel; static int retry_count_sec = 10; #endif static int screen_last_status = 0; static void *cookie = NULL; static atomic_t temp_state = ATOMIC_INIT(0); static atomic_t switch_mode = ATOMIC_INIT(-1); static atomic_t balance_mode = ATOMIC_INIT(0); static atomic_t modem_limit = ATOMIC_INIT(0); static atomic_t market_download_limit = ATOMIC_INIT(0); static atomic_t board_sensor_temp_comp_default = ATOMIC_INIT(0); static atomic_t cpu_nolimit_temp_default = ATOMIC_INIT(0); static atomic_t poor_modem_limit= ATOMIC_INIT(0); static atomic_t wifi_limit = ATOMIC_INIT(0); static atomic_t flash_state = ATOMIC_INIT(0); static atomic_t modem_rate = ATOMIC_INIT(0); static atomic_t modem_level = ATOMIC_INIT(0); static atomic_t thermal_max_brightness = ATOMIC_INIT(0); static char boost_buf[128]; const char *board_sensor; static char board_sensor_temp[128]; static char board_sensor_second_temp[128]; static char board_sensor_other_temp[128]; static char ambient_sensor_temp[128]; const char *ambient_sensor; #ifdef CONFIG_HAVE_CHARGE_TEMP static char board_sensor_charge_temp[128]; #endif static LIST_HEAD(cpufreq_dev_list); static DEFINE_MUTEX(cpufreq_list_lock); static DEFINE_PER_CPU(struct freq_qos_request, qos_req); static struct workqueue_struct *screen_state_wq; static struct delayed_work screen_state_dw; #if IS_ENABLED(CONFIG_XIAOMI_SMART_CHG) /*mi_thermal_notifier*/ SRCU_NOTIFIER_HEAD(mi_thermal_notifier); EXPORT_SYMBOL_GPL(mi_thermal_notifier); int mi_thermal_reg_notifier(struct notifier_block *nb) { return srcu_notifier_chain_register(&mi_thermal_notifier, nb); } EXPORT_SYMBOL_GPL(mi_thermal_reg_notifier); int mi_thermal_unreg_notifier(struct notifier_block *nb) { return srcu_notifier_chain_unregister(&mi_thermal_notifier, nb); } EXPORT_SYMBOL_GPL(mi_thermal_unreg_notifier); int mi_thermal_notifier_call_chain(unsigned long event, int val) { return srcu_notifier_call_chain(&mi_thermal_notifier, event, &val); } EXPORT_SYMBOL_GPL(mi_thermal_notifier_call_chain); #endif static int cpufreq_set_level(struct cpufreq_device *cdev, unsigned long state) { /* Request state should be less than max_level */ if (WARN_ON(state > cdev->max_level)) return -EINVAL; /* Check if the old cooling action is same as new cooling action */ if (cdev->cpufreq_state == state) return 0; cdev->cpufreq_state = state; return freq_qos_update_request(cdev->qos_req,cdev->freq_table[state].frequency); } void cpu_limits_set_level(unsigned int cpu, unsigned int max_freq) { struct cpufreq_device *cpufreq_dev; unsigned int level = 0; list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { if (cpufreq_dev->id == cpu) { for (level = 0; level <= cpufreq_dev->max_level; level++) { int target_freq = cpufreq_dev->freq_table[level].frequency; if (max_freq >= target_freq) { cpufreq_set_level(cpufreq_dev, level); break; } } break; } } } static unsigned int find_next_max(struct cpufreq_frequency_table *table, unsigned int prev_max) { struct cpufreq_frequency_table *pos; unsigned int max = 0; cpufreq_for_each_valid_entry(pos, table) { if (pos->frequency > max && pos->frequency < prev_max) max = pos->frequency; } return max; } static int cpu_thermal_init(void) { int cpu, ret; struct cpufreq_policy *policy; struct freq_qos_request *req; for_each_possible_cpu(cpu) { unsigned int i; unsigned int freq; struct cpufreq_device *cpufreq_dev; req = &per_cpu(qos_req, cpu); policy = cpufreq_cpu_get(cpu); if (!policy) { pr_err("%s: cpufreq policy not found for cpu%d\n", __func__, cpu); return -ESRCH; } printk(KERN_ERR "%s cpu=%d\n", __func__, cpu); i = cpufreq_table_count_valid_entries(policy); if (!i) { pr_debug("%s: CPUFreq table not found or has no valid entries\n", __func__); return -ENODEV; } cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); if (!cpufreq_dev) return -ENOMEM; cpufreq_dev->policy = policy; cpufreq_dev->qos_req = req; /* max_level is an index, not a counter */ cpufreq_dev->max_level = i - 1; cpufreq_dev->id = policy->cpu; cpufreq_dev->freq_table = kmalloc_array(i, sizeof(*cpufreq_dev->freq_table), GFP_KERNEL); if (!cpufreq_dev->freq_table) return -ENOMEM; /* Fill freq-table in descending order of frequencies */ for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { freq = find_next_max(policy->freq_table, freq); cpufreq_dev->freq_table[i].frequency = freq; /* Warn for duplicate entries */ if (!freq) pr_warn("%s: table has duplicate entries\n", __func__); else pr_debug("%s: freq:%u KHz\n", __func__, freq); } ret = freq_qos_add_request(&policy->constraints, cpufreq_dev->qos_req, FREQ_QOS_MAX, cpufreq_dev->freq_table[0].frequency); if (ret < 0) { pr_err("%s: Failed to add freq constraint (%d)\n", __func__, ret); return ret; } mutex_lock(&cpufreq_list_lock); list_add(&cpufreq_dev->node, &cpufreq_dev_list); mutex_unlock(&cpufreq_list_lock); } return ret; } static void destory_thermal_cpu(void){ struct cpufreq_device *priv, *tmp; list_for_each_entry_safe(priv, tmp, &cpufreq_dev_list, node) { freq_qos_remove_request(priv->qos_req); list_del(&priv->node); kfree(priv->freq_table); kfree(priv); } } static ssize_t thermal_temp_state_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&temp_state)); } static ssize_t thermal_temp_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&temp_state, val); return len; } static DEVICE_ATTR(temp_state, 0664, thermal_temp_state_show, thermal_temp_state_store); static ssize_t thermal_max_brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&thermal_max_brightness)); } static ssize_t thermal_max_brightness_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&thermal_max_brightness, val); return len; } static DEVICE_ATTR(thermal_max_brightness, 0664, thermal_max_brightness_show, thermal_max_brightness_store); static ssize_t cpu_limits_show(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } static ssize_t cpu_limits_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { unsigned int cpu; unsigned int max; if (sscanf(buf, "cpu%u %u", &cpu, &max) != 2) { pr_err("input param error, can not prase param\n"); return -EINVAL; } cpu_limits_set_level(cpu, max); return len; } static DEVICE_ATTR(cpu_limits, 0664, cpu_limits_show, cpu_limits_store); static ssize_t thermal_screen_state_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", screen_state); } static DEVICE_ATTR(screen_state, 0664, thermal_screen_state_show, NULL); static ssize_t thermal_sconfig_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&switch_mode)); } static ssize_t thermal_sconfig_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; #if IS_ENABLED(CONFIG_XIAOMI_SMART_CHG) int ret = 0; #endif val = simple_strtol(buf, NULL, 10); atomic_set(&switch_mode, val); #if IS_ENABLED(CONFIG_XIAOMI_SMART_CHG) ret = mi_thermal_notifier_call_chain(THERMAL_SCENE, atomic_read(&switch_mode)); if (ret) { pr_err("%s: mi_thermal_notifier_call_chain error:%d\n", __func__, ret); } #endif return len; } static ssize_t thermal_boost_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, boost_buf); } static ssize_t thermal_boost_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int ret; ret = snprintf(boost_buf, BOOST_BUFFER_SIZE, buf); return len; } static ssize_t thermal_balance_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&balance_mode)); } static ssize_t thermal_balance_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&balance_mode, val); return len; } static ssize_t thermal_market_download_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&market_download_limit)); } static ssize_t thermal_market_download_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&market_download_limit, val); return len; } static DEVICE_ATTR(boost, 0644, thermal_boost_show, thermal_boost_store); static DEVICE_ATTR(sconfig, 0664, thermal_sconfig_show, thermal_sconfig_store); static DEVICE_ATTR(balance_mode, 0664, thermal_balance_mode_show, thermal_balance_mode_store); static DEVICE_ATTR(market_download_limit, 0664, thermal_market_download_limit_show, thermal_market_download_limit_store); static ssize_t thermal_board_sensor_show(struct device *dev, struct device_attribute *attr, char *buf) { if (!board_sensor) board_sensor = "invalid"; return snprintf(buf, PAGE_SIZE, "%s", board_sensor); } static DEVICE_ATTR(board_sensor, 0664, thermal_board_sensor_show, NULL); static ssize_t thermal_board_sensor_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, board_sensor_temp); } static ssize_t thermal_board_sensor_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { #if IS_ENABLED(CONFIG_XIAOMI_SMART_CHG) int ret = 0; int val = -1; #endif snprintf(board_sensor_temp, BOARD__BUFFER_SIZE, buf); #if IS_ENABLED(CONFIG_XIAOMI_SMART_CHG) val = simple_strtol(buf, NULL, 10); ret = mi_thermal_notifier_call_chain(THERMAL_BOARD_TEMP, val/100); if (ret) { pr_err("%s: mi_thermal_notifier_call_chain error:%d\n", __func__, ret); } #endif return len; } static DEVICE_ATTR(board_sensor_temp, 0664, thermal_board_sensor_temp_show, thermal_board_sensor_temp_store); static ssize_t thermal_modem_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&modem_rate)); } static ssize_t thermal_modem_rate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&modem_rate, val); return len; } static DEVICE_ATTR(modem_rate, 0664, thermal_modem_rate_show, thermal_modem_rate_store); static ssize_t thermal_modem_level_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&modem_level)); } static ssize_t thermal_modem_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&modem_level, val); return len; } static DEVICE_ATTR(modem_level, 0664, thermal_modem_level_show, thermal_modem_level_store); static ssize_t thermal_board_sensor_second_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, board_sensor_second_temp); } static ssize_t thermal_board_sensor_second_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { snprintf(board_sensor_second_temp, BOARD__BUFFER_SIZE, buf); return len; } static DEVICE_ATTR(board_sensor_second_temp, 0664, thermal_board_sensor_second_temp_show, thermal_board_sensor_second_temp_store); static ssize_t thermal_board_sensor_other_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, board_sensor_other_temp); } static ssize_t thermal_board_sensor_other_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { snprintf(board_sensor_other_temp, BOARD__BUFFER_SIZE, buf); return len; } static DEVICE_ATTR(board_sensor_other_temp, 0664, thermal_board_sensor_other_temp_show, thermal_board_sensor_other_temp_store); static ssize_t thermal_ambient_sensor_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s", "ABT-SENSOR"); } static DEVICE_ATTR(ambient_sensor, 0664, thermal_ambient_sensor_show, NULL); static ssize_t thermal_ambient_sensor_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, ambient_sensor_temp); } static ssize_t thermal_ambient_sensor_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { snprintf(ambient_sensor_temp, BOARD__BUFFER_SIZE, buf); return len; } static DEVICE_ATTR(ambient_sensor_temp, 0664, thermal_ambient_sensor_temp_show, thermal_ambient_sensor_temp_store); #ifdef CONFIG_HAVE_CHARGE_TEMP static ssize_t thermal_board_sensor_charge_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, board_sensor_charge_temp); } static ssize_t thermal_board_sensor_charge_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { snprintf(board_sensor_charge_temp, BOARD__BUFFER_SIZE, buf); return len; } static DEVICE_ATTR(board_sensor_charge_temp, 0664, thermal_board_sensor_charge_temp_show, thermal_board_sensor_charge_temp_store); #endif static ssize_t thermal_modem_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&modem_limit)); } static ssize_t thermal_modem_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&modem_limit, val); return len; } static DEVICE_ATTR(modem_limit, 0664, thermal_modem_limit_show, thermal_modem_limit_store); static ssize_t thermal_wifi_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&wifi_limit)); } static ssize_t thermal_wifi_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&wifi_limit, val); return len; } static DEVICE_ATTR(wifi_limit, 0664, thermal_wifi_limit_show, thermal_wifi_limit_store); static ssize_t thermal_flash_state_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&flash_state)); } static ssize_t thermal_flash_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&flash_state, val); return len; } static DEVICE_ATTR(flash_state, 0664, thermal_flash_state_show, thermal_flash_state_store); static ssize_t thermal_board_sensor_temp_comp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&board_sensor_temp_comp_default)); } static ssize_t thermal_board_sensor_temp_comp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&board_sensor_temp_comp_default, val); return len; } static DEVICE_ATTR(board_sensor_temp_comp, 0664, thermal_board_sensor_temp_comp_show, thermal_board_sensor_temp_comp_store); static ssize_t thermal_poor_modem_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&poor_modem_limit)); } static ssize_t thermal_poor_modem_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&poor_modem_limit, val); return len; } static DEVICE_ATTR(poor_modem_limit, 0664, thermal_poor_modem_limit_show, thermal_poor_modem_limit_store); static ssize_t thermal_cpu_nolimit_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&cpu_nolimit_temp_default)); } static ssize_t thermal_cpu_nolimit_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&cpu_nolimit_temp_default, val); return len; } static ssize_t temp_aware_show (struct class *cls, struct class_attribute *attr, char *buf) { int mode = 0; mode = scnprintf(buf, PAGE_SIZE, "%d\n", temp_aware_mode); return mode; } static ssize_t temp_aware_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count) { unsigned long val; if (kstrtoul(buf, 10, &val)) return -EINVAL; if (TEMP_AWARE_MIN <= val && val < TEMP_AWARE_MAX) temp_aware_mode = val; return count; } static DEVICE_ATTR(cpu_nolimit_temp, 0664, thermal_cpu_nolimit_temp_show, thermal_cpu_nolimit_temp_store); #ifdef CONFIG_MI_THERMAL_MULTI_CHARGE static ssize_t thermal_charger_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&charger_mode)); } static ssize_t thermal_charger_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int val = -1; val = simple_strtol(buf, NULL, 10); atomic_set(&charger_mode, val); return len; } static DEVICE_ATTR(charger_temp, 0664, thermal_charger_temp_show, thermal_charger_temp_store); static ssize_t thermal_usb_online_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", usb_state.usb_online); } static DEVICE_ATTR(usb_online, 0664, thermal_usb_online_show, NULL); static int usb_online_callback(struct notifier_block *nb, unsigned long val, void *data) { struct power_supply *psy = data; if (strcmp(psy->desc->name, "usb")) return NOTIFY_OK; schedule_work(&usb_state.usb_state_work); return NOTIFY_OK; } static void usb_online_work(struct work_struct *work) { static struct power_supply *usb_psy; union power_supply_propval ret = {0,}; int err = 0; if (!usb_psy) usb_psy = power_supply_get_by_name("usb"); if (usb_psy) { err = power_supply_get_property(usb_psy, POWER_SUPPLY_PROP_ONLINE, &ret); if (err) { pr_err("usb online read error:%d\n",err); return; } usb_state.usb_online = ret.intval; if (mi_thermal_dev.dev) sysfs_notify(&mi_thermal_dev.dev->kobj, NULL, "usb_online"); } } #endif static int of_parse_thermal_message(void) { struct device_node *np; np = of_find_node_by_name(NULL, "thermal-message"); if (!np) return -EINVAL; if (of_property_read_string(np, "board-sensor", &board_sensor)) return -EINVAL; pr_info("%s board sensor: %s\n", __func__, board_sensor); return 0; } static struct class_attribute power_debug_attrs[] = { __ATTR(temp_aware, 0664, temp_aware_show, temp_aware_store), __ATTR_NULL }; static struct attribute *mi_thermal_dev_attr_group[] = { &dev_attr_temp_state.attr, &dev_attr_cpu_limits.attr, &dev_attr_sconfig.attr, &dev_attr_screen_state.attr, &dev_attr_boost.attr, &dev_attr_board_sensor.attr, &dev_attr_board_sensor_temp.attr, &dev_attr_board_sensor_second_temp.attr, &dev_attr_board_sensor_other_temp.attr, &dev_attr_balance_mode.attr, &dev_attr_modem_limit.attr, &dev_attr_wifi_limit.attr, &dev_attr_flash_state.attr, &dev_attr_thermal_max_brightness.attr, &dev_attr_market_download_limit.attr, &dev_attr_board_sensor_temp_comp.attr, &dev_attr_poor_modem_limit.attr, &dev_attr_cpu_nolimit_temp.attr, &dev_attr_modem_rate.attr, &dev_attr_modem_level.attr, &dev_attr_ambient_sensor.attr, &dev_attr_ambient_sensor_temp.attr, #ifdef CONFIG_HAVE_CHARGE_TEMP &dev_attr_board_sensor_charge_temp.attr, #endif #ifdef CONFIG_MI_THERMAL_MULTI_CHARGE &dev_attr_charger_temp.attr, &dev_attr_usb_online.attr, #endif NULL, }; static const char *get_screen_state_name(int mode) { switch (mode) { case DRM_PANEL_EVENT_UNBLANK: return "On"; case DRM_PANEL_EVENT_BLANK_LP: return "Doze"; case DRM_PANEL_EVENT_BLANK: return "Off"; default: return "Unknown"; } } static void screen_state_for_thermal_callback(enum panel_event_notifier_tag tag, struct panel_event_notification *notification, void *client_data) { if (!notification) { printk(KERN_ERR "%s:Invalid notification\n", __func__); return; } if(notification->notif_data.early_trigger) { return; } if(tag == PANEL_EVENT_NOTIFICATION_PRIMARY){ switch (notification->notif_type) { case DRM_PANEL_EVENT_UNBLANK: screen_light = screen_light | 0x1; break; case DRM_PANEL_EVENT_BLANK: case DRM_PANEL_EVENT_BLANK_LP: screen_light = screen_light & 0x2; break; case DRM_PANEL_EVENT_FPS_CHANGE: return; default: return; } printk(KERN_ERR "%s: %s, screen_light = %d, %s\n", __func__, get_screen_state_name(notification->notif_type), screen_light, board_sensor_temp); } #if IS_ENABLED(CONFIG_HAVE_MULTI_SCREEN) else if (tag == PANEL_EVENT_NOTIFICATION_SECONDARY) { switch (notification->notif_type) { case DRM_PANEL_EVENT_UNBLANK: screen_light = screen_light | 0x2; break; case DRM_PANEL_EVENT_BLANK: case DRM_PANEL_EVENT_BLANK_LP: screen_light = screen_light & 0x1; break; case DRM_PANEL_EVENT_FPS_CHANGE: return; default: return; } printk(KERN_ERR "%s: %s, sencondery_screen_light = %d, %s\n", __func__, get_screen_state_name(notification->notif_type), screen_light, board_sensor_temp); } #endif if (screen_light) { screen_state = 1; printk(KERN_ERR "%s: screen_light = %d, so screen_state = %d, %s\n", __func__, screen_light, screen_state, board_sensor_temp); } else { screen_state = 0; printk(KERN_ERR "%s: screen_light = %d, so screen_state = %d, %s\n", __func__, screen_light, screen_state, board_sensor_temp); } if (screen_last_status != screen_state) { sysfs_notify(&mi_thermal_dev.dev->kobj, NULL, "screen_state"); screen_last_status = screen_state; } } static int thermal_check_panel(struct device_node *np) { int i; int count; struct device_node *node; struct drm_panel *panel; count = of_count_phandle_with_args(np, "panel", NULL); printk(KERN_ERR "%s: count of panel in node is: %d\n",__func__ ,count); if (count <= 0){ #if IS_ENABLED(CONFIG_HAVE_MULTI_SCREEN) goto find_sec_panel; #endif goto out; } for (i = 0; i < count; i++) { node = of_parse_phandle(np, "panel", i); printk(KERN_ERR "%s: try to add of node panel: %s\n",__func__ ,node); panel = of_drm_find_panel(node); of_node_put(node); if (!IS_ERR(panel)) { prim_panel = panel; break; }else{ prim_panel = NULL; } } if (PTR_ERR(prim_panel) == -EPROBE_DEFER) { pr_err("%s ERROR: Cannot fine prim_panel of node!", __func__); } printk(KERN_ERR "%s: count of panel in node PTR_ERR_prim_panel is: %d\n",__func__ , PTR_ERR(prim_panel)); #if IS_ENABLED(CONFIG_HAVE_MULTI_SCREEN) find_sec_panel: count = of_count_phandle_with_args(np, "panel1", NULL); printk(KERN_ERR "%s: count of panel1 in node is: %d\n",__func__ , count); if (count <= 0){ goto out; } for (i = 0; i < count; i++) { node = of_parse_phandle(np, "panel1", i); printk(KERN_ERR "%s: try to add of node panel1: %s\n",__func__ , node); panel = of_drm_find_panel(node); of_node_put(node); if (!IS_ERR(panel)) { sec_panel = panel; break; } } if (PTR_ERR(sec_panel) == -EPROBE_DEFER) { pr_err("%s ERROR: Cannot fine sec_panel of node!", __func__); } printk(KERN_ERR "%s: count of panel1 in node PTR_ERR_sec_panel is: %d\n",__func__ , PTR_ERR(sec_panel)); #endif out: return 0; } static void create_thermal_message_node(void) { int ret = 0; struct kernfs_node *sysfs_sd = NULL; struct kernfs_node *thermal_sd = NULL; struct kernfs_node *class_sd = NULL; struct class *cls = NULL; struct subsys_private *cp = NULL; struct kobject *kobj_tmp = NULL; sysfs_sd = kernel_kobj->sd->parent; if (!sysfs_sd) { printk(KERN_ERR "%s: sysfs_sd is NULL\n", __func__); } else { class_sd = kernfs_find_and_get(sysfs_sd, "class"); if (!class_sd) { printk(KERN_ERR "%s:can not find class_sd\n", __func__); } else { thermal_sd = kernfs_find_and_get(class_sd, "thermal"); if (thermal_sd) { kobj_tmp = (struct kobject *)thermal_sd->priv; if (kobj_tmp) { cp = to_subsys_private(kobj_tmp); cls = cp->class; } else { printk(KERN_ERR "%s:can not find thermal kobj\n", __func__); } } else { printk(KERN_ERR "%s:can not find thermal_sd\n", __func__); } } } if (!mi_thermal_dev.class && cls) { mi_thermal_dev.class = cls; mi_thermal_dev.dev = device_create(mi_thermal_dev.class, NULL, 'H', NULL, "thermal_message"); if (!mi_thermal_dev.dev) { pr_err("%s create device dev err\n", __func__); return; } mi_thermal_dev.attrs.attrs = mi_thermal_dev_attr_group; ret = sysfs_create_group(&mi_thermal_dev.dev->kobj, &mi_thermal_dev.attrs); if (ret) { pr_err("%s ERROR: Cannot create sysfs structure!:%d\n", __func__, ret); return; } } } static int __init power_debug_init(void) { int ret; int i; power_debug_class = class_create(THIS_MODULE, "power_debug"); if (IS_ERR(power_debug_class)) { ret = PTR_ERR(power_debug_class); pr_err("Failed to create power_debug class: %d\n", ret); return ret; } for (i = 0; power_debug_attrs[i].attr.name!= NULL; i++){ ret = class_create_file(power_debug_class, &power_debug_attrs[i]); if (ret != 0){ pr_err("Failed to create temp_aware attribute: %d\n", ret); class_destroy(power_debug_class); } } pr_info("power_debug module loaded\n"); return 0; } static void __exit power_debug_exit(void) { int i; for (i = 0; power_debug_attrs[i].attr.name!= NULL; i++){ class_remove_file(power_debug_class, &power_debug_attrs[i]); } class_destroy(power_debug_class); pr_info("power_debug module unloaded\n"); } static void destroy_thermal_message_node(void) { printk(KERN_ERR "%s:destroy_thermal_message_node", __func__); sysfs_remove_group(&mi_thermal_dev.dev->kobj, &mi_thermal_dev.attrs); if (NULL != mi_thermal_dev.class){ device_destroy(mi_thermal_dev.class,'H'); mi_thermal_dev.class = NULL; } } static void screen_state_check(struct work_struct *work) { #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) struct device_node *node; void *pvt_data = NULL; int error = 0; static int retry_count = 10; cpu_thermal_init(); node = of_find_node_by_name(NULL, "thermal-screen"); if (!node) { pr_err("%s ERROR: Cannot find node with panel!", __func__); return; } error = thermal_check_panel(node); if (prim_panel) { if (!cookie) { cookie = panel_event_notifier_register(PANEL_EVENT_NOTIFICATION_PRIMARY, PANEL_EVENT_NOTIFIER_CLIENT_THERMAL, prim_panel, screen_state_for_thermal_callback, pvt_data); if (IS_ERR(cookie)) printk(KERN_ERR "%s:Failed to register for prim_panel events\n", __func__); else printk(KERN_ERR "%s:prim_panel_event_notifier_register register succeed\n", __func__); } } else if (retry_count > 0) { printk(KERN_ERR "%s:prim_panel is NULL Failed to register for panel events\n", __func__); retry_count--; queue_delayed_work(screen_state_wq, &screen_state_dw, 5 * HZ); } #if IS_ENABLED(CONFIG_HAVE_MULTI_SCREEN) if (sec_panel) { if (!cookie_sec) { cookie_sec = panel_event_notifier_register(PANEL_EVENT_NOTIFICATION_SECONDARY, PANEL_EVENT_NOTIFIER_CLIENT_THERMAL_SECOND, sec_panel, screen_state_for_thermal_callback, pvt_data); if (IS_ERR(cookie_sec)) printk(KERN_ERR "%s:Failed to register for sec_panel events\n", __func__); else printk(KERN_ERR "%s:sec_panel_event_notifier_register register succeed\n", __func__); } } else if (retry_count_sec > 0) { printk(KERN_ERR "%s:sec_panel is NULL Failed to register for panel events\n", __func__); retry_count_sec--; queue_delayed_work(screen_state_wq, &screen_state_dw, 5 * HZ); } #endif #endif } static int __init mi_thermal_interface_init(void) { int result; #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) screen_state_wq = create_singlethread_workqueue("screen_state_wq"); if (screen_state_wq) { INIT_DELAYED_WORK(&screen_state_dw, screen_state_check); queue_delayed_work(screen_state_wq, &screen_state_dw, 5 * HZ); } #endif result = of_parse_thermal_message(); if (result) printk(KERN_ERR "%s:Thermal: Can not parse thermal message node, return %d\n", __func__,result); create_thermal_message_node(); #ifdef CONFIG_MI_THERMAL_MULTI_CHARGE INIT_WORK(&usb_state.usb_state_work, usb_online_work); usb_state.psy_nb.notifier_call=usb_online_callback; result = power_supply_reg_notifier(&usb_state.psy_nb); if (result < 0) { pr_err("usb online notifier registration error. return: %d\n", result); } #endif power_debug_init(); return 0; } static void __exit mi_thermal_interface_exit(void) { #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) if (screen_state_wq) { cancel_delayed_work_sync(&screen_state_dw); destroy_workqueue(screen_state_wq); } if (prim_panel && !IS_ERR(cookie)) { panel_event_notifier_unregister(cookie); } else { printk(KERN_ERR "%s:prim_panel_event_notifier_unregister falt\n", __func__); } #if IS_ENABLED(CONFIG_HAVE_MULTI_SCREEN) if (sec_panel && !IS_ERR(cookie_sec)) { panel_event_notifier_unregister(cookie_sec); } else { printk(KERN_ERR "%s:sec_panel_event_notifier_unregister falt\n", __func__); } #endif #endif destroy_thermal_message_node(); power_debug_exit(); destory_thermal_cpu(); } module_init(mi_thermal_interface_init); module_exit(mi_thermal_interface_exit); MODULE_AUTHOR("Xiaomi thermal team"); MODULE_DESCRIPTION("Xiaomi thermal control interface"); MODULE_LICENSE("GPL v2");
12-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值