mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
drivers: thermal: Add a snapshot of bcl soc driver
Add a snapshot of bcl soc driver from msm-5.10 of commit
4911990d5e6d ("drivers: thermal: bcl_soc: Remove QTI_THERMAL
dependency").
Updates:
- Change GPL v2 to GPL
Change-Id: I39f087d54a2be1e12756481ca05279a28b781bd5
Signed-off-by: Manaf Meethalavalappu Pallikunhi <quic_manafm@quicinc.com>
Signed-off-by: Rashid Zafar <quic_rzafar@quicinc.com>
This commit is contained in:
parent
91808785bc
commit
240423ee6b
|
|
@ -62,3 +62,14 @@ config QTI_BCL_PMIC5
|
|||
voltage sensors with the thermal core framework and can take
|
||||
threshold input and notify the thermal core when the threshold is
|
||||
reached.
|
||||
|
||||
config QTI_BCL_SOC_DRIVER
|
||||
tristate "QTI Battery state of charge sensor driver"
|
||||
depends on THERMAL && POWER_SUPPLY
|
||||
help
|
||||
This driver registers battery state of charge as a sensor with
|
||||
thermal framework. This sensor can monitor for state of charge
|
||||
thresholds and notify the thermal framework when the thresholds
|
||||
are reached and cleared. This will help to monitor and apply any
|
||||
mitigation when state of charge goes below a certain threshold.
|
||||
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
|
|||
obj-$(CONFIG_QCOM_LMH) += lmh.o
|
||||
obj-$(CONFIG_QTI_CPU_PAUSE_COOLING_DEVICE) += thermal_pause.o
|
||||
obj-$(CONFIG_QTI_BCL_PMIC5) += bcl_pmic5.o
|
||||
obj-$(CONFIG_QTI_BCL_SOC_DRIVER) += bcl_soc.o
|
||||
|
|
|
|||
188
drivers/thermal/qcom/bcl_soc.c
Normal file
188
drivers/thermal/qcom/bcl_soc.c
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#define BCL_DRIVER_NAME "bcl_soc_peripheral"
|
||||
|
||||
struct bcl_device {
|
||||
struct device *dev;
|
||||
struct notifier_block psy_nb;
|
||||
struct work_struct soc_eval_work;
|
||||
long trip_temp;
|
||||
int trip_val;
|
||||
struct mutex state_trans_lock;
|
||||
bool irq_enabled;
|
||||
struct thermal_zone_device *tz_dev;
|
||||
struct thermal_zone_of_device_ops ops;
|
||||
};
|
||||
|
||||
static struct bcl_device *bcl_perph;
|
||||
|
||||
static int bcl_set_soc(void *data, int low, int high)
|
||||
{
|
||||
if (high == bcl_perph->trip_temp)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&bcl_perph->state_trans_lock);
|
||||
pr_debug("socd threshold:%d\n", high);
|
||||
bcl_perph->trip_temp = high;
|
||||
if (high == INT_MAX) {
|
||||
bcl_perph->irq_enabled = false;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
bcl_perph->irq_enabled = true;
|
||||
schedule_work(&bcl_perph->soc_eval_work);
|
||||
|
||||
unlock_and_exit:
|
||||
mutex_unlock(&bcl_perph->state_trans_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcl_read_soc(void *data, int *val)
|
||||
{
|
||||
static struct power_supply *batt_psy;
|
||||
union power_supply_propval ret = {0,};
|
||||
int err = 0;
|
||||
|
||||
*val = 0;
|
||||
if (!batt_psy)
|
||||
batt_psy = power_supply_get_by_name("battery");
|
||||
if (batt_psy) {
|
||||
err = power_supply_get_property(batt_psy,
|
||||
POWER_SUPPLY_PROP_CAPACITY, &ret);
|
||||
if (err) {
|
||||
pr_err("battery percentage read error:%d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
*val = 100 - ret.intval;
|
||||
}
|
||||
pr_debug("soc:%d\n", *val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bcl_evaluate_soc(struct work_struct *work)
|
||||
{
|
||||
int battery_depletion;
|
||||
|
||||
if (!bcl_perph->tz_dev)
|
||||
return;
|
||||
|
||||
if (bcl_read_soc(NULL, &battery_depletion))
|
||||
return;
|
||||
|
||||
mutex_lock(&bcl_perph->state_trans_lock);
|
||||
if (!bcl_perph->irq_enabled)
|
||||
goto eval_exit;
|
||||
if (battery_depletion < bcl_perph->trip_temp)
|
||||
goto eval_exit;
|
||||
|
||||
bcl_perph->trip_val = battery_depletion;
|
||||
mutex_unlock(&bcl_perph->state_trans_lock);
|
||||
thermal_zone_device_update(bcl_perph->tz_dev,
|
||||
THERMAL_TRIP_VIOLATED);
|
||||
|
||||
return;
|
||||
eval_exit:
|
||||
mutex_unlock(&bcl_perph->state_trans_lock);
|
||||
}
|
||||
|
||||
static int battery_supply_callback(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct power_supply *psy = data;
|
||||
|
||||
if (strcmp(psy->desc->name, "battery"))
|
||||
return NOTIFY_OK;
|
||||
schedule_work(&bcl_perph->soc_eval_work);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int bcl_soc_remove(struct platform_device *pdev)
|
||||
{
|
||||
power_supply_unreg_notifier(&bcl_perph->psy_nb);
|
||||
flush_work(&bcl_perph->soc_eval_work);
|
||||
if (bcl_perph->tz_dev)
|
||||
thermal_zone_of_sensor_unregister(&pdev->dev,
|
||||
bcl_perph->tz_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcl_soc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bcl_perph = devm_kzalloc(&pdev->dev, sizeof(*bcl_perph), GFP_KERNEL);
|
||||
if (!bcl_perph)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&bcl_perph->state_trans_lock);
|
||||
bcl_perph->dev = &pdev->dev;
|
||||
bcl_perph->ops.get_temp = bcl_read_soc;
|
||||
bcl_perph->ops.set_trips = bcl_set_soc;
|
||||
INIT_WORK(&bcl_perph->soc_eval_work, bcl_evaluate_soc);
|
||||
bcl_perph->psy_nb.notifier_call = battery_supply_callback;
|
||||
ret = power_supply_reg_notifier(&bcl_perph->psy_nb);
|
||||
if (ret < 0) {
|
||||
pr_err("soc notifier registration error. defer. err:%d\n",
|
||||
ret);
|
||||
ret = -EPROBE_DEFER;
|
||||
goto bcl_soc_probe_exit;
|
||||
}
|
||||
bcl_perph->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
|
||||
0, bcl_perph, &bcl_perph->ops);
|
||||
if (IS_ERR(bcl_perph->tz_dev)) {
|
||||
pr_err("soc TZ register failed. err:%ld\n",
|
||||
PTR_ERR(bcl_perph->tz_dev));
|
||||
ret = PTR_ERR(bcl_perph->tz_dev);
|
||||
bcl_perph->tz_dev = NULL;
|
||||
goto bcl_soc_probe_exit;
|
||||
}
|
||||
thermal_zone_device_update(bcl_perph->tz_dev, THERMAL_DEVICE_UP);
|
||||
schedule_work(&bcl_perph->soc_eval_work);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, bcl_perph);
|
||||
|
||||
return 0;
|
||||
|
||||
bcl_soc_probe_exit:
|
||||
bcl_soc_remove(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcl_match[] = {
|
||||
{
|
||||
.compatible = "qcom,msm-bcl-soc",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver bcl_driver = {
|
||||
.probe = bcl_soc_probe,
|
||||
.remove = bcl_soc_remove,
|
||||
.driver = {
|
||||
.name = BCL_DRIVER_NAME,
|
||||
.of_match_table = bcl_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(bcl_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
Loading…
Reference in New Issue
Block a user