1303 lines
33 KiB
C
1303 lines
33 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/err.h>
|
|
#include <linux/syscalls.h>
|
|
#include "mt-plat/mtk_thermal_monitor.h"
|
|
#include <linux/uidgid.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/fb.h>
|
|
#include "mach/mtk_thermal.h"
|
|
|
|
|
|
#define CONFIG_MTK_GAUGE_VERSION 30
|
|
/* ************************************ */
|
|
/* Weak functions */
|
|
/* ************************************ */
|
|
int __attribute__ ((weak))
|
|
get_bat_charging_current_level(void)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 500;
|
|
}
|
|
int __attribute__ ((weak))
|
|
mt_get_charger_type(void)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
set_bat_charging_current_limit(int current_limit)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
unsigned int __attribute__ ((weak))
|
|
set_chr_input_current_limit(int current_limit)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_soc(unsigned int *soc)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_ui_soc(unsigned int *ui_soc)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_vbat(unsigned int *vbat)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_ibat(unsigned int *ibat)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_vbus(unsigned int *vbus)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_aicr(unsigned int *aicr)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int __attribute__ ((weak))
|
|
mtk_chr_get_tchr(int *min_temp, int *max_temp)
|
|
{
|
|
pr_notice("E_WF: %s doesn't exist\n", __func__);
|
|
return 0;
|
|
}
|
|
/* ************************************ */
|
|
|
|
#define mtk_cooler_bcct_dprintk_always(fmt, args...) \
|
|
pr_notice("[Thermal/TC/bcct]" fmt, ##args)
|
|
|
|
#define mtk_cooler_bcct_dprintk(fmt, args...) \
|
|
do { \
|
|
if (cl_bcct_klog_on == 1) \
|
|
pr_debug("[Thermal/TC/bcct]" fmt, ##args); \
|
|
} while (0)
|
|
|
|
#define MAX_NUM_INSTANCE_MTK_COOLER_BCCT 3
|
|
|
|
#define MTK_CL_BCCT_GET_LIMIT(limit, state) \
|
|
{(limit) = (short) (((unsigned long) (state))>>16); }
|
|
|
|
#define MTK_CL_BCCT_SET_LIMIT(limit, state) \
|
|
{(state) = ((((unsigned long) (state))&0xFFFF) | ((short) limit<<16)); }
|
|
|
|
#define MTK_CL_BCCT_GET_CURR_STATE(curr_state, state) \
|
|
{(curr_state) = (((unsigned long) (state))&0xFFFF); }
|
|
|
|
#define MTK_CL_BCCT_SET_CURR_STATE(curr_state, state) \
|
|
do { \
|
|
if (0 == (curr_state)) \
|
|
state &= ~0x1; \
|
|
else \
|
|
state |= 0x1; \
|
|
} while (0)
|
|
|
|
static kuid_t uid = KUIDT_INIT(0);
|
|
static kgid_t gid = KGIDT_INIT(1000);
|
|
|
|
#define MIN(_a_, _b_) ((_a_) > (_b_) ? (_b_) : (_a_))
|
|
#define MAX(_a_, _b_) ((_a_) > (_b_) ? (_a_) : (_b_))
|
|
|
|
/* Battery & Charger Status*/
|
|
static int bat_info_soc; /* battery soc */
|
|
static int bat_info_uisoc; /* battery UI soc */
|
|
static int bat_info_vbat; /* battery voltage */
|
|
static int bat_info_ibat; /* charging current */
|
|
static int bat_info_mintchr; /* charger min temp */
|
|
static int bat_info_maxtchr; /* charger max temp */
|
|
static int bat_info_vbus; /* Vbus */
|
|
static int bat_info_aicr; /* input current */
|
|
|
|
|
|
/* Charger Limiter
|
|
* Charger Limiter provides API to limit charger IC input current and
|
|
* battery charging current. It arbitrates the limitation from users and sets
|
|
* limitation to charger driver via two API functions:
|
|
* set_chr_input_current_limit()
|
|
* set_bat_charging_current_limit()
|
|
*/
|
|
int chrlmt_chr_input_curr_limit = -1; /**< -1 is unlimit, unit is mA. */
|
|
int chrlmt_bat_chr_curr_limit = -1; /**< -1 is unlimit, unit is mA. */
|
|
static bool chrlmt_is_lcmoff; /**0 is lcm on, 1 is lcm off */
|
|
static int chrlmt_lcmoff_policy_enable; /**0: No lcmoff abcct */
|
|
|
|
struct chrlmt_handle {
|
|
int chr_input_curr_limit;
|
|
int bat_chr_curr_limit;
|
|
};
|
|
|
|
static struct workqueue_struct *bcct_chrlmt_queue;
|
|
static struct work_struct bcct_chrlmt_work;
|
|
|
|
/* temp solution, use list instead */
|
|
#define CHR_LMT_MAX_USER_COUNT (4)
|
|
|
|
static struct chrlmt_handle
|
|
*chrlmt_registered_users[CHR_LMT_MAX_USER_COUNT] = { 0 };
|
|
|
|
static int chrlmt_register(struct chrlmt_handle *handle)
|
|
{
|
|
int i;
|
|
|
|
if (!handle)
|
|
return -1;
|
|
|
|
handle->chr_input_curr_limit = -1;
|
|
handle->bat_chr_curr_limit = -1;
|
|
|
|
/* find an empty entry */
|
|
for (i = CHR_LMT_MAX_USER_COUNT; --i >= 0; )
|
|
if (!chrlmt_registered_users[i]) {
|
|
chrlmt_registered_users[i] = handle;
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int chrlmt_unregister(struct chrlmt_handle *handle)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int clbcct_get_chr_curr_limit(void)
|
|
{
|
|
return chrlmt_bat_chr_curr_limit;
|
|
}
|
|
|
|
int clbcct_get_input_curr_limit(void)
|
|
{
|
|
return chrlmt_chr_input_curr_limit;
|
|
}
|
|
|
|
static void chrlmt_set_limit_handler(struct work_struct *work)
|
|
{
|
|
|
|
mtk_cooler_bcct_dprintk_always("%s %d %d\n", __func__
|
|
, chrlmt_chr_input_curr_limit,
|
|
chrlmt_bat_chr_curr_limit);
|
|
|
|
#ifdef CONFIG_MTK_SWITCH_INPUT_OUTPUT_CURRENT_SUPPORT
|
|
set_chr_input_current_limit(chrlmt_chr_input_curr_limit);
|
|
#endif
|
|
set_bat_charging_current_limit(chrlmt_bat_chr_curr_limit);
|
|
}
|
|
|
|
static int chrlmt_set_limit(
|
|
struct chrlmt_handle *handle, int chr_input_curr_limit, int bat_char_curr_limit)
|
|
{
|
|
int i;
|
|
int min_char_input_curr_limit = 0xFFFFFF;
|
|
int min_bat_char_curr_limit = 0xFFFFFF;
|
|
|
|
if (!handle)
|
|
return -1;
|
|
|
|
handle->chr_input_curr_limit = chr_input_curr_limit;
|
|
handle->bat_chr_curr_limit = bat_char_curr_limit;
|
|
|
|
for (i = CHR_LMT_MAX_USER_COUNT; --i >= 0; )
|
|
if (chrlmt_registered_users[i]) {
|
|
if (chrlmt_registered_users[i]->chr_input_curr_limit
|
|
> -1)
|
|
min_char_input_curr_limit =
|
|
MIN(
|
|
chrlmt_registered_users[i]->chr_input_curr_limit
|
|
, min_char_input_curr_limit);
|
|
|
|
if (chrlmt_registered_users[i]->bat_chr_curr_limit
|
|
> -1)
|
|
min_bat_char_curr_limit =
|
|
MIN(
|
|
chrlmt_registered_users[i]->bat_chr_curr_limit
|
|
, min_bat_char_curr_limit);
|
|
}
|
|
|
|
if (min_char_input_curr_limit == 0xFFFFFF)
|
|
min_char_input_curr_limit = -1;
|
|
if (min_bat_char_curr_limit == 0xFFFFFF)
|
|
min_bat_char_curr_limit = -1;
|
|
|
|
if ((min_char_input_curr_limit != chrlmt_chr_input_curr_limit)
|
|
|| (min_bat_char_curr_limit != chrlmt_bat_chr_curr_limit)) {
|
|
chrlmt_chr_input_curr_limit = min_char_input_curr_limit;
|
|
chrlmt_bat_chr_curr_limit = min_bat_char_curr_limit;
|
|
|
|
if (bcct_chrlmt_queue)
|
|
queue_work(bcct_chrlmt_queue, &bcct_chrlmt_work);
|
|
|
|
mtk_cooler_bcct_dprintk_always("%s %p %d %d\n", __func__
|
|
, handle, chrlmt_chr_input_curr_limit,
|
|
chrlmt_bat_chr_curr_limit);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int cl_bcct_klog_on;
|
|
static struct thermal_cooling_device
|
|
*cl_bcct_dev[MAX_NUM_INSTANCE_MTK_COOLER_BCCT] = { 0 };
|
|
|
|
static unsigned long cl_bcct_state[MAX_NUM_INSTANCE_MTK_COOLER_BCCT] = { 0 };
|
|
static struct chrlmt_handle cl_bcct_chrlmt_handle;
|
|
|
|
static int cl_bcct_cur_limit = 65535;
|
|
|
|
static void mtk_cl_bcct_set_bcct_limit(void)
|
|
{
|
|
/* TODO: optimize */
|
|
int i = 0;
|
|
int min_limit = 65535;
|
|
|
|
for (; i < MAX_NUM_INSTANCE_MTK_COOLER_BCCT; i++) {
|
|
unsigned long curr_state;
|
|
|
|
MTK_CL_BCCT_GET_CURR_STATE(curr_state, cl_bcct_state[i]);
|
|
if (curr_state == 1) {
|
|
|
|
int limit;
|
|
|
|
MTK_CL_BCCT_GET_LIMIT(limit, cl_bcct_state[i]);
|
|
if ((min_limit > limit) && (limit > 0))
|
|
min_limit = limit;
|
|
}
|
|
}
|
|
|
|
if (min_limit != cl_bcct_cur_limit) {
|
|
cl_bcct_cur_limit = min_limit;
|
|
|
|
if (cl_bcct_cur_limit >= 65535) {
|
|
chrlmt_set_limit(&cl_bcct_chrlmt_handle, -1, -1);
|
|
mtk_cooler_bcct_dprintk("%s limit=-1\n", __func__);
|
|
} else {
|
|
chrlmt_set_limit(&cl_bcct_chrlmt_handle, -1,
|
|
cl_bcct_cur_limit);
|
|
|
|
mtk_cooler_bcct_dprintk("%s limit=%d\n", __func__
|
|
, cl_bcct_cur_limit);
|
|
}
|
|
|
|
mtk_cooler_bcct_dprintk("%s real limit=%d\n", __func__
|
|
, get_bat_charging_current_level() / 100);
|
|
|
|
}
|
|
}
|
|
|
|
static int mtk_cl_bcct_get_max_state(
|
|
struct thermal_cooling_device *cdev, unsigned long *state)
|
|
{
|
|
*state = 1;
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, *state);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_cl_bcct_get_cur_state(
|
|
struct thermal_cooling_device *cdev, unsigned long *state)
|
|
{
|
|
MTK_CL_BCCT_GET_CURR_STATE(*state, *((unsigned long *)cdev->devdata));
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, *state);
|
|
mtk_cooler_bcct_dprintk("%s %s limit=%d\n", __func__, cdev->type,
|
|
get_bat_charging_current_level() / 100);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_cl_bcct_set_cur_state(
|
|
struct thermal_cooling_device *cdev, unsigned long state)
|
|
{
|
|
/*Only active while lcm not off */
|
|
if (chrlmt_is_lcmoff)
|
|
state = 0;
|
|
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, state);
|
|
MTK_CL_BCCT_SET_CURR_STATE(state, *((unsigned long *)cdev->devdata));
|
|
mtk_cl_bcct_set_bcct_limit();
|
|
mtk_cooler_bcct_dprintk("%s %s limit=%d\n", __func__, cdev->type,
|
|
get_bat_charging_current_level() / 100);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* bind fan callbacks to fan device */
|
|
static struct thermal_cooling_device_ops mtk_cl_bcct_ops = {
|
|
.get_max_state = mtk_cl_bcct_get_max_state,
|
|
.get_cur_state = mtk_cl_bcct_get_cur_state,
|
|
.set_cur_state = mtk_cl_bcct_set_cur_state,
|
|
};
|
|
|
|
static int mtk_cooler_bcct_register_ltf(void)
|
|
{
|
|
int i;
|
|
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
chrlmt_register(&cl_bcct_chrlmt_handle);
|
|
|
|
#if (MAX_NUM_INSTANCE_MTK_COOLER_BCCT == 3)
|
|
MTK_CL_BCCT_SET_LIMIT(1000, cl_bcct_state[0]);
|
|
MTK_CL_BCCT_SET_LIMIT(500, cl_bcct_state[1]);
|
|
MTK_CL_BCCT_SET_LIMIT(0, cl_bcct_state[2]);
|
|
#endif
|
|
|
|
for (i = MAX_NUM_INSTANCE_MTK_COOLER_BCCT; i-- > 0;) {
|
|
char temp[20] = { 0 };
|
|
|
|
sprintf(temp, "mtk-cl-bcct%02d", i);
|
|
/* put bcct state to cooler devdata */
|
|
cl_bcct_dev[i] = mtk_thermal_cooling_device_register(
|
|
temp, (void *)&cl_bcct_state[i],
|
|
&mtk_cl_bcct_ops);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mtk_cooler_bcct_unregister_ltf(void)
|
|
{
|
|
int i;
|
|
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
for (i = MAX_NUM_INSTANCE_MTK_COOLER_BCCT; i-- > 0;) {
|
|
if (cl_bcct_dev[i]) {
|
|
mtk_thermal_cooling_device_unregister(cl_bcct_dev[i]);
|
|
cl_bcct_dev[i] = NULL;
|
|
cl_bcct_state[i] = 0;
|
|
}
|
|
}
|
|
|
|
chrlmt_unregister(&cl_bcct_chrlmt_handle);
|
|
}
|
|
|
|
static struct thermal_cooling_device *cl_abcct_dev;
|
|
static unsigned long cl_abcct_state;
|
|
static struct chrlmt_handle abcct_chrlmt_handle;
|
|
static long abcct_prev_temp;
|
|
static long abcct_curr_temp;
|
|
static long abcct_target_temp = 48000;
|
|
static long abcct_kp = 1000;
|
|
static long abcct_ki = 3000;
|
|
static long abcct_kd = 10000;
|
|
static int abcct_max_bat_chr_curr_limit = 3000;
|
|
static int abcct_min_bat_chr_curr_limit = 200;
|
|
static int abcct_cur_bat_chr_curr_limit;
|
|
static int abcct_input_current_limit_on;
|
|
static int abcct_HW_thermal_solution = 3000;
|
|
static int abcct_max_chr_input_curr_limit = 3000;
|
|
static int abcct_min_chr_input_curr_limit = 200;
|
|
static int abcct_cur_chr_input_curr_limit;
|
|
static long abcct_iterm;
|
|
static int abcct_times_of_ts_polling_interval = 1;
|
|
|
|
static int mtk_cl_abcct_get_max_state(
|
|
struct thermal_cooling_device *cdev, unsigned long *state)
|
|
{
|
|
*state = 1;
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, *state);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_cl_abcct_get_cur_state(
|
|
struct thermal_cooling_device *cdev, unsigned long *state)
|
|
{
|
|
*state = cl_abcct_state;
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, *state);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_cl_abcct_set_cur_state(
|
|
struct thermal_cooling_device *cdev, unsigned long state)
|
|
{
|
|
int ret = 0;
|
|
|
|
cl_abcct_state = state;
|
|
|
|
/*Only active while lcm not off */
|
|
if (chrlmt_is_lcmoff)
|
|
cl_abcct_state = 0;
|
|
|
|
if (cl_bcct_klog_on == 1) {
|
|
ret = mtk_chr_get_soc(&bat_info_soc);
|
|
if (ret)
|
|
mtk_cooler_bcct_dprintk("mtk_chr_get_soc: %d err: %d\n",
|
|
bat_info_soc, ret);
|
|
|
|
ret = mtk_chr_get_ui_soc(&bat_info_uisoc);
|
|
|
|
if (ret)
|
|
mtk_cooler_bcct_dprintk("bat_info_uisoc: %d err: %d\n",
|
|
bat_info_uisoc, ret);
|
|
|
|
ret = mtk_chr_get_vbat(&bat_info_vbat);
|
|
|
|
if (ret)
|
|
mtk_cooler_bcct_dprintk("bat_info_vbat: %d err: %d\n",
|
|
bat_info_vbat, ret);
|
|
|
|
ret = mtk_chr_get_ibat(&bat_info_ibat);
|
|
|
|
if (ret)
|
|
mtk_cooler_bcct_dprintk("bat_info_ibat: %d err: %d\n",
|
|
bat_info_ibat, ret);
|
|
|
|
ret = mtk_chr_get_vbus(&bat_info_vbus);
|
|
|
|
if (ret)
|
|
mtk_cooler_bcct_dprintk("bat_info_vbus: %d err: %d\n",
|
|
bat_info_vbus, ret);
|
|
|
|
ret = mtk_chr_get_aicr(&bat_info_aicr);
|
|
|
|
if (ret)
|
|
mtk_cooler_bcct_dprintk("bat_info_aicr: %d err: %d\n",
|
|
bat_info_aicr, ret);
|
|
/*
|
|
* ret = mtk_chr_get_tchr(&bat_info_mintchr, &bat_info_maxtchr);
|
|
* if (ret)
|
|
* mtk_cooler_bcct_dprintk("mtk_chr_get_tchr: %d %d err: %d\n",
|
|
* bat_info_mintchr, bat_info_maxtchr, ret);
|
|
*/
|
|
}
|
|
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__,
|
|
cdev->type, cl_abcct_state);
|
|
return 0;
|
|
}
|
|
|
|
/* bind fan callbacks to fan device */
|
|
static struct thermal_cooling_device_ops mtk_cl_abcct_ops = {
|
|
.get_max_state = mtk_cl_abcct_get_max_state,
|
|
.get_cur_state = mtk_cl_abcct_get_cur_state,
|
|
.set_cur_state = mtk_cl_abcct_set_cur_state,
|
|
};
|
|
|
|
static int mtk_cl_abcct_set_cur_temp(
|
|
struct thermal_cooling_device *cdev, unsigned long temp)
|
|
{
|
|
long delta, pterm, dterm;
|
|
int limit;
|
|
static int i;
|
|
|
|
if (++i < abcct_times_of_ts_polling_interval)
|
|
return 0;
|
|
|
|
i = 0;
|
|
|
|
/* based on temp and state to do ATM */
|
|
abcct_prev_temp = abcct_curr_temp;
|
|
abcct_curr_temp = (long) temp;
|
|
|
|
if (cl_abcct_state == 0) {
|
|
abcct_iterm = 0;
|
|
abcct_cur_bat_chr_curr_limit = abcct_max_bat_chr_curr_limit;
|
|
abcct_cur_chr_input_curr_limit = -1;
|
|
chrlmt_set_limit(&abcct_chrlmt_handle, -1, -1);
|
|
return 0;
|
|
}
|
|
|
|
pterm = abcct_target_temp - abcct_curr_temp;
|
|
|
|
abcct_iterm += pterm;
|
|
if (((abcct_curr_temp < abcct_target_temp) && (abcct_iterm < 0)) ||
|
|
((abcct_curr_temp > abcct_target_temp)
|
|
&& (abcct_iterm > 0)))
|
|
abcct_iterm = 0;
|
|
|
|
if (((abcct_curr_temp < abcct_target_temp)
|
|
&& (abcct_curr_temp < abcct_prev_temp))
|
|
|| ((abcct_curr_temp > abcct_target_temp)
|
|
&& (abcct_curr_temp > abcct_prev_temp)))
|
|
dterm = abcct_prev_temp - abcct_curr_temp;
|
|
else
|
|
dterm = 0;
|
|
|
|
delta = pterm/abcct_kp + abcct_iterm/abcct_ki + dterm/abcct_kd;
|
|
|
|
/* Align limit to 50mA to avoid redundant calls to chrlmt. */
|
|
if (delta > 0 && delta < 50)
|
|
delta = 50;
|
|
else if (delta > -50 && delta < 0)
|
|
delta = -50;
|
|
|
|
if (abcct_cur_chr_input_curr_limit == -1) {
|
|
limit = abcct_cur_bat_chr_curr_limit + (int) delta;
|
|
/* Align limit to 50mA to avoid redundant calls to chrlmt. */
|
|
limit = (limit / 50) * 50;
|
|
limit = MIN(abcct_max_bat_chr_curr_limit, limit);
|
|
limit = MAX(abcct_min_bat_chr_curr_limit, limit);
|
|
|
|
abcct_cur_bat_chr_curr_limit = limit;
|
|
|
|
if ((abcct_input_current_limit_on)
|
|
&& (abcct_cur_bat_chr_curr_limit == 0)) {
|
|
abcct_max_chr_input_curr_limit =
|
|
abcct_HW_thermal_solution / 5; /* mA = mW/5V */
|
|
|
|
abcct_cur_chr_input_curr_limit =
|
|
abcct_max_chr_input_curr_limit;
|
|
}
|
|
} else {
|
|
limit = abcct_cur_chr_input_curr_limit + (int) delta;
|
|
/* Align limit to 50mA to avoid redundant calls to chrlmt. */
|
|
limit = (limit / 50) * 50;
|
|
limit = MIN(abcct_max_chr_input_curr_limit, limit);
|
|
limit = MAX(abcct_min_chr_input_curr_limit, limit);
|
|
abcct_cur_chr_input_curr_limit = limit;
|
|
|
|
if (abcct_cur_chr_input_curr_limit
|
|
== abcct_max_chr_input_curr_limit)
|
|
abcct_cur_chr_input_curr_limit = -1;
|
|
}
|
|
|
|
mtk_cooler_bcct_dprintk("%s %ld %ld %ld %ld %ld %d %d\n"
|
|
, __func__, abcct_curr_temp, pterm,
|
|
abcct_iterm, dterm, delta,
|
|
abcct_cur_chr_input_curr_limit,
|
|
abcct_cur_bat_chr_curr_limit);
|
|
|
|
chrlmt_set_limit(&abcct_chrlmt_handle, abcct_cur_chr_input_curr_limit,
|
|
abcct_cur_bat_chr_curr_limit);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct thermal_cooling_device_ops_extra mtk_cl_abcct_ops_ext = {
|
|
.set_cur_temp = mtk_cl_abcct_set_cur_temp
|
|
};
|
|
|
|
static struct thermal_cooling_device *cl_abcct_lcmoff_dev;
|
|
static unsigned long cl_abcct_lcmoff_state;
|
|
static struct chrlmt_handle abcct_lcmoff_chrlmt_handle;
|
|
static long abcct_lcmoff_prev_temp;
|
|
static long abcct_lcmoff_curr_temp;
|
|
static long abcct_lcmoff_target_temp = 48000;
|
|
static long abcct_lcmoff_kp = 1000;
|
|
static long abcct_lcmoff_ki = 3000;
|
|
static long abcct_lcmoff_kd = 10000;
|
|
static int abcct_lcmoff_max_bat_chr_curr_limit = 3000;
|
|
static int abcct_lcmoff_min_bat_chr_curr_limit = 200;
|
|
static int abcct_lcmoff_cur_bat_chr_curr_limit;
|
|
static long abcct_lcmoff_iterm;
|
|
|
|
static int mtk_cl_abcct_lcmoff_get_max_state(
|
|
struct thermal_cooling_device *cdev, unsigned long *state)
|
|
{
|
|
*state = 1;
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, *state);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_cl_abcct_lcmoff_get_cur_state(
|
|
struct thermal_cooling_device *cdev, unsigned long *state)
|
|
{
|
|
*state = cl_abcct_lcmoff_state;
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__, cdev->type, *state);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_cl_abcct_lcmoff_set_cur_state(
|
|
struct thermal_cooling_device *cdev, unsigned long state)
|
|
{
|
|
cl_abcct_lcmoff_state = state;
|
|
|
|
/*Only active while lcm off */
|
|
if (!chrlmt_is_lcmoff)
|
|
cl_abcct_lcmoff_state = 0;
|
|
mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__,
|
|
cdev->type, cl_abcct_lcmoff_state);
|
|
return 0;
|
|
}
|
|
|
|
/* bind fan callbacks to fan device */
|
|
static struct thermal_cooling_device_ops mtk_cl_abcct_lcmoff_ops = {
|
|
.get_max_state = mtk_cl_abcct_lcmoff_get_max_state,
|
|
.get_cur_state = mtk_cl_abcct_lcmoff_get_cur_state,
|
|
.set_cur_state = mtk_cl_abcct_lcmoff_set_cur_state,
|
|
};
|
|
|
|
static int mtk_cl_abcct_lcmoff_set_cur_temp(
|
|
struct thermal_cooling_device *cdev, unsigned long temp)
|
|
{
|
|
long delta, pterm, dterm;
|
|
int limit;
|
|
|
|
/* based on temp and state to do ATM */
|
|
abcct_lcmoff_prev_temp = abcct_lcmoff_curr_temp;
|
|
abcct_lcmoff_curr_temp = (long) temp;
|
|
|
|
if (cl_abcct_lcmoff_state == 0) {
|
|
abcct_lcmoff_iterm = 0;
|
|
abcct_lcmoff_cur_bat_chr_curr_limit =
|
|
abcct_lcmoff_max_bat_chr_curr_limit;
|
|
chrlmt_set_limit(&abcct_lcmoff_chrlmt_handle, -1, -1);
|
|
return 0;
|
|
}
|
|
|
|
pterm = abcct_lcmoff_target_temp - abcct_lcmoff_curr_temp;
|
|
|
|
abcct_lcmoff_iterm += pterm;
|
|
if (((abcct_lcmoff_curr_temp < abcct_target_temp)
|
|
&& (abcct_lcmoff_iterm < 0))
|
|
|| ((abcct_lcmoff_curr_temp > abcct_target_temp)
|
|
&& (abcct_lcmoff_iterm > 0)))
|
|
abcct_lcmoff_iterm = 0;
|
|
|
|
if (((abcct_lcmoff_curr_temp < abcct_target_temp)
|
|
&& (abcct_lcmoff_curr_temp < abcct_lcmoff_prev_temp))
|
|
|| ((abcct_lcmoff_curr_temp > abcct_target_temp)
|
|
&& (abcct_lcmoff_curr_temp > abcct_lcmoff_prev_temp)))
|
|
dterm = abcct_lcmoff_prev_temp - abcct_lcmoff_curr_temp;
|
|
else
|
|
dterm = 0;
|
|
|
|
delta = pterm/abcct_lcmoff_kp + abcct_lcmoff_iterm/abcct_lcmoff_ki
|
|
+ dterm/abcct_lcmoff_kd;
|
|
|
|
/* Align limit to 50mA to avoid redundant calls to chrlmt. */
|
|
if (delta > 0 && delta < 50)
|
|
delta = 50;
|
|
else if (delta > -50 && delta < 0)
|
|
delta = -50;
|
|
|
|
limit = abcct_lcmoff_cur_bat_chr_curr_limit + (int) delta;
|
|
/* Align limit to 50mA to avoid redundant calls to chrlmt. */
|
|
limit = (limit / 50) * 50;
|
|
limit = MIN(abcct_lcmoff_max_bat_chr_curr_limit, limit);
|
|
limit = MAX(abcct_lcmoff_min_bat_chr_curr_limit, limit);
|
|
abcct_lcmoff_cur_bat_chr_curr_limit = limit;
|
|
|
|
mtk_cooler_bcct_dprintk("%s %ld %ld %ld %ld %ld %d\n"
|
|
, __func__, abcct_lcmoff_curr_temp, pterm,
|
|
abcct_lcmoff_iterm, dterm, delta, limit);
|
|
|
|
chrlmt_set_limit(&abcct_lcmoff_chrlmt_handle, -1, limit);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct thermal_cooling_device_ops_extra mtk_cl_abcct_lcmoff_ops_ext = {
|
|
.set_cur_temp = mtk_cl_abcct_lcmoff_set_cur_temp
|
|
};
|
|
|
|
static int mtk_cooler_abcct_register_ltf(void)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
chrlmt_register(&abcct_chrlmt_handle);
|
|
|
|
if (!cl_abcct_dev)
|
|
cl_abcct_dev =
|
|
mtk_thermal_cooling_device_register_wrapper_extra(
|
|
"abcct", (void *)NULL,
|
|
&mtk_cl_abcct_ops,
|
|
&mtk_cl_abcct_ops_ext);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mtk_cooler_abcct_unregister_ltf(void)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
if (cl_abcct_dev) {
|
|
mtk_thermal_cooling_device_unregister(cl_abcct_dev);
|
|
cl_abcct_dev = NULL;
|
|
cl_abcct_state = 0;
|
|
}
|
|
|
|
chrlmt_unregister(&abcct_chrlmt_handle);
|
|
}
|
|
|
|
static int mtk_cooler_abcct_lcmoff_register_ltf(void)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
chrlmt_register(&abcct_lcmoff_chrlmt_handle);
|
|
|
|
if (!cl_abcct_lcmoff_dev)
|
|
cl_abcct_lcmoff_dev =
|
|
mtk_thermal_cooling_device_register_wrapper_extra(
|
|
"abcct_lcmoff", (void *)NULL,
|
|
&mtk_cl_abcct_lcmoff_ops,
|
|
&mtk_cl_abcct_lcmoff_ops_ext);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mtk_cooler_abcct_lcmoff_unregister_ltf(void)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
if (cl_abcct_lcmoff_dev) {
|
|
mtk_thermal_cooling_device_unregister(cl_abcct_lcmoff_dev);
|
|
cl_abcct_lcmoff_dev = NULL;
|
|
cl_abcct_lcmoff_state = 0;
|
|
}
|
|
|
|
chrlmt_unregister(&abcct_lcmoff_chrlmt_handle);
|
|
}
|
|
|
|
static ssize_t _cl_bcct_write(
|
|
struct file *filp, const char __user *buf, size_t len, loff_t *data)
|
|
{
|
|
/* int ret = 0; */
|
|
char tmp[128] = { 0 };
|
|
int klog_on, limit0, limit1, limit2;
|
|
|
|
len = (len < (128 - 1)) ? len : (128 - 1);
|
|
/* write data to the buffer */
|
|
if (copy_from_user(tmp, buf, len))
|
|
return -EFAULT;
|
|
|
|
/**
|
|
* sscanf format <klog_on> <mtk-cl-bcct00 limit> <mtk-cl-bcct01 limit>
|
|
* <klog_on> can only be 0 or 1
|
|
* <mtk-cl-bcct00 limit> can only be positive integer
|
|
* or -1 to denote no limit
|
|
*/
|
|
|
|
if (data == NULL) {
|
|
mtk_cooler_bcct_dprintk("%s null data\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
/* WARNING: Modify here if
|
|
* MTK_THERMAL_MONITOR_COOLER_MAX_EXTRA_CONDITIONS
|
|
* is changed to other than 3
|
|
*/
|
|
#if (MAX_NUM_INSTANCE_MTK_COOLER_BCCT == 3)
|
|
MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state[0]);
|
|
MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state[1]);
|
|
MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state[2]);
|
|
|
|
if (sscanf(
|
|
tmp, "%d %d %d %d", &klog_on, &limit0, &limit1, &limit2) >= 1) {
|
|
if (klog_on == 0 || klog_on == 1)
|
|
cl_bcct_klog_on = klog_on;
|
|
|
|
if (limit0 >= -1)
|
|
MTK_CL_BCCT_SET_LIMIT(limit0, cl_bcct_state[0]);
|
|
if (limit1 >= -1)
|
|
MTK_CL_BCCT_SET_LIMIT(limit1, cl_bcct_state[1]);
|
|
if (limit2 >= -1)
|
|
MTK_CL_BCCT_SET_LIMIT(limit2, cl_bcct_state[2]);
|
|
|
|
return len;
|
|
}
|
|
#else
|
|
#error \
|
|
"Change correspondent part when changing MAX_NUM_INSTANCE_MTK_COOLER_BCCT!"
|
|
#endif
|
|
mtk_cooler_bcct_dprintk("%s bad argument\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int _cl_bcct_read(struct seq_file *m, void *v)
|
|
{
|
|
/**
|
|
* The format to print out:
|
|
* kernel_log <0 or 1>
|
|
* <mtk-cl-bcct<ID>> <bcc limit>
|
|
* ..
|
|
*/
|
|
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
{
|
|
int i = 0;
|
|
|
|
seq_printf(m, "%d\n", cl_bcct_cur_limit);
|
|
seq_printf(m, "klog %d\n", cl_bcct_klog_on);
|
|
seq_printf(m, "curr_limit %d\n", cl_bcct_cur_limit);
|
|
|
|
for (; i < MAX_NUM_INSTANCE_MTK_COOLER_BCCT; i++) {
|
|
int limit;
|
|
unsigned int curr_state;
|
|
|
|
MTK_CL_BCCT_GET_LIMIT(limit, cl_bcct_state[i]);
|
|
MTK_CL_BCCT_GET_CURR_STATE(curr_state,
|
|
cl_bcct_state[i]);
|
|
|
|
seq_printf(m, "mtk-cl-bcct%02d %d mA, state %d\n",
|
|
i, limit, curr_state);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cl_bcct_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, _cl_bcct_read, PDE_DATA(inode));
|
|
}
|
|
|
|
static const struct file_operations _cl_bcct_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = _cl_bcct_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.write = _cl_bcct_write,
|
|
.release = single_release,
|
|
};
|
|
|
|
static ssize_t _cl_abcct_write(
|
|
struct file *filp, const char __user *buf, size_t len, loff_t *data)
|
|
{
|
|
/* int ret = 0; */
|
|
char tmp[128] = { 0 };
|
|
long _abcct_target_temp, _abcct_kp, _abcct_ki, _abcct_kd;
|
|
int _max_cur, _min_cur, _input_current_limit_on, _HW_thermal_sol,
|
|
_min_input, _times_of_ts_polling_inteval;
|
|
|
|
int scan_count = 0;
|
|
|
|
len = (len < (128 - 1)) ? len : (128 - 1);
|
|
/* write data to the buffer */
|
|
if (copy_from_user(tmp, buf, len))
|
|
return -EFAULT;
|
|
|
|
if (data == NULL) {
|
|
mtk_cooler_bcct_dprintk("%s null data\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
scan_count = sscanf(tmp, "%ld %ld %ld %ld %d %d %d %d %d %d"
|
|
, &_abcct_target_temp, &_abcct_kp, &_abcct_ki, &_abcct_kd
|
|
, &_max_cur, &_min_cur, &_input_current_limit_on
|
|
, &_HW_thermal_sol, &_min_input, &_times_of_ts_polling_inteval);
|
|
|
|
if (scan_count >= 6) {
|
|
abcct_target_temp = _abcct_target_temp;
|
|
abcct_kp = _abcct_kp;
|
|
abcct_ki = _abcct_ki;
|
|
abcct_kd = _abcct_kd;
|
|
abcct_max_bat_chr_curr_limit = _max_cur;
|
|
abcct_min_bat_chr_curr_limit = _min_cur;
|
|
|
|
if (scan_count > 6) {
|
|
abcct_input_current_limit_on = _input_current_limit_on;
|
|
abcct_HW_thermal_solution = _HW_thermal_sol;
|
|
abcct_min_chr_input_curr_limit = _min_input;
|
|
abcct_times_of_ts_polling_interval =
|
|
_times_of_ts_polling_inteval;
|
|
}
|
|
|
|
abcct_cur_chr_input_curr_limit = -1;
|
|
abcct_cur_bat_chr_curr_limit = abcct_max_bat_chr_curr_limit;
|
|
|
|
abcct_iterm = 0;
|
|
|
|
return len;
|
|
}
|
|
|
|
mtk_cooler_bcct_dprintk("%s bad argument\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int _cl_abcct_read(struct seq_file *m, void *v)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
seq_printf(m, "%d %ld %ld %ld %ld %d %d\n",
|
|
abcct_cur_bat_chr_curr_limit,
|
|
abcct_target_temp,
|
|
abcct_kp, abcct_ki, abcct_kd,
|
|
abcct_max_bat_chr_curr_limit,
|
|
abcct_min_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_cur_bat_chr_curr_limit %d\n",
|
|
abcct_cur_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_cur_chr_input_curr_limit %d\n",
|
|
abcct_cur_chr_input_curr_limit);
|
|
|
|
seq_printf(m, "abcct_target_temp %ld\n", abcct_target_temp);
|
|
seq_printf(m, "abcct_kp %ld\n", abcct_kp);
|
|
seq_printf(m, "abcct_ki %ld\n", abcct_ki);
|
|
seq_printf(m, "abcct_kd %ld\n", abcct_kd);
|
|
seq_printf(m, "abcct_max_bat_chr_curr_limit %d\n",
|
|
abcct_max_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_min_bat_chr_curr_limit %d\n",
|
|
abcct_min_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_input_current_limit_on %d\n",
|
|
abcct_input_current_limit_on);
|
|
|
|
seq_printf(m, "abcct_HW_thermal_solution %d\n",
|
|
abcct_HW_thermal_solution);
|
|
|
|
seq_printf(m, "abcct_min_chr_input_curr_limit %d\n",
|
|
abcct_min_chr_input_curr_limit);
|
|
|
|
seq_printf(m, "abcct_times_of_ts_polling_interval %d\n",
|
|
abcct_times_of_ts_polling_interval);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cl_abcct_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, _cl_abcct_read, PDE_DATA(inode));
|
|
}
|
|
|
|
static const struct file_operations _cl_abcct_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = _cl_abcct_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.write = _cl_abcct_write,
|
|
.release = single_release,
|
|
};
|
|
|
|
static ssize_t _cl_abcct_lcmoff_write(
|
|
struct file *filp, const char __user *buf, size_t len, loff_t *data)
|
|
{
|
|
/* int ret = 0; */
|
|
char tmp[128] = { 0 };
|
|
int _lcmoff_policy_enable;
|
|
long _abcct_lcmoff_target_temp, _abcct_lcmoff_kp,
|
|
_abcct_lcmoff_ki, _abcct_lcmoff_kd;
|
|
|
|
int _max_cur, _min_cur;
|
|
|
|
len = (len < (128 - 1)) ? len : (128 - 1);
|
|
/* write data to the buffer */
|
|
if (copy_from_user(tmp, buf, len))
|
|
return -EFAULT;
|
|
|
|
if (data == NULL) {
|
|
mtk_cooler_bcct_dprintk("%s null data\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sscanf(tmp, "%d %ld %ld %ld %ld %d %d"
|
|
, &_lcmoff_policy_enable
|
|
, &_abcct_lcmoff_target_temp, &_abcct_lcmoff_kp
|
|
, &_abcct_lcmoff_ki, &_abcct_lcmoff_kd
|
|
, &_max_cur, &_min_cur) >= 7) {
|
|
|
|
chrlmt_lcmoff_policy_enable = _lcmoff_policy_enable;
|
|
abcct_lcmoff_target_temp = _abcct_lcmoff_target_temp;
|
|
abcct_lcmoff_kp = _abcct_lcmoff_kp;
|
|
abcct_lcmoff_ki = _abcct_lcmoff_ki;
|
|
abcct_lcmoff_kd = _abcct_lcmoff_kd;
|
|
abcct_lcmoff_max_bat_chr_curr_limit = _max_cur;
|
|
abcct_lcmoff_min_bat_chr_curr_limit = _min_cur;
|
|
abcct_lcmoff_cur_bat_chr_curr_limit =
|
|
abcct_lcmoff_max_bat_chr_curr_limit;
|
|
|
|
abcct_lcmoff_iterm = 0;
|
|
|
|
return len;
|
|
}
|
|
|
|
mtk_cooler_bcct_dprintk("%s bad argument\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int _cl_abcct_lcmoff_read(struct seq_file *m, void *v)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
seq_printf(m, "chrlmt_lcmoff_policy_enable %d\n",
|
|
chrlmt_lcmoff_policy_enable);
|
|
|
|
seq_printf(m, "%d\n", abcct_lcmoff_cur_bat_chr_curr_limit);
|
|
seq_printf(m, "abcct_lcmoff_cur_bat_chr_curr_limit %d\n",
|
|
abcct_lcmoff_cur_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_lcmoff_target_temp %ld\n",
|
|
abcct_lcmoff_target_temp);
|
|
|
|
seq_printf(m, "abcct_lcmoff_kp %ld\n", abcct_lcmoff_kp);
|
|
seq_printf(m, "abcct_lcmoff_ki %ld\n", abcct_lcmoff_ki);
|
|
seq_printf(m, "abcct_lcmoff_kd %ld\n", abcct_lcmoff_kd);
|
|
seq_printf(m, "abcct_lcmoff_max_bat_chr_curr_limit %d\n",
|
|
abcct_lcmoff_max_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_lcmoff_min_bat_chr_curr_limit %d\n",
|
|
abcct_lcmoff_min_bat_chr_curr_limit);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cl_abcct_lcmoff_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, _cl_abcct_lcmoff_read, PDE_DATA(inode));
|
|
}
|
|
|
|
static const struct file_operations _cl_abcct_lcmoff_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = _cl_abcct_lcmoff_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.write = _cl_abcct_lcmoff_write,
|
|
.release = single_release,
|
|
};
|
|
|
|
static void bcct_lcmoff_switch(int onoff)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s: onoff = %d\n", __func__, onoff);
|
|
|
|
/* onoff = 0: LCM OFF */
|
|
/* others: LCM ON */
|
|
if (onoff) {
|
|
/* deactivate lcmoff policy */
|
|
chrlmt_is_lcmoff = 0;
|
|
} else {
|
|
/* activate lcmoff policy */
|
|
chrlmt_is_lcmoff = 1;
|
|
}
|
|
}
|
|
|
|
static int bcct_lcmoff_fb_notifier_callback(
|
|
struct notifier_block *self, unsigned long event, void *data)
|
|
{
|
|
struct fb_event *evdata = data;
|
|
int blank;
|
|
|
|
/* skip if it's not a blank event */
|
|
if ((event != FB_EVENT_BLANK) || (data == NULL))
|
|
return 0;
|
|
|
|
/* skip if policy is not enable */
|
|
if (!chrlmt_lcmoff_policy_enable)
|
|
return 0;
|
|
|
|
blank = *(int *)evdata->data;
|
|
mtk_cooler_bcct_dprintk("%s: blank = %d, event = %lu\n", __func__,
|
|
blank, event);
|
|
|
|
switch (blank) {
|
|
/* LCM ON */
|
|
case FB_BLANK_UNBLANK:
|
|
bcct_lcmoff_switch(1);
|
|
break;
|
|
/* LCM OFF */
|
|
case FB_BLANK_POWERDOWN:
|
|
bcct_lcmoff_switch(0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct notifier_block bcct_lcmoff_fb_notifier = {
|
|
.notifier_call = bcct_lcmoff_fb_notifier_callback,
|
|
};
|
|
|
|
static int _cl_chrlmt_read(struct seq_file *m, void *v)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
seq_printf(m, "%d,%d\n", chrlmt_chr_input_curr_limit,
|
|
chrlmt_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "chrlmt_chr_input_curr_limit %d\n",
|
|
chrlmt_chr_input_curr_limit);
|
|
|
|
seq_printf(m, "chrlmt_bat_chr_curr_limit %d\n",
|
|
chrlmt_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "abcct_cur_bat_chr_curr_limit %d\n",
|
|
abcct_cur_bat_chr_curr_limit);
|
|
|
|
seq_printf(m, "cl_bcct_cur_limit %d\n", cl_bcct_cur_limit);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cl_chrlmt_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, _cl_chrlmt_read, PDE_DATA(inode));
|
|
}
|
|
|
|
static const struct file_operations _cl_chrlmt_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = _cl_chrlmt_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static int _cl_battery_status_read(struct seq_file *m, void *v)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
seq_printf(m, "%d,%d,%d,%d,%d,%d,%d,%d\n",
|
|
bat_info_soc, bat_info_uisoc,
|
|
bat_info_vbat, bat_info_ibat,
|
|
bat_info_mintchr, bat_info_maxtchr,
|
|
bat_info_vbus, bat_info_aicr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _cl_battery_status_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, _cl_battery_status_read, PDE_DATA(inode));
|
|
}
|
|
|
|
static const struct file_operations _cl_battery_status_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = _cl_battery_status_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static int __init mtk_cooler_bcct_init(void)
|
|
{
|
|
int err = 0;
|
|
int i;
|
|
|
|
for (i = MAX_NUM_INSTANCE_MTK_COOLER_BCCT; i-- > 0;) {
|
|
cl_bcct_dev[i] = NULL;
|
|
cl_bcct_state[i] = 0;
|
|
}
|
|
|
|
/* cl_bcct_dev = NULL; */
|
|
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
err = mtk_cooler_bcct_register_ltf();
|
|
if (err)
|
|
goto err_unreg;
|
|
|
|
err = mtk_cooler_abcct_register_ltf();
|
|
if (err)
|
|
goto err_unreg;
|
|
|
|
err = mtk_cooler_abcct_lcmoff_register_ltf();
|
|
if (err)
|
|
goto err_unreg;
|
|
|
|
if (fb_register_client(&bcct_lcmoff_fb_notifier)) {
|
|
mtk_cooler_bcct_dprintk_always(
|
|
"%s: register FB client failed!\n",
|
|
__func__);
|
|
err = -EINVAL;
|
|
goto err_unreg;
|
|
}
|
|
|
|
/* create a proc file */
|
|
{
|
|
struct proc_dir_entry *entry = NULL;
|
|
struct proc_dir_entry *dir_entry = NULL;
|
|
|
|
dir_entry = mtk_thermal_get_proc_drv_therm_dir_entry();
|
|
if (!dir_entry) {
|
|
mtk_cooler_bcct_dprintk(
|
|
"[%s]: mkdir /proc/driver/thermal failed\n",
|
|
__func__);
|
|
}
|
|
|
|
entry = proc_create("clbcct", 0664, dir_entry, &_cl_bcct_fops);
|
|
|
|
if (!entry)
|
|
mtk_cooler_bcct_dprintk_always(
|
|
"%s clbcct creation failed\n",
|
|
__func__);
|
|
else
|
|
proc_set_user(entry, uid, gid);
|
|
|
|
entry = proc_create("clabcct", 0664, dir_entry,
|
|
&_cl_abcct_fops);
|
|
|
|
if (!entry)
|
|
mtk_cooler_bcct_dprintk_always(
|
|
"%s clabcct creation failed\n",
|
|
__func__);
|
|
else
|
|
proc_set_user(entry, uid, gid);
|
|
|
|
entry = proc_create("clabcct_lcmoff", 0664,
|
|
dir_entry, &_cl_abcct_lcmoff_fops);
|
|
|
|
if (!entry)
|
|
mtk_cooler_bcct_dprintk_always(
|
|
"%s clabcct_lcmoff creation failed\n",
|
|
__func__);
|
|
else
|
|
proc_set_user(entry, uid, gid);
|
|
|
|
entry = proc_create("bcctlmt", 0444, NULL, &_cl_chrlmt_fops);
|
|
|
|
entry = proc_create("battery_status", 0444, NULL,
|
|
&_cl_battery_status_fops);
|
|
}
|
|
|
|
bcct_chrlmt_queue = alloc_workqueue("bcct_chrlmt_work",
|
|
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
|
|
INIT_WORK(&bcct_chrlmt_work, chrlmt_set_limit_handler);
|
|
|
|
return 0;
|
|
|
|
err_unreg:
|
|
mtk_cooler_bcct_unregister_ltf();
|
|
return err;
|
|
}
|
|
|
|
static void __exit mtk_cooler_bcct_exit(void)
|
|
{
|
|
mtk_cooler_bcct_dprintk("%s\n", __func__);
|
|
|
|
if (bcct_chrlmt_queue) {
|
|
cancel_work_sync(&bcct_chrlmt_work);
|
|
flush_workqueue(bcct_chrlmt_queue);
|
|
destroy_workqueue(bcct_chrlmt_queue);
|
|
bcct_chrlmt_queue = NULL;
|
|
}
|
|
|
|
/* remove the proc file */
|
|
remove_proc_entry("driver/thermal/clbcct", NULL);
|
|
remove_proc_entry("driver/thermal/clabcct", NULL);
|
|
remove_proc_entry("driver/thermal/clabcct_lcmoff", NULL);
|
|
|
|
mtk_cooler_bcct_unregister_ltf();
|
|
mtk_cooler_abcct_unregister_ltf();
|
|
mtk_cooler_abcct_lcmoff_unregister_ltf();
|
|
|
|
fb_unregister_client(&bcct_lcmoff_fb_notifier);
|
|
}
|
|
module_init(mtk_cooler_bcct_init);
|
|
module_exit(mtk_cooler_bcct_exit);
|