#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
+#include <linux/pm_qos.h>
+#include <soc/rockchip/scpi.h>
/**
* If the temperature over a period of time High,
enum tshut_mode tshut_mode;
enum tsadc_mode mode;
enum tshut_polarity tshut_polarity;
+ int latency_bound;
const struct chip_tsadc_table *temp_table;
struct kobject *rk3368_thermal_kobj;
struct regulator *ref_regulator;
int regulator_uv;
+ int latency_req;
+ int latency_bound;
struct notifier_block tsadc_nb;
};
static DEFINE_MUTEX(thermal_reg_mutex);
+static DEFINE_MUTEX(thermal_lat_mutex);
+
static const struct tsadc_table code_table_3368[] = {
{0, MIN_TEMP},
{106, MIN_TEMP},
static const struct rk3368_tsadc_chip rk3368_tsadc_data = {
.tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
.tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
+ .latency_bound = 50000, /* default 50000 us */
.hw_shut_temp = 125000,
.mode = TSHUT_USER_MODE,
.chn_num = 2,
{
u32 shut_temp;
u32 rate;
+ u32 cycle;
+ int lat_bound;
int ret;
if (of_property_read_u32(np, "clock-frequency", &rate)) {
}
ret = clk_set_rate(thermal->clk, rate);
+ cycle = DIV_ROUND_UP(1000000000, rate) / 1000;
+
+ if (scpi_thermal_set_clk_cycle(cycle)) {
+ dev_err(dev, "scpi_thermal_set_clk_cycle error.\n");
+ return -EINVAL;
+ }
+
if (of_property_read_u32(np, "hw-shut-temp", &shut_temp)) {
dev_warn(dev,
"Missing tshut temp property, using default %ld\n",
thermal->hw_shut_temp = shut_temp;
}
+ if (of_property_read_u32(np, "latency-bound", &lat_bound)) {
+ dev_warn(dev,
+ "Missing latency-bound property, using default %d\n",
+ thermal->chip->latency_bound);
+ thermal->latency_bound = thermal->chip->latency_bound;
+ } else {
+ thermal->latency_bound = lat_bound;
+ }
+
if (thermal->hw_shut_temp > INT_MAX) {
dev_err(dev, "Invalid tshut temperature specified: %ld\n",
thermal->hw_shut_temp);
#define RAW_CODE_MIN (50)
#define RAW_CODE_MAX (225)
-static int rk3368_get_raw_code(void)
+static int rk3368_get_raw_code(struct rk3368_thermal_data *ctx)
{
static int old_data = 130;
int tsadc_data = 0;
- tsadc_data = get_raw_code_internal();
+ if (ctx->latency_req > ctx->latency_bound)
+ tsadc_data = scpi_thermal_get_temperature();
+ else
+ tsadc_data = get_raw_code_internal();
if ((tsadc_data < RAW_CODE_MIN) || (tsadc_data > RAW_CODE_MAX))
tsadc_data = old_data;
pdev = ctx->pdev;
mutex_lock(&thermal_reg_mutex);
- raw_code = rk3368_get_raw_code();
+ raw_code = rk3368_get_raw_code(ctx);
temp = rk3368_convert_code_2_temp(raw_code, ctx->regulator_uv);
*out_temp = predict_temp(temp / 1000) * 1000;
mutex_unlock(&thermal_reg_mutex);
return NOTIFY_OK;
}
+/*
+ * This function gets called when a part of the kernel has a new latency
+ * requirement. We record this requirement to instruct us to get temperature.
+ */
+static int tsadc_latency_notify(struct notifier_block *b,
+ unsigned long l, void *v)
+{
+ struct rk3368_thermal_data *ctx = rk3368_thermal_get_data();
+
+ if (!ctx)
+ return NOTIFY_OK;
+
+ mutex_lock(&thermal_lat_mutex);
+ ctx->latency_req = (int)l;
+ mutex_unlock(&thermal_lat_mutex);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block tsadc_latency_notifier = {
+ .notifier_call = tsadc_latency_notify,
+};
+
+static inline int tsadc_add_latency_notifier(struct notifier_block *n)
+{
+ return pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n);
+}
+
+static inline int tsadc_remove_latency_notifier(struct notifier_block *n)
+{
+ return pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY, n);
+}
+
static const struct of_device_id of_rk3368_thermal_match[] = {
{
.compatible = "rockchip,rk3368-tsadc-legacy",
int error;
int uv;
int ajust_code = 0;
+ int latency_req = 0;
match = of_match_node(of_rk3368_thermal_match, np);
if (!match)
ctx->regulator_uv = uv;
mutex_unlock(&thermal_reg_mutex);
+ error = tsadc_add_latency_notifier(&tsadc_latency_notifier);
+ if (error) {
+ dev_err(&pdev->dev, "latency notifier request failed\n");
+ goto err_unreg_notifier;
+ }
+
+ latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+
+ mutex_lock(&thermal_lat_mutex);
+ if (!ctx->latency_req)
+ ctx->latency_req = latency_req;
+ mutex_unlock(&thermal_lat_mutex);
+
rk3368_get_ajust_code(np, &ajust_code);
ctx->cpu_temp_adjust = (int)ajust_code;
for (j = 0; j < i; j++)
thermal_zone_of_sensor_unregister(&pdev->dev,
ctx->sensors[j].tzd);
- goto err_unreg_notifier;
+ goto err_remove_latancy_notifier;
}
}
error = -ENOMEM;
dev_err(&pdev->dev,
"failed to creat debug node : error= %d\n", error);
- goto err_unreg_notifier;
+ goto err_remove_latancy_notifier;
}
for (i = 0; i < ARRAY_SIZE(rk3368_thermal_attrs); i++) {
sysfs_remove_file(ctx->rk3368_thermal_kobj,
&rk3368_thermal_attrs[j].attr);
- goto err_unreg_notifier;
+ goto err_remove_latancy_notifier;
}
}
return 0;
+err_remove_latancy_notifier:
+ tsadc_remove_latency_notifier(&tsadc_latency_notifier);
err_unreg_notifier:
regulator_unregister_notifier(ctx->ref_regulator, &ctx->tsadc_nb);
struct rk3368_thermal_data *ctx = platform_get_drvdata(pdev);
int i;
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &rk3368_thermal_panic_block);
for (i = 0; i < ctx->chip->chn_num; i++) {
struct rk3368_thermal_sensor *sensor = &ctx->sensors[i];
thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);
}
+ tsadc_remove_latency_notifier(&tsadc_latency_notifier);
+ regulator_unregister_notifier(ctx->ref_regulator, &ctx->tsadc_nb);
clk_disable_unprepare(ctx->pclk);
clk_disable_unprepare(ctx->clk);