diff options
author | Ansuel Smith <ansuelsmth@gmail.com> | 2019-12-19 04:01:28 +0100 |
---|---|---|
committer | Petr Štetiar <ynezz@true.cz> | 2019-12-26 08:31:42 +0100 |
commit | 77f4d5c6bb8323ec67248176a5a2907475041a79 (patch) | |
tree | c164759fd55b66526c189dffc734ad129360c3b5 | |
parent | a666f817a27c01adb9d4e5d5a25367254b556a44 (diff) | |
download | upstream-77f4d5c6bb8323ec67248176a5a2907475041a79.tar.gz upstream-77f4d5c6bb8323ec67248176a5a2907475041a79.tar.bz2 upstream-77f4d5c6bb8323ec67248176a5a2907475041a79.zip |
ipq806x: rework ipq806x specific tsense temp driver
Tsense driver for ipq806x have various problem.
- Emit wrong error. On probing of this driver, nvmem driver can be
not ready and this cause a EDEFER error. Actually this is not an
error as the kernel will retry to probe the driver after the
nvmem driver is loaded.
- Use uninitialized value on trigger of critical temp
- Doesn't free allocated memory
Because of this, rework the driver and improve it by removing extra
load of data.
Change the logic of loading data. Use the backup calib data only
when the calib data is not present. As the calibration is only
needed to set the temp offset, we don't really need to read
both calib data and set the offset based only on the backup one.
Also change how the notifier function work. At times when we
output the trigger message, we already have read the temp so
remove the extra read and the wrong uninitialized data that
probably caused a kernel panic for null pointer exception.
(Think we never experience this bug because the router
never reached that temp ever... So just lucky)
Tested-by: Stefan Lippers-Hollmann <s.l-h@gmx.de> [nbg6817/ipq8065]
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
-rw-r--r-- | target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch b/target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch new file mode 100644 index 0000000000..7092552559 --- /dev/null +++ b/target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch @@ -0,0 +1,107 @@ +--- a/drivers/thermal/qcom/tsens-ipq8064.c ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -13,10 +13,12 @@ + */ + + #include <linux/platform_device.h> ++#include <linux/err.h> + #include <linux/delay.h> + #include <linux/bitops.h> + #include <linux/regmap.h> + #include <linux/thermal.h> ++#include <linux/slab.h> + #include <linux/nvmem-consumer.h> + #include <linux/io.h> + #include <linux/interrupt.h> +@@ -210,9 +212,8 @@ + struct tsens_device *tmdev = container_of(work, struct tsens_device, + tsens_work); + unsigned int threshold, threshold_low, code, reg, sensor, mask; +- unsigned int sensor_addr; + bool upper_th_x, lower_th_x; +- int adc_code, ret; ++ int ret; + + ret = regmap_read(tmdev->map, STATUS_CNTL_8064, ®); + if (ret) +@@ -261,9 +262,8 @@ + if (upper_th_x || lower_th_x) { + /* Notify user space */ + schedule_work(&tmdev->sensor[0].notify_work); +- regmap_read(tmdev->map, sensor_addr, &adc_code); + pr_debug("Trigger (%d degrees) for sensor %d\n", +- code_to_degC(adc_code, &tmdev->sensor[0]), 0); ++ code_to_degC(code, &tmdev->sensor[0]), 0); + } + } + regmap_write(tmdev->map, STATUS_CNTL_8064, reg & mask); +@@ -372,40 +372,55 @@ + static int calibrate_ipq8064(struct tsens_device *tmdev) + { + int i; +- char *data, *data_backup; +- ++ int ret = 0; ++ u8 *data, *data_backup; ++ struct device *dev = tmdev->dev; + ssize_t num_read = tmdev->num_sensors; + struct tsens_sensor *s = tmdev->sensor; + +- data = qfprom_read(tmdev->dev, "calib"); ++ data = qfprom_read(dev, "calib"); + if (IS_ERR(data)) { +- pr_err("Calibration not found.\n"); +- return PTR_ERR(data); ++ ret = PTR_ERR(data); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Calibration not found."); ++ goto exit; + } + +- data_backup = qfprom_read(tmdev->dev, "calib_backup"); ++ data_backup = qfprom_read(dev, "calib_backup"); + if (IS_ERR(data_backup)) { +- pr_err("Backup calibration not found.\n"); +- return PTR_ERR(data_backup); ++ ret = PTR_ERR(data_backup); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Backup Calibration not found."); ++ goto free_data; + } + + for (i = 0; i < num_read; i++) { + s[i].calib_data = readb_relaxed(data + i); +- s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data) { ++ s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data_backup) { ++ dev_err(dev, "QFPROM TSENS calibration data not present"); ++ ret = -ENODEV; ++ goto free_backup; ++ } + +- if (s[i].calib_data_backup) + s[i].calib_data = s[i].calib_data_backup; +- if (!s[i].calib_data) { +- pr_err("QFPROM TSENS calibration data not present\n"); +- return -ENODEV; + } ++ + s[i].slope = tsens_8064_slope[i]; + s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); + } + + hw_init(tmdev); + +- return 0; ++free_backup: ++ kfree(data_backup); ++free_data: ++ kfree(data); ++exit: ++ return ret; + } + + static int get_temp_ipq8064(struct tsens_device *tmdev, int id, int *temp) |