kernel_samsung_a34x-permissive/drivers/misc/mediatek/thermal/mtk_cooler_cam.c
2024-04-28 15:51:13 +02:00

649 lines
15 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/types.h>
#include <linux/kobject.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include "mt-plat/mtk_thermal_monitor.h"
#include "mach/mtk_thermal.h"
#include "mtk_cooler_setting.h"
#define MAX_NUM_INSTANCE_MTK_COOLER_CAM 3
static kuid_t uid = KUIDT_INIT(0);
static kgid_t gid = KGIDT_INIT(1000);
#define mtk_cooler_cam_dprintk_always(fmt, args...) \
pr_notice("[Thermal/TC/cam]" fmt, ##args)
#define mtk_cooler_cam_dprintk(fmt, args...) \
do { \
if (cl_cam_klog_on == 1) \
pr_notice("[Thermal/TC/cam]" fmt, ##args); \
} while (0)
#define MAX_LEN (256)
static int cl_cam_klog_on;
static struct thermal_cooling_device
*cl_cam_dev[MAX_NUM_INSTANCE_MTK_COOLER_CAM] = { 0 };
static unsigned long cl_cam_state[MAX_NUM_INSTANCE_MTK_COOLER_CAM] = { 0 };
static unsigned int _cl_cam;
static struct thermal_cooling_device *cl_cam_urgent_dev;
static unsigned long cl_cam_urgent_state;
static unsigned int _cl_cam_urgent;
static unsigned int _cl_cam_status;
static unsigned int _cl_cam_dual_off;
#if defined(THERMAL_APU_UNLIMIT)
static unsigned int _cl_apu_status;
#endif
/* < 20C: DualCam off, >= 20C: DualCam on */
static int dualcam_Tj_jump_threshold = 10000;
/*single cam = 1, dual cam = 0, default = 0*/
static int single_cam_flag;
/*10000=>10'C*/
static int dualcam_Tj_hysteresis = 10000;
static int ttj_offset;
/*
* The cooler status of exit camera.
* This is for camera app reference.
*/
enum {
CL_CAM_DEACTIVE = 0,
CL_CAM_ACTIVE = 1,
CL_CAM_URGENT = 2
};
#if defined(THERMAL_APU_UNLIMIT)
void cl_set_apu_status(int vv)
{
mtk_cooler_cam_dprintk("[Thermal/TC/cam]%s %d\n", __func__,
_cl_apu_status);
_cl_apu_status = vv;
}
EXPORT_SYMBOL(cl_set_apu_status);
unsigned int cl_get_apu_status(void)
{
//if(_cl_apu_status == 1)
// mtk_cooler_cam_dprintk_always("%s %d\n", __func__,
//_cl_apu_status);
return _cl_apu_status;
}
EXPORT_SYMBOL(cl_get_apu_status);
#endif
int cl_cam_dualcam_off(void)
{
int tj_headroom = 0;
int curr_tj = mtk_thermal_get_temp(MTK_THERMAL_SENSOR_CPU);
int curr_ttj = get_cpu_target_tj();
/* if any error */
if (curr_tj < 0 || curr_ttj < 0) {
mtk_cooler_cam_dprintk_always("%s error: %d %d\n", __func__,
curr_tj, curr_ttj);
return 1;
}
tj_headroom = curr_ttj + ttj_offset - curr_tj;
mtk_cooler_cam_dprintk(
"%s ttj = %d, tj %d, tj_headroom %d, single_cam_flag <%d>\n",
__func__, curr_ttj, curr_tj, tj_headroom, single_cam_flag);
if ((tj_headroom <= 0) || (tj_headroom < dualcam_Tj_jump_threshold)) {
single_cam_flag = 1;
mtk_cooler_cam_dprintk(
"%s tj_headroom:%d < Tj jump threshold:%d\n",
__func__, tj_headroom, dualcam_Tj_jump_threshold);
return 1; /*single cam*/
}
if ((single_cam_flag == 1)
&& (curr_tj < (curr_ttj - dualcam_Tj_jump_threshold
- dualcam_Tj_hysteresis))) {
single_cam_flag = 0;
mtk_cooler_cam_dprintk(
"%s Tj:%d TTj:%d Tj jump threshold:%d Tj_hys:%d, %d\n",
__func__, curr_tj, curr_ttj, dualcam_Tj_jump_threshold,
dualcam_Tj_hysteresis, (curr_ttj -
dualcam_Tj_jump_threshold - dualcam_Tj_hysteresis));
return 0;/*dual cam*/
}
mtk_cooler_cam_dprintk("Tj:%d TTj:%d Tj jump thd:%d Tj_hys:%d, %d\n",
curr_tj, curr_ttj, dualcam_Tj_jump_threshold,
dualcam_Tj_hysteresis, (curr_ttj + ttj_offset -
dualcam_Tj_jump_threshold - dualcam_Tj_hysteresis));
return 0;/*dual cam*/
}
static void cl_cam_status_update(void)
{
if (_cl_cam_urgent)
_cl_cam_status = CL_CAM_URGENT;
else if (_cl_cam)
_cl_cam_status = CL_CAM_ACTIVE;
else
_cl_cam_status = CL_CAM_DEACTIVE;
}
static ssize_t _cl_cam_write
(struct file *filp, const char __user *buf, size_t len, loff_t *data)
{
int ret = 0;
char tmp[MAX_LEN] = { 0 };
len = (len < (MAX_LEN - 1)) ? len : (MAX_LEN - 1);
/* write data to the buffer */
if (copy_from_user(tmp, buf, len))
return -EFAULT;
ret = kstrtouint(tmp, 10, &_cl_cam);
if (ret)
WARN_ON_ONCE(1);
mtk_cooler_cam_dprintk_always("%s %s = %d\n", __func__, tmp, _cl_cam);
return len;
}
static int _cl_cam_read(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", _cl_cam);
return 0;
}
static int _cl_cam_open(struct inode *inode, struct file *file)
{
return single_open(file, _cl_cam_read, PDE_DATA(inode));
}
static const struct file_operations _cl_cam_fops = {
.owner = THIS_MODULE,
.open = _cl_cam_open,
.read = seq_read,
.llseek = seq_lseek,
.write = _cl_cam_write,
.release = single_release,
};
static int mtk_cl_cam_get_max_state
(struct thermal_cooling_device *cdev, unsigned long *state)
{
*state = 1;
return 0;
}
static int mtk_cl_cam_get_cur_state
(struct thermal_cooling_device *cdev, unsigned long *state)
{
*state = *((unsigned long *)cdev->devdata);
return 0;
}
static int mtk_cl_cam_set_cur_state
(struct thermal_cooling_device *cdev, unsigned long state)
{
/* mtk_cooler_cam_dprintk("%s %s %d\n", __func__, cdev->type, state); */
*((unsigned long *)cdev->devdata) = state;
if (state == 1)
_cl_cam = 1;
else {
int i;
for (i = 0; i < MAX_NUM_INSTANCE_MTK_COOLER_CAM; i++) {
if (cl_cam_state[i])
break;
}
if (i == MAX_NUM_INSTANCE_MTK_COOLER_CAM)
_cl_cam = 0;
}
cl_cam_status_update();
return 0;
}
#if defined(THERMAL_APU_UNLIMIT)
static ssize_t _cl_apu_status_write
(struct file *filp, const char __user *buf, size_t len, loff_t *data)
{
int ret = 0;
char tmp[128] = { 0 };
len = (len < (128 - 1)) ? len : (128 - 1);
/* write data to the buffer */
if (copy_from_user(tmp, buf, len))
return -EFAULT;
ret = kstrtouint(tmp, 10, &_cl_apu_status);
if (ret)
WARN_ON_ONCE(1);
mtk_cooler_cam_dprintk_always(
"%s %s = %d\n", __func__, tmp, _cl_apu_status);
return len;
}
static int _cl_apu_status_read(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", _cl_apu_status);
if (_cl_apu_status)
mtk_cooler_cam_dprintk_always(
"%s: %d\n", __func__, _cl_apu_status);
return 0;
}
static int _cl_apu_status_open(struct inode *inode, struct file *file)
{
return single_open(file, _cl_apu_status_read, PDE_DATA(inode));
}
static const struct file_operations _cl_apu_status_fops = {
.owner = THIS_MODULE,
.open = _cl_apu_status_open,
.read = seq_read,
.llseek = seq_lseek,
.write = _cl_apu_status_write,
.release = single_release,
};
#endif
/* bind fan callbacks to fan device */
static struct thermal_cooling_device_ops mtk_cl_cam_ops = {
.get_max_state = mtk_cl_cam_get_max_state,
.get_cur_state = mtk_cl_cam_get_cur_state,
.set_cur_state = mtk_cl_cam_set_cur_state,
};
static ssize_t _cl_cam_status_write
(struct file *filp, const char __user *buf, size_t len, loff_t *data)
{
int ret = 0;
char tmp[128] = { 0 };
len = (len < (128 - 1)) ? len : (128 - 1);
/* write data to the buffer */
if (copy_from_user(tmp, buf, len))
return -EFAULT;
ret = kstrtouint(tmp, 10, &_cl_cam_status);
if (ret)
WARN_ON_ONCE(1);
mtk_cooler_cam_dprintk_always(
"%s %s = %d\n", __func__, tmp, _cl_cam_status);
return len;
}
static int _cl_cam_status_read(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", _cl_cam_status);
if (_cl_cam_status)
mtk_cooler_cam_dprintk_always(
"%s: %d\n", __func__, _cl_cam_status);
return 0;
}
static int _cl_cam_status_open(struct inode *inode, struct file *file)
{
return single_open(file, _cl_cam_status_read, PDE_DATA(inode));
}
static const struct file_operations _cl_cam_status_fops = {
.owner = THIS_MODULE,
.open = _cl_cam_status_open,
.read = seq_read,
.llseek = seq_lseek,
.write = _cl_cam_status_write,
.release = single_release,
};
static ssize_t _cl_cam_dual_off_write
(struct file *filp, const char __user *buf, size_t len, loff_t *data)
{
char tmp[128] = { 0 };
int klog_on, tj_jump_threshold, tj_hysteresis, tj_offset;
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_cam_dprintk_always("%s null data\n", __func__);
return -EINVAL;
}
if (sscanf(tmp, "%d %d %d %d", &klog_on, &tj_jump_threshold,
&tj_hysteresis, &tj_offset) >= 1) {
if (klog_on == 0 || klog_on == 1)
cl_cam_klog_on = klog_on;
dualcam_Tj_hysteresis = tj_hysteresis;
dualcam_Tj_jump_threshold = tj_jump_threshold;
ttj_offset = tj_offset;
mtk_cooler_cam_dprintk_always("%s : %d %d %d\n",
__func__, dualcam_Tj_hysteresis,
dualcam_Tj_jump_threshold, ttj_offset);
return len;
}
return len;
}
static int _cl_cam_dual_off_read(struct seq_file *m, void *v)
{
_cl_cam_dual_off = cl_cam_dualcam_off();
seq_printf(m, "%d\n", _cl_cam_dual_off);
return 0;
}
static int _cl_cam_dual_off_open(struct inode *inode, struct file *file)
{
return single_open(file, _cl_cam_dual_off_read, PDE_DATA(inode));
}
static const struct file_operations _cl_cam_dual_off_fops = {
.owner = THIS_MODULE,
.open = _cl_cam_dual_off_open,
.read = seq_read,
.llseek = seq_lseek,
.write = _cl_cam_dual_off_write,
.release = single_release,
};
static ssize_t _cl_cam_dual_off_setting_write
(struct file *filp, const char __user *buf, size_t len, loff_t *data)
{
char tmp[128] = { 0 };
int klog_on, tj_jump_threshold, tj_hysteresis, tj_offset;
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_cam_dprintk_always("%s null data\n", __func__);
return -EINVAL;
}
if (sscanf(tmp, "%d %d %d %d", &klog_on, &tj_jump_threshold,
&tj_hysteresis, &tj_offset) >= 1) {
if (klog_on == 0 || klog_on == 1)
cl_cam_klog_on = klog_on;
dualcam_Tj_hysteresis = tj_hysteresis;
dualcam_Tj_jump_threshold = tj_jump_threshold;
ttj_offset = tj_offset;
mtk_cooler_cam_dprintk_always("%s : %d %d %d\n",
__func__, dualcam_Tj_hysteresis,
dualcam_Tj_jump_threshold, ttj_offset);
return len;
}
return len;
}
static int _cl_cam_dual_off_setting_read(struct seq_file *m, void *v)
{
_cl_cam_dual_off = cl_cam_dualcam_off();
seq_printf(m, "%d\n", _cl_cam_dual_off);
seq_printf(m, "%d\n", dualcam_Tj_hysteresis);
seq_printf(m, "%d\n", dualcam_Tj_jump_threshold);
seq_printf(m, "%d\n", ttj_offset);
return 0;
}
static int _cl_cam_dual_off_setting_open(struct inode *inode, struct file *file)
{
return single_open(file, _cl_cam_dual_off_setting_read,
PDE_DATA(inode));
}
static const struct file_operations _cl_cam_dual_off_fops_setting = {
.owner = THIS_MODULE,
.open = _cl_cam_dual_off_setting_open,
.read = seq_read,
.llseek = seq_lseek,
.write = _cl_cam_dual_off_setting_write,
.release = single_release,
};
static int mtk_cl_cam_urgent_get_max_state
(struct thermal_cooling_device *cdev, unsigned long *state)
{
*state = 1;
return 0;
}
static int mtk_cl_cam_urgent_get_cur_state
(struct thermal_cooling_device *cdev, unsigned long *state)
{
*state = *((unsigned long *)cdev->devdata);
return 0;
}
static int mtk_cl_cam_urgent_set_cur_state
(struct thermal_cooling_device *cdev, unsigned long state)
{
/* mtk_cooler_cam_dprintk("%s %s %d\n", __func__, cdev->type, state); */
*((unsigned long *)cdev->devdata) = state;
if (state == 1)
_cl_cam_urgent = 1;
else
_cl_cam_urgent = 0;
cl_cam_status_update();
return 0;
}
/* bind fan callbacks to fan device */
static struct thermal_cooling_device_ops mtk_cl_cam_urgent_ops = {
.get_max_state = mtk_cl_cam_urgent_get_max_state,
.get_cur_state = mtk_cl_cam_urgent_get_cur_state,
.set_cur_state = mtk_cl_cam_urgent_set_cur_state,
};
static int mtk_cooler_cam_register_ltf(void)
{
int i;
/* mtk_cooler_cam_dprintk("%s\n", __func__); */
for (i = MAX_NUM_INSTANCE_MTK_COOLER_CAM; i-- > 0;) {
char temp[20] = { 0 };
sprintf(temp, "mtk-cl-cam%02d", i);
cl_cam_dev[i] = mtk_thermal_cooling_device_register(temp,
(void *)&cl_cam_state[i],
&mtk_cl_cam_ops);
}
return 0;
}
static void mtk_cooler_cam_unregister_ltf(void)
{
int i;
/* mtk_cooler_cam_dprintk("%s\n", __func__); */
for (i = MAX_NUM_INSTANCE_MTK_COOLER_CAM; i-- > 0;) {
if (cl_cam_dev[i]) {
mtk_thermal_cooling_device_unregister(cl_cam_dev[i]);
cl_cam_dev[i] = NULL;
cl_cam_state[i] = 0;
}
}
}
static int mtk_cooler_cam_urgent_register_ltf(void)
{
/* mtk_cooler_cam_dprintk("%s\n", __func__); */
cl_cam_urgent_dev = mtk_thermal_cooling_device_register(
"mtk-cl-cam-urgent",
(void *)&cl_cam_urgent_state,
&mtk_cl_cam_urgent_ops);
return 0;
}
static void mtk_cooler_cam_urgent_unregister_ltf(void)
{
/* mtk_cooler_cam_dprintk("%s\n", __func__); */
if (cl_cam_urgent_dev) {
mtk_thermal_cooling_device_unregister(cl_cam_urgent_dev);
cl_cam_urgent_dev = NULL;
cl_cam_urgent_state = 0;
}
}
static int __init mtk_cooler_cam_init(void)
{
int err = 0;
int i;
struct proc_dir_entry *entry = NULL;
struct proc_dir_entry *camsetting_dir = NULL;
for (i = MAX_NUM_INSTANCE_MTK_COOLER_CAM; i-- > 0;) {
cl_cam_dev[i] = NULL;
cl_cam_state[i] = 0;
}
/* mtk_cooler_cam_dprintk("%s\n", __func__); */
{
struct proc_dir_entry *entry;
#if 0
entry = create_proc_entry("driver/cl_cam", 0644, NULL);
if (entry != NULL) {
entry->read_proc = _cl_cam_read;
entry->write_proc = _cl_cam_write;
}
#endif
#if defined(THERMAL_APU_UNLIMIT)
entry = proc_create("driver/cl_apu_status", 0664,
NULL, &_cl_apu_status_fops);
if (entry)
proc_set_user(entry, uid, gid);
else
mtk_cooler_cam_dprintk(
"%s driver/cl_apu_status creation failed\n",
__func__);
#endif
entry = proc_create("driver/cl_cam", 0644, NULL, &_cl_cam_fops);
if (!entry)
mtk_cooler_cam_dprintk(
"%s driver/cl_cam creation failed\n", __func__);
entry = proc_create("driver/cl_cam_status", 0644,
NULL, &_cl_cam_status_fops);
if (!entry)
mtk_cooler_cam_dprintk(
"%s driver/cl_cam_status creation failed\n", __func__);
entry = proc_create("driver/cl_cam_dual_off", 0664, NULL,
&_cl_cam_dual_off_fops);
if (!entry)
mtk_cooler_cam_dprintk(
"%s driver/cl_cam_dual creation failed\n", __func__);
}
camsetting_dir = mtk_thermal_get_proc_drv_therm_dir_entry();
if (!camsetting_dir)
mtk_cooler_cam_dprintk_always(
"[%s]: mkdir /proc/driver/thermal failed\n", __func__);
else {
entry = proc_create("cl_cam_dual_off_setting",
0664,
camsetting_dir, &_cl_cam_dual_off_fops_setting);
if (entry)
proc_set_user(entry, uid, gid);
}
err = mtk_cooler_cam_register_ltf();
if (err)
goto err_unreg;
err = mtk_cooler_cam_urgent_register_ltf();
if (err)
goto err_unreg;
return 0;
err_unreg:
mtk_cooler_cam_unregister_ltf();
mtk_cooler_cam_urgent_unregister_ltf();
return err;
}
static void __exit mtk_cooler_cam_exit(void)
{
/* mtk_cooler_cam_dprintk("%s\n", __func__); */
mtk_cooler_cam_unregister_ltf();
mtk_cooler_cam_urgent_unregister_ltf();
}
module_init(mtk_cooler_cam_init);
module_exit(mtk_cooler_cam_exit);