Dne petek, 09. februar 2024 ob 15:42:19 CET je Andre Przywara napisal(a): > The Allwinner H616 SoC needs to clear a bit in one register in the SRAM > controller, to report reasonable temperature values. On reset, bit 16 in > register 0x3000000 is set, which leads to the driver reporting > temperatures around 200C. Clearing this bit brings the values down to the > expected range. The BSP code does a one-time write in U-Boot, with a > comment just mentioning the effect on the THS, but offering no further > explanation. > > To not rely on firmware to set things up for us, add code that queries > the SRAM controller device via a DT phandle link, then clear just this > single bit. > > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> > --- > drivers/thermal/sun8i_thermal.c | 50 +++++++++++++++++++++++++++++++++ > 1 file changed, 50 insertions(+) > > diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c > index c919b0fd5e169..8a9d2bdc71ece 100644 > --- a/drivers/thermal/sun8i_thermal.c > +++ b/drivers/thermal/sun8i_thermal.c > @@ -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> > @@ -66,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; > @@ -83,6 +85,7 @@ 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; > @@ -337,6 +340,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; > @@ -381,6 +412,21 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev) > if (ret) > return ret; > > + if (tmdev->chip->needs_sram) { > + const struct reg_field sun8i_sram_reg_field = > + REG_FIELD(0x0, 16, 16); What about global static constant for a field? Many drivers do so and code would be simpler. Best regards, Jernej > + 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_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; > @@ -427,6 +473,10 @@ 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); > + > /* > * The manual recommends an overall sample frequency of 50 KHz (20us, > * 480 cycles at 24 MHz), which provides plenty of time for both the >