More thermal control updates for 6.9-rc1
- 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). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmX5iDQSHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRx8AAP/3SqwpcoUrb4wLC0K8d4r+KkZef3Ju3q phT9PNVYb1/eK1pEdr82wa8jXZkKn20bQhQR5FhJM3hfJJf3LwnP2AFtojkF5P8i Tg3AS9fGRXhXOP4BOwvZ4V0NjtFyf+ICxm542n5FybZYD4/TlvmaNFDj83AzwhSZ UY085G17nabJ5oju9YgJ8pthFOtNHB0hKvnpvhaDG3kzzvAvYFlolhYfVh/rYeL0 bdZYXygTjokYttEuCUfSkN2g/1sNGWSWWfMjtoze+/lqjVPPX0qEklIuJ/GwVfYU mtHiHWDCRhlQ/lrHNhQWydJ78Dlbf64JQ5ExDuSmH6diaMXeVRtX+ORuPiwTtEQa DX0En7rbcXiXKy+9Q+X/Yql7nDEb3WYUOUFNgrvvYKgsX3l+wQk/y0PQStpL2Ol5 ypen+GCdGOgQuEduyjyVJY7DSv8YsMyo7KIdAnfp4lvnCsNgHHRbE/1z0kJYpPxG gZ+97sodxTLIHIytr8LNTvdSu+E0qY5E7fhbTL2wikhB4BoiIavARyvnZQ1yxuhb QOGNY6739nHW8nimgs+bc6y6UfdpuwKh0+ID28796fu4dOng9Spl9lHeQdUrzReR gVg2qyCv/oj4ij9eX+B/ZIajlETKMDVAGN4vA9rVmeGWQf3nkVmVMw0KIUi+V6HN 6n0kqo5lQ3Pb =jtjA -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ed302ad52b
@ -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:
|
|||||||
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:
|
|||||||
- 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:
|
|||||||
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:
|
|||||||
const: 1
|
const: 1
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
properties:
|
not:
|
||||||
compatible:
|
properties:
|
||||||
contains:
|
compatible:
|
||||||
enum:
|
contains:
|
||||||
- allwinner,sun8i-h3-ths
|
enum:
|
||||||
- allwinner,sun8i-r40-ths
|
- allwinner,sun8i-a83t-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:
|
|||||||
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:
|
|||||||
- 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:
|
|||||||
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:
|
|||||||
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);
|
|||||||
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 = {
|
|||||||
|
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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 = {
|
|||||||
/* 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)
|
||||||
|
@ -43,7 +43,7 @@ obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o
|
|||||||
obj-$(CONFIG_RZG2L_THERMAL) += rzg2l_thermal.o
|
obj-$(CONFIG_RZG2L_THERMAL) += rzg2l_thermal.o
|
||||||
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
|
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
|
||||||
obj-y += samsung/
|
obj-y += samsung/
|
||||||
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
|
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
|
||||||
obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
|
obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
|
||||||
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
|
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
|
||||||
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
|
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
|
||||||
|
@ -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
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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[] = {
|
|||||||
.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);
|
||||||
|
@ -38,10 +38,10 @@ struct st_thermal_sensor;
|
|||||||
*
|
*
|
||||||
* @power_ctrl: Function for powering on/off a sensor. Clock to the
|
* @power_ctrl: Function for powering on/off a sensor. Clock to the
|
||||||
* sensor is also controlled from this function.
|
* sensor is also controlled from this function.
|
||||||
* @alloc_regfields: Allocate regmap register fields, specific to a sensor.
|
* @alloc_regfields: Allocate regmap register fields, specific to a sensor.
|
||||||
* @do_memmap_regmap: Memory map the thermal register space and init regmap
|
* @do_memmap_regmap: Memory map the thermal register space and init regmap
|
||||||
* instance or find regmap instance.
|
* instance or find regmap instance.
|
||||||
* @register_irq: Register an interrupt handler for a sensor.
|
* @register_irq: Register an interrupt handler for a sensor.
|
||||||
*/
|
*/
|
||||||
struct st_thermal_sensor_ops {
|
struct st_thermal_sensor_ops {
|
||||||
int (*power_ctrl)(struct st_thermal_sensor *, enum st_thermal_power_state);
|
int (*power_ctrl)(struct st_thermal_sensor *, enum st_thermal_power_state);
|
||||||
@ -56,15 +56,15 @@ struct st_thermal_sensor_ops {
|
|||||||
*
|
*
|
||||||
* @reg_fields: Pointer to the regfields array for a sensor.
|
* @reg_fields: Pointer to the regfields array for a sensor.
|
||||||
* @sys_compat: Pointer to the syscon node compatible string.
|
* @sys_compat: Pointer to the syscon node compatible string.
|
||||||
* @ops: Pointer to private thermal ops for a sensor.
|
* @ops: Pointer to private thermal ops for a sensor.
|
||||||
* @calibration_val: Default calibration value to be written to the DCORRECT
|
* @calibration_val: Default calibration value to be written to the DCORRECT
|
||||||
* register field for a sensor.
|
* register field for a sensor.
|
||||||
* @temp_adjust_val: Value to be added/subtracted from the data read from
|
* @temp_adjust_val: Value to be added/subtracted from the data read from
|
||||||
* the sensor. If value needs to be added please provide a
|
* the sensor. If value needs to be added please provide a
|
||||||
* positive value and if it is to be subtracted please
|
* positive value and if it is to be subtracted please
|
||||||
* provide a negative value.
|
* provide a negative value.
|
||||||
* @crit_temp: The temperature beyond which the SoC should be shutdown
|
* @crit_temp: The temperature beyond which the SoC should be shutdown
|
||||||
* to prevent damage.
|
* to prevent damage.
|
||||||
*/
|
*/
|
||||||
struct st_thermal_compat_data {
|
struct st_thermal_compat_data {
|
||||||
char *sys_compat;
|
char *sys_compat;
|
||||||
|
@ -27,7 +27,7 @@ static const struct reg_field st_mmap_thermal_regfields[MAX_REGFIELDS] = {
|
|||||||
* written simultaneously for powering on and off the temperature
|
* written simultaneously for powering on and off the temperature
|
||||||
* sensor. regmap_update_bits() will be used to update the register.
|
* sensor. regmap_update_bits() will be used to update the register.
|
||||||
*/
|
*/
|
||||||
[INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH, 0, 7),
|
[INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH, 0, 7),
|
||||||
[DCORRECT] = REG_FIELD(STIH416_MPE_CONF, 5, 9),
|
[DCORRECT] = REG_FIELD(STIH416_MPE_CONF, 5, 9),
|
||||||
[OVERFLOW] = REG_FIELD(STIH416_MPE_STATUS, 9, 9),
|
[OVERFLOW] = REG_FIELD(STIH416_MPE_STATUS, 9, 9),
|
||||||
[DATA] = REG_FIELD(STIH416_MPE_STATUS, 11, 18),
|
[DATA] = REG_FIELD(STIH416_MPE_STATUS, 11, 18),
|
||||||
|
@ -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 @@
|
|||||||
#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 {
|
|||||||
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 {
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
i,
|
i,
|
||||||
&tmdev->sensor[i],
|
&tmdev->sensor[i],
|
||||||
&ths_ops);
|
&ths_ops);
|
||||||
if (IS_ERR(tmdev->sensor[i].tzd))
|
|
||||||
return PTR_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);
|
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,
|
.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[] = {
|
|||||||
{ .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
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +464,7 @@ static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
|
|||||||
* @ops: A set of thermal sensor ops
|
* @ops: A set of thermal sensor ops
|
||||||
*
|
*
|
||||||
* Return: a valid thermal zone structure pointer on success.
|
* Return: a valid thermal zone structure pointer on success.
|
||||||
* - EINVAL: if the device tree thermal description is malformed
|
* - EINVAL: if the device tree thermal description is malformed
|
||||||
* - ENOMEM: if one structure can not be allocated
|
* - ENOMEM: if one structure can not be allocated
|
||||||
* - Other negative errors are returned by the underlying called functions
|
* - Other negative errors are returned by the underlying called functions
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user