Commit ed302ad5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'thermal-6.9-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more thermal control updates from Rafael Wysocki:
 "These update thermal drivers for ARM platforms by adding new hardware
  support (r8a779h0, H616 THS), addressing issues (Mediatek LVTS,
  Mediatek MT7896, thermal-of) and cleaning up code.

  Specifics:

   - Fix memory leak in the error path at probe time in the Mediatek
     LVTS driver (Christophe Jaillet)

   - Fix control buffer enablement regression on Meditek MT7896 (Frank
     Wunderlich)

   - Drop spaces before TABs in different places: thermal-of, ST drivers
     and Makefile (Geert Uytterhoeven)

   - Adjust DT binding for NXP as fsl,tmu-range min/maxItems can vary
     among several SoC versions (Fabio Estevam)

   - Add support for the H616 THS controller on Sun8i platforms (Martin
     Botka)

   - Don't fail probe due to zone registration failure because there is
     no trip points defined in the DT (Mark Brown)

   - Support variable TMU array size for new platforms (Peng Fan)

   - Adjust the DT binding for thermal-of and make the polling time not
     required and assume it is zero when not found in the DT (Konrad
     Dybcio)

   - Add r8a779h0 support in both the DT and the rcar_gen3 driver (Geert
     Uytterhoeven)"

* tag 'thermal-6.9-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  thermal/drivers/rcar_gen3: Add support for R-Car V4M
  dt-bindings: thermal: rcar-gen3-thermal: Add r8a779h0 support
  thermal/of: Assume polling-delay(-passive) 0 when absent
  dt-bindings: thermal-zones: Don't require polling-delay(-passive)
  thermal/drivers/qoriq: Fix getting tmu range
  thermal/drivers/sun8i: Don't fail probe due to zone registration failure
  thermal/drivers/sun8i: Add support for H616 THS controller
  thermal/drivers/sun8i: Add SRAM register access code
  thermal/drivers/sun8i: Extend H6 calibration to support 4 sensors
  thermal/drivers/sun8i: Explain unknown H6 register value
  dt-bindings: thermal: sun8i: Add H616 THS controller
  soc: sunxi: sram: export register 0 for THS on H616
  dt-bindings: thermal: qoriq-thermal: Adjust fsl,tmu-range min/maxItems
  thermal: Drop spaces before TABs
  thermal/drivers/mediatek: Fix control buffer enablement on MT7896
  thermal/drivers/mediatek/lvts_thermal: Fix a memory leak in an error handling path
parents 2f3c2b39 4e7193ac
...@@ -21,6 +21,7 @@ properties: ...@@ -21,6 +21,7 @@ properties:
- allwinner,sun50i-a100-ths - allwinner,sun50i-a100-ths
- allwinner,sun50i-h5-ths - allwinner,sun50i-h5-ths
- allwinner,sun50i-h6-ths - allwinner,sun50i-h6-ths
- allwinner,sun50i-h616-ths
clocks: clocks:
minItems: 1 minItems: 1
...@@ -50,6 +51,10 @@ properties: ...@@ -50,6 +51,10 @@ properties:
nvmem-cell-names: nvmem-cell-names:
const: calibration const: calibration
allwinner,sram:
maxItems: 1
description: phandle to device controlling temperate offset SYS_CFG register
# See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details # See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details
"#thermal-sensor-cells": "#thermal-sensor-cells":
enum: enum:
...@@ -65,6 +70,7 @@ allOf: ...@@ -65,6 +70,7 @@ allOf:
- allwinner,sun20i-d1-ths - allwinner,sun20i-d1-ths
- allwinner,sun50i-a100-ths - allwinner,sun50i-a100-ths
- allwinner,sun50i-h6-ths - allwinner,sun50i-h6-ths
- allwinner,sun50i-h616-ths
then: then:
properties: properties:
...@@ -82,6 +88,17 @@ allOf: ...@@ -82,6 +88,17 @@ allOf:
clock-names: clock-names:
minItems: 2 minItems: 2
- if:
not:
properties:
compatible:
contains:
const: allwinner,sun50i-h616-ths
then:
properties:
allwinner,sram: false
- if: - if:
properties: properties:
compatible: compatible:
...@@ -101,17 +118,12 @@ allOf: ...@@ -101,17 +118,12 @@ allOf:
const: 1 const: 1
- if: - if:
not:
properties: properties:
compatible: compatible:
contains: contains:
enum: enum:
- allwinner,sun8i-h3-ths - allwinner,sun8i-a83t-ths
- allwinner,sun8i-r40-ths
- allwinner,sun20i-d1-ths
- allwinner,sun50i-a64-ths
- allwinner,sun50i-a100-ths
- allwinner,sun50i-h5-ths
- allwinner,sun50i-h6-ths
then: then:
required: required:
......
...@@ -33,7 +33,8 @@ properties: ...@@ -33,7 +33,8 @@ properties:
description: | description: |
The values to be programmed into TTRnCR, as specified by the SoC The values to be programmed into TTRnCR, as specified by the SoC
reference manual. The first cell is TTR0CR, the second is TTR1CR, etc. reference manual. The first cell is TTR0CR, the second is TTR1CR, etc.
maxItems: 4 minItems: 2
maxItems: 7
fsl,tmu-calibration: fsl,tmu-calibration:
$ref: /schemas/types.yaml#/definitions/uint32-matrix $ref: /schemas/types.yaml#/definitions/uint32-matrix
......
...@@ -29,6 +29,7 @@ properties: ...@@ -29,6 +29,7 @@ properties:
- renesas,r8a779a0-thermal # R-Car V3U - renesas,r8a779a0-thermal # R-Car V3U
- renesas,r8a779f0-thermal # R-Car S4-8 - renesas,r8a779f0-thermal # R-Car S4-8
- renesas,r8a779g0-thermal # R-Car V4H - renesas,r8a779g0-thermal # R-Car V4H
- renesas,r8a779h0-thermal # R-Car V4M
reg: true reg: true
...@@ -90,6 +91,7 @@ else: ...@@ -90,6 +91,7 @@ else:
enum: enum:
- renesas,r8a779f0-thermal - renesas,r8a779f0-thermal
- renesas,r8a779g0-thermal - renesas,r8a779g0-thermal
- renesas,r8a779h0-thermal
then: then:
required: required:
- interrupts - interrupts
......
...@@ -228,8 +228,6 @@ patternProperties: ...@@ -228,8 +228,6 @@ patternProperties:
additionalProperties: false additionalProperties: false
required: required:
- polling-delay
- polling-delay-passive
- thermal-sensors - thermal-sensors
- trips - trips
......
...@@ -287,6 +287,7 @@ EXPORT_SYMBOL(sunxi_sram_release); ...@@ -287,6 +287,7 @@ EXPORT_SYMBOL(sunxi_sram_release);
struct sunxi_sramc_variant { struct sunxi_sramc_variant {
int num_emac_clocks; int num_emac_clocks;
bool has_ldo_ctrl; bool has_ldo_ctrl;
bool has_ths_offset;
}; };
static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
...@@ -308,8 +309,10 @@ static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { ...@@ -308,8 +309,10 @@ static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = { static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = {
.num_emac_clocks = 2, .num_emac_clocks = 2,
.has_ths_offset = true,
}; };
#define SUNXI_SRAM_THS_OFFSET_REG 0x0
#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30 #define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
#define SUNXI_SYS_LDO_CTRL_REG 0x150 #define SUNXI_SYS_LDO_CTRL_REG 0x150
...@@ -318,6 +321,8 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev, ...@@ -318,6 +321,8 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
{ {
const struct sunxi_sramc_variant *variant = dev_get_drvdata(dev); const struct sunxi_sramc_variant *variant = dev_get_drvdata(dev);
if (reg == SUNXI_SRAM_THS_OFFSET_REG && variant->has_ths_offset)
return true;
if (reg >= SUNXI_SRAM_EMAC_CLOCK_REG && if (reg >= SUNXI_SRAM_EMAC_CLOCK_REG &&
reg < SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4) reg < SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
return true; return true;
...@@ -327,6 +332,20 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev, ...@@ -327,6 +332,20 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
return false; return false;
} }
static void sunxi_sram_lock(void *_lock)
{
spinlock_t *lock = _lock;
spin_lock(lock);
}
static void sunxi_sram_unlock(void *_lock)
{
spinlock_t *lock = _lock;
spin_unlock(lock);
}
static struct regmap_config sunxi_sram_regmap_config = { static struct regmap_config sunxi_sram_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.val_bits = 32, .val_bits = 32,
...@@ -336,6 +355,9 @@ static struct regmap_config sunxi_sram_regmap_config = { ...@@ -336,6 +355,9 @@ static struct regmap_config sunxi_sram_regmap_config = {
/* other devices have no business accessing other registers */ /* other devices have no business accessing other registers */
.readable_reg = sunxi_sram_regmap_accessible_reg, .readable_reg = sunxi_sram_regmap_accessible_reg,
.writeable_reg = sunxi_sram_regmap_accessible_reg, .writeable_reg = sunxi_sram_regmap_accessible_reg,
.lock = sunxi_sram_lock,
.unlock = sunxi_sram_unlock,
.lock_arg = &sram_lock,
}; };
static int __init sunxi_sram_probe(struct platform_device *pdev) static int __init sunxi_sram_probe(struct platform_device *pdev)
......
...@@ -690,6 +690,9 @@ static const struct mtk_thermal_data mt7986_thermal_data = { ...@@ -690,6 +690,9 @@ static const struct mtk_thermal_data mt7986_thermal_data = {
.adcpnp = mt7986_adcpnp, .adcpnp = mt7986_adcpnp,
.sensor_mux_values = mt7986_mux_values, .sensor_mux_values = mt7986_mux_values,
.version = MTK_THERMAL_V3, .version = MTK_THERMAL_V3,
.apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1,
.apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3),
.apmixed_buffer_ctl_set = BIT(0),
}; };
static bool mtk_thermal_temp_is_valid(int temp) static bool mtk_thermal_temp_is_valid(int temp)
......
...@@ -719,8 +719,10 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td ...@@ -719,8 +719,10 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td
lvts_td->calib = devm_krealloc(dev, lvts_td->calib, lvts_td->calib = devm_krealloc(dev, lvts_td->calib,
lvts_td->calib_len + len, GFP_KERNEL); lvts_td->calib_len + len, GFP_KERNEL);
if (!lvts_td->calib) if (!lvts_td->calib) {
kfree(efuse);
return -ENOMEM; return -ENOMEM;
}
memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len); memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len);
......
...@@ -57,6 +57,9 @@ ...@@ -57,6 +57,9 @@
#define REGS_TTRnCR(n) (0xf10 + 4 * (n)) /* Temperature Range n #define REGS_TTRnCR(n) (0xf10 + 4 * (n)) /* Temperature Range n
* Control Register * Control Register
*/ */
#define NUM_TTRCR_V1 4
#define NUM_TTRCR_MAX 16
#define REGS_IPBRR(n) (0xbf8 + 4 * (n)) /* IP Block Revision #define REGS_IPBRR(n) (0xbf8 + 4 * (n)) /* IP Block Revision
* Register n * Register n
*/ */
...@@ -71,6 +74,7 @@ struct qoriq_sensor { ...@@ -71,6 +74,7 @@ struct qoriq_sensor {
struct qoriq_tmu_data { struct qoriq_tmu_data {
int ver; int ver;
u32 ttrcr[NUM_TTRCR_MAX];
struct regmap *regmap; struct regmap *regmap;
struct clk *clk; struct clk *clk;
struct qoriq_sensor sensor[SITES_MAX]; struct qoriq_sensor sensor[SITES_MAX];
...@@ -182,17 +186,17 @@ static int qoriq_tmu_calibration(struct device *dev, ...@@ -182,17 +186,17 @@ static int qoriq_tmu_calibration(struct device *dev,
struct qoriq_tmu_data *data) struct qoriq_tmu_data *data)
{ {
int i, val, len; int i, val, len;
u32 range[4];
const u32 *calibration; const u32 *calibration;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
len = of_property_count_u32_elems(np, "fsl,tmu-range"); len = of_property_count_u32_elems(np, "fsl,tmu-range");
if (len < 0 || len > 4) { if (len < 0 || (data->ver == TMU_VER1 && len > NUM_TTRCR_V1) ||
(data->ver > TMU_VER1 && len > NUM_TTRCR_MAX)) {
dev_err(dev, "invalid range data.\n"); dev_err(dev, "invalid range data.\n");
return len; return len;
} }
val = of_property_read_u32_array(np, "fsl,tmu-range", range, len); val = of_property_read_u32_array(np, "fsl,tmu-range", data->ttrcr, len);
if (val != 0) { if (val != 0) {
dev_err(dev, "failed to read range data.\n"); dev_err(dev, "failed to read range data.\n");
return val; return val;
...@@ -200,7 +204,7 @@ static int qoriq_tmu_calibration(struct device *dev, ...@@ -200,7 +204,7 @@ static int qoriq_tmu_calibration(struct device *dev,
/* Init temperature range registers */ /* Init temperature range registers */
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
regmap_write(data->regmap, REGS_TTRnCR(i), range[i]); regmap_write(data->regmap, REGS_TTRnCR(i), data->ttrcr[i]);
calibration = of_get_property(np, "fsl,tmu-calibration", &len); calibration = of_get_property(np, "fsl,tmu-calibration", &len);
if (calibration == NULL || len % 8) { if (calibration == NULL || len % 8) {
......
...@@ -428,6 +428,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { ...@@ -428,6 +428,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
.compatible = "renesas,r8a779g0-thermal", .compatible = "renesas,r8a779g0-thermal",
.data = &rcar_gen4_thermal_info, .data = &rcar_gen4_thermal_info,
}, },
{
.compatible = "renesas,r8a779h0-thermal",
.data = &rcar_gen4_thermal_info,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/nvmem-consumer.h> #include <linux/nvmem-consumer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/reset.h> #include <linux/reset.h>
...@@ -50,7 +51,8 @@ ...@@ -50,7 +51,8 @@
#define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16) #define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16)
#define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8) #define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8)
#define SUN50I_THS_CTRL0_T_ACQ(x) ((GENMASK(15, 0) & (x)) << 16) #define SUN50I_THS_CTRL0_T_ACQ(x) (GENMASK(15, 0) & ((x) - 1))
#define SUN50I_THS_CTRL0_T_SAMPLE_PER(x) ((GENMASK(15, 0) & ((x) - 1)) << 16)
#define SUN50I_THS_FILTER_EN BIT(2) #define SUN50I_THS_FILTER_EN BIT(2)
#define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) #define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) #define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12)
...@@ -65,6 +67,7 @@ struct tsensor { ...@@ -65,6 +67,7 @@ struct tsensor {
struct ths_thermal_chip { struct ths_thermal_chip {
bool has_mod_clk; bool has_mod_clk;
bool has_bus_clk_reset; bool has_bus_clk_reset;
bool needs_sram;
int sensor_num; int sensor_num;
int offset; int offset;
int scale; int scale;
...@@ -82,12 +85,16 @@ struct ths_device { ...@@ -82,12 +85,16 @@ struct ths_device {
const struct ths_thermal_chip *chip; const struct ths_thermal_chip *chip;
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
struct regmap_field *sram_regmap_field;
struct reset_control *reset; struct reset_control *reset;
struct clk *bus_clk; struct clk *bus_clk;
struct clk *mod_clk; struct clk *mod_clk;
struct tsensor sensor[MAX_SENSOR_NUM]; struct tsensor sensor[MAX_SENSOR_NUM];
}; };
/* The H616 needs to have a bit 16 in the SRAM control register cleared. */
static const struct reg_field sun8i_ths_sram_reg_field = REG_FIELD(0x0, 16, 16);
/* Temp Unit: millidegree Celsius */ /* Temp Unit: millidegree Celsius */
static int sun8i_ths_calc_temp(struct ths_device *tmdev, static int sun8i_ths_calc_temp(struct ths_device *tmdev,
int id, int reg) int id, int reg)
...@@ -188,6 +195,9 @@ static irqreturn_t sun8i_irq_thread(int irq, void *data) ...@@ -188,6 +195,9 @@ static irqreturn_t sun8i_irq_thread(int irq, void *data)
int i; int i;
for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) { for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) {
/* We allow some zones to not register. */
if (IS_ERR(tmdev->sensor[i].tzd))
continue;
thermal_zone_device_update(tmdev->sensor[i].tzd, thermal_zone_device_update(tmdev->sensor[i].tzd,
THERMAL_EVENT_UNSPECIFIED); THERMAL_EVENT_UNSPECIFIED);
} }
...@@ -221,16 +231,21 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev, ...@@ -221,16 +231,21 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
struct device *dev = tmdev->dev; struct device *dev = tmdev->dev;
int i, ft_temp; int i, ft_temp;
if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num) if (!caldata[0])
return -EINVAL; return -EINVAL;
/* /*
* efuse layout: * efuse layout:
* *
* 0 11 16 32 * 0 11 16 27 32 43 48 57
* +-------+-------+-------+ * +----------+-----------+-----------+-----------+
* |temp| |sensor0|sensor1| * | temp | |sensor0| |sensor1| |sensor2| |
* +-------+-------+-------+ * +----------+-----------+-----------+-----------+
* ^ ^ ^
* | | |
* | | sensor3[11:8]
* | sensor3[7:4]
* sensor3[3:0]
* *
* The calibration data on the H6 is the ambient temperature and * The calibration data on the H6 is the ambient temperature and
* sensor values that are filled during the factory test stage. * sensor values that are filled during the factory test stage.
...@@ -243,9 +258,16 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev, ...@@ -243,9 +258,16 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
ft_temp = (caldata[0] & FT_TEMP_MASK) * 100; ft_temp = (caldata[0] & FT_TEMP_MASK) * 100;
for (i = 0; i < tmdev->chip->sensor_num; i++) { for (i = 0; i < tmdev->chip->sensor_num; i++) {
int sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK; int sensor_reg, sensor_temp, cdata, offset;
int cdata, offset;
int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg); if (i == 3)
sensor_reg = (caldata[1] >> 12)
| ((caldata[2] >> 12) << 4)
| ((caldata[3] >> 12) << 8);
else
sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK;
sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
/* /*
* Calibration data is CALIBRATE_DEFAULT - (calculated * Calibration data is CALIBRATE_DEFAULT - (calculated
...@@ -324,6 +346,34 @@ static void sun8i_ths_reset_control_assert(void *data) ...@@ -324,6 +346,34 @@ static void sun8i_ths_reset_control_assert(void *data)
reset_control_assert(data); reset_control_assert(data);
} }
static struct regmap *sun8i_ths_get_sram_regmap(struct device_node *node)
{
struct device_node *sram_node;
struct platform_device *sram_pdev;
struct regmap *regmap = NULL;
sram_node = of_parse_phandle(node, "allwinner,sram", 0);
if (!sram_node)
return ERR_PTR(-ENODEV);
sram_pdev = of_find_device_by_node(sram_node);
if (!sram_pdev) {
/* platform device might not be probed yet */
regmap = ERR_PTR(-EPROBE_DEFER);
goto out_put_node;
}
/* If no regmap is found then the other device driver is at fault */
regmap = dev_get_regmap(&sram_pdev->dev, NULL);
if (!regmap)
regmap = ERR_PTR(-EINVAL);
platform_device_put(sram_pdev);
out_put_node:
of_node_put(sram_node);
return regmap;
}
static int sun8i_ths_resource_init(struct ths_device *tmdev) static int sun8i_ths_resource_init(struct ths_device *tmdev)
{ {
struct device *dev = tmdev->dev; struct device *dev = tmdev->dev;
...@@ -368,6 +418,19 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev) ...@@ -368,6 +418,19 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
if (ret) if (ret)
return ret; return ret;
if (tmdev->chip->needs_sram) {
struct regmap *regmap;
regmap = sun8i_ths_get_sram_regmap(dev->of_node);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
tmdev->sram_regmap_field = devm_regmap_field_alloc(dev,
regmap,
sun8i_ths_sram_reg_field);
if (IS_ERR(tmdev->sram_regmap_field))
return PTR_ERR(tmdev->sram_regmap_field);
}
ret = sun8i_ths_calibrate(tmdev); ret = sun8i_ths_calibrate(tmdev);
if (ret) if (ret)
return ret; return ret;
...@@ -410,25 +473,31 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev) ...@@ -410,25 +473,31 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev)
return 0; return 0;
} }
/*
* Without this undocumented value, the returned temperatures would
* be higher than real ones by about 20C.
*/
#define SUN50I_H6_CTRL0_UNK 0x0000002f
static int sun50i_h6_thermal_init(struct ths_device *tmdev) static int sun50i_h6_thermal_init(struct ths_device *tmdev)
{ {
int val; int val;
/* The H616 needs to have a bit in the SRAM control register cleared. */
if (tmdev->sram_regmap_field)
regmap_field_write(tmdev->sram_regmap_field, 0);
/* /*
* T_acq = 20us * The manual recommends an overall sample frequency of 50 KHz (20us,
* clkin = 24MHz * 480 cycles at 24 MHz), which provides plenty of time for both the
* * acquisition time (>24 cycles) and the actual conversion time
* x = T_acq * clkin - 1 * (>14 cycles).
* = 479 * The lower half of the CTRL register holds the "acquire time", in
* clock cycles, which the manual recommends to be 2us:
* 24MHz * 2us = 48 cycles.
* The high half of THS_CTRL encodes the sample frequency, in clock
* cycles: 24MHz * 20us = 480 cycles.
* This is explained in the H616 manual, but apparently wrongly
* described in the H6 manual, although the BSP code does the same
* for both SoCs.
*/ */
regmap_write(tmdev->regmap, SUN50I_THS_CTRL0, regmap_write(tmdev->regmap, SUN50I_THS_CTRL0,
SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479)); SUN50I_THS_CTRL0_T_ACQ(48) |
SUN50I_THS_CTRL0_T_SAMPLE_PER(480));
/* average over 4 samples */ /* average over 4 samples */
regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC, regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC,
SUN50I_THS_FILTER_EN | SUN50I_THS_FILTER_EN |
...@@ -465,8 +534,17 @@ static int sun8i_ths_register(struct ths_device *tmdev) ...@@ -465,8 +534,17 @@ static int sun8i_ths_register(struct ths_device *tmdev)
i, i,
&tmdev->sensor[i], &tmdev->sensor[i],
&ths_ops); &ths_ops);
if (IS_ERR(tmdev->sensor[i].tzd))
/*
* If an individual zone fails to register for reasons
* other than probe deferral (eg, a bad DT) then carry
* on, other zones might register successfully.
*/
if (IS_ERR(tmdev->sensor[i].tzd)) {
if (PTR_ERR(tmdev->sensor[i].tzd) == -EPROBE_DEFER)
return PTR_ERR(tmdev->sensor[i].tzd); return PTR_ERR(tmdev->sensor[i].tzd);
continue;
}
devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd); devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd);
} }
...@@ -618,6 +696,20 @@ static const struct ths_thermal_chip sun20i_d1_ths = { ...@@ -618,6 +696,20 @@ static const struct ths_thermal_chip sun20i_d1_ths = {
.calc_temp = sun8i_ths_calc_temp, .calc_temp = sun8i_ths_calc_temp,
}; };
static const struct ths_thermal_chip sun50i_h616_ths = {
.sensor_num = 4,
.has_bus_clk_reset = true,
.needs_sram = true,
.ft_deviation = 8000,
.offset = 263655,
.scale = 810,
.temp_data_base = SUN50I_H6_THS_TEMP_DATA,
.calibrate = sun50i_h6_ths_calibrate,
.init = sun50i_h6_thermal_init,
.irq_ack = sun50i_h6_irq_ack,
.calc_temp = sun8i_ths_calc_temp,
};
static const struct of_device_id of_ths_match[] = { static const struct of_device_id of_ths_match[] = {
{ .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths }, { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
{ .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths }, { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
...@@ -627,6 +719,7 @@ static const struct of_device_id of_ths_match[] = { ...@@ -627,6 +719,7 @@ static const struct of_device_id of_ths_match[] = {
{ .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths }, { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths },
{ .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths }, { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths },
{ .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths }, { .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths },
{ .compatible = "allwinner,sun50i-h616-ths", .data = &sun50i_h616_ths },
{ /* sentinel */ }, { /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(of, of_ths_match); MODULE_DEVICE_TABLE(of, of_ths_match);
......
...@@ -227,14 +227,18 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel ...@@ -227,14 +227,18 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
int ret; int ret;
ret = of_property_read_u32(np, "polling-delay-passive", pdelay); ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
if (ret < 0) { if (ret == -EINVAL) {
pr_err("%pOFn: missing polling-delay-passive property\n", np); *pdelay = 0;
} else if (ret < 0) {
pr_err("%pOFn: Couldn't get polling-delay-passive: %d\n", np, ret);
return ret; return ret;
} }
ret = of_property_read_u32(np, "polling-delay", delay); ret = of_property_read_u32(np, "polling-delay", delay);
if (ret < 0) { if (ret == -EINVAL) {
pr_err("%pOFn: missing polling-delay property\n", np); *delay = 0;
} else if (ret < 0) {
pr_err("%pOFn: Couldn't get polling-delay: %d\n", np, ret);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment