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:
- allwinner,sun50i-a100-ths
- allwinner,sun50i-h5-ths
- allwinner,sun50i-h6-ths
- allwinner,sun50i-h616-ths
clocks:
minItems: 1
......@@ -50,6 +51,10 @@ properties:
nvmem-cell-names:
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
"#thermal-sensor-cells":
enum:
......@@ -65,6 +70,7 @@ allOf:
- allwinner,sun20i-d1-ths
- allwinner,sun50i-a100-ths
- allwinner,sun50i-h6-ths
- allwinner,sun50i-h616-ths
then:
properties:
......@@ -82,6 +88,17 @@ allOf:
clock-names:
minItems: 2
- if:
not:
properties:
compatible:
contains:
const: allwinner,sun50i-h616-ths
then:
properties:
allwinner,sram: false
- if:
properties:
compatible:
......@@ -101,17 +118,12 @@ allOf:
const: 1
- if:
not:
properties:
compatible:
contains:
enum:
- allwinner,sun8i-h3-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
- allwinner,sun8i-a83t-ths
then:
required:
......
......@@ -33,7 +33,8 @@ properties:
description: |
The values to be programmed into TTRnCR, as specified by the SoC
reference manual. The first cell is TTR0CR, the second is TTR1CR, etc.
maxItems: 4
minItems: 2
maxItems: 7
fsl,tmu-calibration:
$ref: /schemas/types.yaml#/definitions/uint32-matrix
......
......@@ -29,6 +29,7 @@ properties:
- renesas,r8a779a0-thermal # R-Car V3U
- renesas,r8a779f0-thermal # R-Car S4-8
- renesas,r8a779g0-thermal # R-Car V4H
- renesas,r8a779h0-thermal # R-Car V4M
reg: true
......@@ -90,6 +91,7 @@ else:
enum:
- renesas,r8a779f0-thermal
- renesas,r8a779g0-thermal
- renesas,r8a779h0-thermal
then:
required:
- interrupts
......
......@@ -228,8 +228,6 @@ patternProperties:
additionalProperties: false
required:
- polling-delay
- polling-delay-passive
- thermal-sensors
- trips
......
......@@ -287,6 +287,7 @@ EXPORT_SYMBOL(sunxi_sram_release);
struct sunxi_sramc_variant {
int num_emac_clocks;
bool has_ldo_ctrl;
bool has_ths_offset;
};
static const struct sunxi_sramc_variant sun4i_a10_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 = {
.num_emac_clocks = 2,
.has_ths_offset = true,
};
#define SUNXI_SRAM_THS_OFFSET_REG 0x0
#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
#define SUNXI_SYS_LDO_CTRL_REG 0x150
......@@ -318,6 +321,8 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *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 &&
reg < SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
return true;
......@@ -327,6 +332,20 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
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 = {
.reg_bits = 32,
.val_bits = 32,
......@@ -336,6 +355,9 @@ static struct regmap_config sunxi_sram_regmap_config = {
/* other devices have no business accessing other registers */
.readable_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)
......
......@@ -690,6 +690,9 @@ static const struct mtk_thermal_data mt7986_thermal_data = {
.adcpnp = mt7986_adcpnp,
.sensor_mux_values = mt7986_mux_values,
.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)
......
......@@ -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_len + len, GFP_KERNEL);
if (!lvts_td->calib)
if (!lvts_td->calib) {
kfree(efuse);
return -ENOMEM;
}
memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len);
......
......@@ -57,6 +57,9 @@
#define REGS_TTRnCR(n) (0xf10 + 4 * (n)) /* Temperature Range n
* Control Register
*/
#define NUM_TTRCR_V1 4
#define NUM_TTRCR_MAX 16
#define REGS_IPBRR(n) (0xbf8 + 4 * (n)) /* IP Block Revision
* Register n
*/
......@@ -71,6 +74,7 @@ struct qoriq_sensor {
struct qoriq_tmu_data {
int ver;
u32 ttrcr[NUM_TTRCR_MAX];
struct regmap *regmap;
struct clk *clk;
struct qoriq_sensor sensor[SITES_MAX];
......@@ -182,17 +186,17 @@ static int qoriq_tmu_calibration(struct device *dev,
struct qoriq_tmu_data *data)
{
int i, val, len;
u32 range[4];
const u32 *calibration;
struct device_node *np = dev->of_node;
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");
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) {
dev_err(dev, "failed to read range data.\n");
return val;
......@@ -200,7 +204,7 @@ static int qoriq_tmu_calibration(struct device *dev,
/* Init temperature range registers */
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);
if (calibration == NULL || len % 8) {
......
......@@ -428,6 +428,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
.compatible = "renesas,r8a779g0-thermal",
.data = &rcar_gen4_thermal_info,
},
{
.compatible = "renesas,r8a779h0-thermal",
.data = &rcar_gen4_thermal_info,
},
{},
};
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
......
......@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
......@@ -50,7 +51,8 @@
#define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16)
#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_TYPE(x) (GENMASK(1, 0) & (x))
#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12)
......@@ -65,6 +67,7 @@ struct tsensor {
struct ths_thermal_chip {
bool has_mod_clk;
bool has_bus_clk_reset;
bool needs_sram;
int sensor_num;
int offset;
int scale;
......@@ -82,12 +85,16 @@ struct ths_device {
const struct ths_thermal_chip *chip;
struct device *dev;
struct regmap *regmap;
struct regmap_field *sram_regmap_field;
struct reset_control *reset;
struct clk *bus_clk;
struct clk *mod_clk;
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 */
static int sun8i_ths_calc_temp(struct ths_device *tmdev,
int id, int reg)
......@@ -188,6 +195,9 @@ static irqreturn_t sun8i_irq_thread(int irq, void *data)
int i;
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_EVENT_UNSPECIFIED);
}
......@@ -221,16 +231,21 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
struct device *dev = tmdev->dev;
int i, ft_temp;
if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num)
if (!caldata[0])
return -EINVAL;
/*
* efuse layout:
*
* 0 11 16 32
* +-------+-------+-------+
* |temp| |sensor0|sensor1|
* +-------+-------+-------+
* 0 11 16 27 32 43 48 57
* +----------+-----------+-----------+-----------+
* | temp | |sensor0| |sensor1| |sensor2| |
* +----------+-----------+-----------+-----------+
* ^ ^ ^
* | | |
* | | sensor3[11:8]
* | sensor3[7:4]
* sensor3[3:0]
*
* The calibration data on the H6 is the ambient temperature and
* sensor values that are filled during the factory test stage.
......@@ -243,9 +258,16 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
ft_temp = (caldata[0] & FT_TEMP_MASK) * 100;
for (i = 0; i < tmdev->chip->sensor_num; i++) {
int sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK;
int cdata, offset;
int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
int sensor_reg, sensor_temp, cdata, offset;
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
......@@ -324,6 +346,34 @@ static void sun8i_ths_reset_control_assert(void *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)
{
struct device *dev = tmdev->dev;
......@@ -368,6 +418,19 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
if (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);
if (ret)
return ret;
......@@ -410,25 +473,31 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev)
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)
{
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
* clkin = 24MHz
*
* x = T_acq * clkin - 1
* = 479
* The manual recommends an overall sample frequency of 50 KHz (20us,
* 480 cycles at 24 MHz), which provides plenty of time for both the
* acquisition time (>24 cycles) and the actual conversion time
* (>14 cycles).
* 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,
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 */
regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC,
SUN50I_THS_FILTER_EN |
......@@ -465,8 +534,17 @@ static int sun8i_ths_register(struct ths_device *tmdev)
i,
&tmdev->sensor[i],
&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);
continue;
}
devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd);
}
......@@ -618,6 +696,20 @@ static const struct ths_thermal_chip sun20i_d1_ths = {
.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[] = {
{ .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
{ .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
......@@ -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-h6-ths", .data = &sun50i_h6_ths },
{ .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths },
{ .compatible = "allwinner,sun50i-h616-ths", .data = &sun50i_h616_ths },
{ /* sentinel */ },
};
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
int ret;
ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
if (ret < 0) {
pr_err("%pOFn: missing polling-delay-passive property\n", np);
if (ret == -EINVAL) {
*pdelay = 0;
} else if (ret < 0) {
pr_err("%pOFn: Couldn't get polling-delay-passive: %d\n", np, ret);
return ret;
}
ret = of_property_read_u32(np, "polling-delay", delay);
if (ret < 0) {
pr_err("%pOFn: missing polling-delay property\n", np);
if (ret == -EINVAL) {
*delay = 0;
} else if (ret < 0) {
pr_err("%pOFn: Couldn't get polling-delay: %d\n", np, 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