mbox series

[v7,0/6] Add LVTS architecture thermal

Message ID 20220524152552.246193-1-abailon@baylibre.com
Headers show
Series Add LVTS architecture thermal | expand

Message

Alexandre Bailon May 24, 2022, 3:25 p.m. UTC
This patch move thermal files related to Mediatek to the mediatek folder.
And introduce the new architecture LVTS (low pressure thermal sensor) driver to report
the highest temperature in the SoC and record the highest temperature sensor,
each sensor as a hot zone.
The LVTS body is divided into two parts, the LVTS controller and the LVTS device.
The LVTS controller can connect up to 4 LVTS devices, and each LVTS device
can connect up to 7 TSMCUs.

The architecture will be the first to be used on mt6873 and mt8192.

Change in v7:
        - Fix coding style issues
        - Rewrite dt bindings
          - was not accurate
          - Use mt8195 for example (instead of mt8192)
          - Rename mt6873 to mt8192
          - Remove clock name
        - Rebased on top of to series:
          - https://patchwork.kernel.org/project/linux-mediatek/list/?series=637849
          - https://patchwork.kernel.org/project/linux-pm/list/?series=639386
Change in v6:
        - Remove temperature aggregation (it will be added in another series)
        - Update the way to read the temperature (read one sensor instead of all)
        - Add support of mt8195
Change in v5:
        - Use 'git mv' for the relocated file.

Change in v4:
        - Rebase to kernel-v5.13-rc1
        - Resend

Change in v3:
        - [2/3]
          - change the expression in the lvts_temp_to_raw to dev_s64.

Change in v2:
        - Rebase to kernel-5.11-rc1.
        - [2/3]
          - sort headers
          - remove initial value 0 of msr_raw in the lvts_temp_to_raw.
          - disconstruct the api of lvts_read_tc_msr_raw.
          - add the initial value max_temp = 0 and compare e.q.
            in the lvts_read_all_tc_temperature.
          - add the return with invalid number in the lvts_init.

This patch depends on [1], [2] and [3].

[1]https://patchwork.kernel.org/project/linux-mediatek/patch/20210524122053.17155-7-chun-jie.chen@mediatek.com/
[2]https://patchwork.kernel.org/project/linux-mediatek/list/?series=637849
[3]https://patchwork.kernel.org/project/linux-pm/list/?series=639386

Alexandre Bailon (2):
  dt-bindings: thermal: Add binding document for LVTS thermal
    controllers
  arm64: dts: mt8195: Add efuse node to mt8195

Michael Kao (3):
  thermal: mediatek: Relocate driver to mediatek folder
  thermal: mediatek: Add LVTS drivers for SoC theraml zones
  thermal: mediatek: Add thermal zone settings for mt8195

Tinghan Shen (1):
  arm64: dts: mt8195: Add thermal zone

 .../thermal/mediatek,mt8192-lvts.yaml         |   81 +
 arch/arm64/boot/dts/mediatek/mt8195.dtsi      |  121 ++
 drivers/thermal/Kconfig                       |   14 +-
 drivers/thermal/Makefile                      |    2 +-
 drivers/thermal/mediatek/Kconfig              |   33 +
 drivers/thermal/mediatek/Makefile             |    2 +
 .../{mtk_thermal.c => mediatek/soc_temp.c}    |    2 +-
 drivers/thermal/mediatek/soc_temp_lvts.c      | 1434 +++++++++++++++++
 drivers/thermal/mediatek/soc_temp_lvts.h      |  304 ++++
 9 files changed, 1981 insertions(+), 12 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
 create mode 100644 drivers/thermal/mediatek/Kconfig
 create mode 100644 drivers/thermal/mediatek/Makefile
 rename drivers/thermal/{mtk_thermal.c => mediatek/soc_temp.c} (99%)
 create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.c
 create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.h

Comments

Rob Herring May 26, 2022, 2:05 a.m. UTC | #1
On Tue, May 24, 2022 at 05:25:49PM +0200, Alexandre Bailon wrote:
> This patch adds binding document for mt8192 and mt8195 thermal
> controllers.
> 
> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
> ---
>  .../thermal/mediatek,mt8192-lvts.yaml         | 81 +++++++++++++++++++
>  1 file changed, 81 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
> 
> diff --git a/Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml b/Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
> new file mode 100644
> index 000000000000..914c877d1f2f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
> @@ -0,0 +1,81 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/thermal/mediatek,mt8192-lvts.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek SoC LVTS thermal controller
> +
> +maintainers:
> +  - Yu-Chia Chang <ethan.chang@mediatek.com>
> +  - Ben Tseng <ben.tseng@mediatek.com>
> +
> +allOf:
> +  - $ref: thermal-sensor.yaml#
> +  - $ref: /nvmem/nvmem-consumer.yaml#

Besides having an error, there is no need to reference this. It is 
applied to all nodes and you still have to list the properties here to 
define how many entries and what they are.

> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8192-lvts
> +      - mediatek,mt8195-lvts
> +
> +  reg:
> +    minItems: 2
> +    maxItems: 4
> +
> +  interrupts:
> +    maxItems: 2
> +
> +  clocks:
> +    maxItems: 1
> +
> +  "#thermal-sensor-cells":
> +    const: 1
> +
> +  nvmem-cells:
> +    maxItems: 2
> +    description: Calibration data for thermal sensors

Need to define what each entry is.

> +
> +  nvmem-cell-names:
> +    items:
> +      - const: e_data1
> +      - const: e_data2

Wow, those are useful names.

> +
> +  resets:
> +    $ref: /schemas/types.yaml#/definitions/phandle-array

Already has a type. Need to define how many entries and what each one is 
(if more than 1).

> +
> +
> +required:
> +  - '#thermal-sensor-cells'
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - nvmem-cells
> +  - nvmem-cell-names
> +  - resets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/thermal/thermal.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/clock/mt8195-clk.h>
> +    #include <dt-bindings/reset/mt8195-resets.h>
> +
> +    lvts: lvts@1100b000 {

Drop unused label.

thermal-sensor@...

> +        compatible = "mediatek,mt8195-lvts";
> +        #thermal-sensor-cells = <1>;
> +        reg = <0 0x1100b000 0 0x1000>,
> +              <0 0x11278000 0 0x1000>;
> +        interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH 0>,
> +                     <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>;
> +        clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
> +        resets = <&infracfg_ao MT8195_INFRA_RST0_THERM_CTRL_SWRST>,
> +                 <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>;
> +        nvmem-cells = <&lvts_e_data1 &lvts_e_data2>;
> +        nvmem-cell-names = "e_data1","e_data2";
> +    };
> +...
> -- 
> 2.35.1
> 
>
AngeloGioacchino Del Regno May 26, 2022, 12:58 p.m. UTC | #2
Il 24/05/22 17:25, Alexandre Bailon ha scritto:
> This patch adds binding document for mt8192 and mt8195 thermal
> controllers.
> 
> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
> ---
>   .../thermal/mediatek,mt8192-lvts.yaml         | 81 +++++++++++++++++++
>   1 file changed, 81 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
> 
> diff --git a/Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml b/Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
> new file mode 100644
> index 000000000000..914c877d1f2f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/mediatek,mt8192-lvts.yaml
> @@ -0,0 +1,81 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/thermal/mediatek,mt8192-lvts.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek SoC LVTS thermal controller
> +
> +maintainers:
> +  - Yu-Chia Chang <ethan.chang@mediatek.com>
> +  - Ben Tseng <ben.tseng@mediatek.com>
> +
> +allOf:
> +  - $ref: thermal-sensor.yaml#
> +  - $ref: /nvmem/nvmem-consumer.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8192-lvts
> +      - mediatek,mt8195-lvts
> +
> +  reg:
> +    minItems: 2
> +    maxItems: 4
> +
> +  interrupts:
> +    maxItems: 2
> +
> +  clocks:
> +    maxItems: 1
> +
> +  "#thermal-sensor-cells":
> +    const: 1
> +
> +  nvmem-cells:
> +    maxItems: 2
> +    description: Calibration data for thermal sensors
> +
> +  nvmem-cell-names:
> +    items:
> +      - const: e_data1
> +      - const: e_data2

 From what I understand, each nvmem cell has calibration data for each thermal
sensor, so let's use some more descriptive names...
some ideas: "lvts1-calib" "lvts1-cal" "calib1".

Also, I think that the best option is to register one driver instance for each
hardware instance, meaning that you should have only one reg, only one nvmem-cell,
only one reset, only one interrupt. This makes it possible to have as many
LVTS instances as possible without any code adjustments in the future.

An example for MT8195:

thermal-sensor@1100b000 {
	compatible = "mediatek,mt8195-lvts";
	reg = <0 0x1100b000 0 0x1000>;
	interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH 0>;
	#thermal-sensor-cells = <1>;
	clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
	nvmem-cells = <&lvts_e_data1>;
	nvmem-cell-names = "calibration";

	/* is this a reset for lvts1? */
	resets = <&infracfg_ao MT8195_INFRA_RST0_THERM_CTRL_SWRST>;
};

thermal-sensor@11278000 {
	compatible = "mediatek,mt8195-lvts";
	reg = <0 0x11278000 0 0x1000>;
	interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>;
	#thermal-sensor-cells = <1>;
	clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
	nvmem-cells = <&lvts_e_data2>;
	nvmem-cell-names = "calibration";

	/* is this a reset for lvts2? */
	resets = <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>;
};

In the future, a new MediaTek SoC may simply define more nodes..... :-)

> +
> +  resets:
> +    $ref: /schemas/types.yaml#/definitions/phandle-array
> +
> +
> +required:
> +  - '#thermal-sensor-cells'
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - nvmem-cells
> +  - nvmem-cell-names
> +  - resets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/thermal/thermal.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/clock/mt8195-clk.h>
> +    #include <dt-bindings/reset/mt8195-resets.h>
> +
> +    lvts: lvts@1100b000 {

Please use generic names: this should be thermal-sensor@1100b000

> +        compatible = "mediatek,mt8195-lvts";
> +        #thermal-sensor-cells = <1>;
> +        reg = <0 0x1100b000 0 0x1000>,
> +              <0 0x11278000 0 0x1000>;
> +        interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH 0>,
> +                     <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>;
> +        clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
> +        resets = <&infracfg_ao MT8195_INFRA_RST0_THERM_CTRL_SWRST>,
> +                 <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>;
> +        nvmem-cells = <&lvts_e_data1 &lvts_e_data2>;
> +        nvmem-cell-names = "e_data1","e_data2";
> +    };
> +...
AngeloGioacchino Del Regno May 26, 2022, 2:41 p.m. UTC | #3
Il 24/05/22 17:25, Alexandre Bailon ha scritto:
> From: Michael Kao <michael.kao@mediatek.com>
> 
> Add a LVTS (Low voltage thermal sensor) driver to report junction
> temperatures in Mediatek SoC and register the maximum temperature
> of sensors and each sensor as a thermal zone.
> 
> Signed-off-by: Yu-Chia Chang <ethan.chang@mediatek.com>
> Signed-off-by: Michael Kao <michael.kao@mediatek.com>
> Signed-off-by: Ben Tseng <ben.tseng@mediatek.com>
> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>

Hello Alexandre,
thanks for the patch! However, there are a few things to improve...

First, a very important issue to uncover:

The MediaTek SVS driver's iospace conflicts with this driver, at least
for the LVTS-1 instance:

SVS iospace:    0x1100bc00, length 0x400
LVTS-1 iospace: 0x1100b000, length 0x1000

The main issue resides in the fact that the SVS driver reads registers
before and after THERMINTST (but not THERMINTST itself), for now it's
only about INTST (at 0x1100bf08), but more are defined in that driver
and I really expect them to be used sooner or later.

There are multiple solutions to this, from defining two iospaces, where
one is start->svs, one is only including THERMINTST... or a syscon, but
the issue with this would be that we wouldn't be able to mix writel() and
writel_relaxed(), as regmap doesn't support this kind of mix (it's either
always or never relaxed).


Also, this driver should register only one LVTS sensor - and then register
(with the aid of devicetrees) multiple driver instances, one for each LVTS
sensor.... check my dt-bindings comment for that.

> ---
>   drivers/thermal/mediatek/Kconfig         |   10 +
>   drivers/thermal/mediatek/Makefile        |    1 +
>   drivers/thermal/mediatek/soc_temp.c      |    2 +-
>   drivers/thermal/mediatek/soc_temp_lvts.c | 1261 ++++++++++++++++++++++
>   drivers/thermal/mediatek/soc_temp_lvts.h |  304 ++++++
>   5 files changed, 1577 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.c
>   create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.h
> 
> diff --git a/drivers/thermal/mediatek/Kconfig b/drivers/thermal/mediatek/Kconfig
> index 592c849b9fed..4839aefeacb3 100644
> --- a/drivers/thermal/mediatek/Kconfig
> +++ b/drivers/thermal/mediatek/Kconfig
> @@ -20,4 +20,14 @@ config MTK_SOC_THERMAL
>   	  configures thermal controllers to collect temperature
>   	  via AUXADC interface.
>   
> +config MTK_SOC_THERMAL_LVTS
> +        tristate "LVTS (Low voltage thermal sensor) driver for Mediatek SoCs"
> +        depends on HAS_IOMEM
> +        depends on NVMEM
> +        depends on RESET_TI_SYSCON
> +        help
> +          Enable this option if you want to get SoC temperature
> +          information for MediaTek platforms. This driver
> +          configures LVTS thermal controllers to collect temperatures
> +          via Analog Serial Interface(ASIF).
>   endif
> diff --git a/drivers/thermal/mediatek/Makefile b/drivers/thermal/mediatek/Makefile
> index f75313ddce5e..16ce166e5916 100644
> --- a/drivers/thermal/mediatek/Makefile
> +++ b/drivers/thermal/mediatek/Makefile
> @@ -1 +1,2 @@
>   obj-$(CONFIG_MTK_SOC_THERMAL)	+= soc_temp.o
> +obj-$(CONFIG_MTK_SOC_THERMAL_LVTS)	+= soc_temp_lvts.o
> diff --git a/drivers/thermal/mediatek/soc_temp.c b/drivers/thermal/mediatek/soc_temp.c
> index 79d592f3f60d..4ed78bbadd62 100644
> --- a/drivers/thermal/mediatek/soc_temp.c
> +++ b/drivers/thermal/mediatek/soc_temp.c
> @@ -23,7 +23,7 @@
>   #include <linux/reset.h>
>   #include <linux/types.h>
>   
> -#include "thermal_hwmon.h"
> +#include "../thermal_hwmon.h"
>   
>   /* AUXADC Registers */
>   #define AUXADC_CON1_SET_V	0x008
> diff --git a/drivers/thermal/mediatek/soc_temp_lvts.c b/drivers/thermal/mediatek/soc_temp_lvts.c
> new file mode 100644
> index 000000000000..4b8c4c419f8e
> --- /dev/null
> +++ b/drivers/thermal/mediatek/soc_temp_lvts.c
> @@ -0,0 +1,1261 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/thermal.h>
> +#include "soc_temp_lvts.h"
> +
> +#define STOP_COUNTING_V4 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
> +#define SET_RG_TSFM_LPDLY_V4 (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
> +#define SET_COUNTING_WINDOW_20US1_V4 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
> +#define SET_COUNTING_WINDOW_20US2_V4 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20)
> +#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x84)
> +#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0x7C)
> +#define SET_TS_RSV_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D)
> +#define SET_TS_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4)
> +#define TOGGLE_RG_TSV2F_VCO_RST1_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xFC)
> +#define TOGGLE_RG_TSV2F_VCO_RST2_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4)
> +
> +#define SET_LVTS_AUTO_RCK_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x01)
> +#define SELECT_SENSOR_RCK_V4(id) (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id))
> +#define SET_DEVICE_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0x78)
> +#define KICK_OFF_RCK_COUNTING_V4 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02)
> +#define SET_SENSOR_NO_RCK_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10)
> +#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8	| 0xB8)


You can simplify these definitions a lot: you've got a lvts_write_device() helper
function that can .. help with that.
Drop DEVICE_WRITE from the definitions, add it to the lvts_write_device() function.

Also, from how I get it... DEVICE_WRITE or DEVICE_READ are definitions that will
set the required bits for I/O, and these are all in the first 16 bits of register
LVTS_CONFIG_0.... which seems to be a I/O wrapper for the various registers of the
controller.

At this point, I would do *at least* something like..

           In *soc_temp_lvts.h*:
/* register definitions */
#define SCK_ONLY		BIT(31) /* you missed this definition! */
#define DEVICE_ADDRESS		GENMASK(23, 18) /* device id for access */
#define READ_32BIT_ACCESS	BIT(17) /* ..and this one too */
#define DEVICE_REG_INDEX	GENMASK(15, 8) /* Register index */
#define DEVICE_REG_DATA		GENMASK(7, 0)  /* Data to write @ register */

/* helper macros */
#define DEVICE_ACCESS	(SCK_ONLY | CK26M_ACTIVE | DEVICE_ACCESS_START)
#define DEVICE_READ	(DEVICE_ACCESS | READ_32BIT_ACCESS)
#define DEVICE_WRITE	(DEVICE_ACCESS | READ_32BIT_ACCESS | WRITE_ACCESS)

         In * this file * :
#define GET_BASE_ADDR(lvts_data, tc)	<---- Don't enforce variable names!!!!!!!!

static void lvts_write_device(....)
{
	void __iomem *base = GET_BASE_ADDR(lvts_data, tc_id);

	writel(DEVICE_WRITE | data, base + LVTS_CONFIG_0);
}

...same for read_device.


*************** BUT! ***************

Since the register has DEVICE_REG_DATA in 7:0:
  1. Why are you hardcoding the data to write to these registers!?
  2. What is that data? I see only magic numbers, if something stops working, or
     doesn't work as expected, this driver is going to be a maintenance HELL...


> +
> +#define ENABLE_FEATURE(feature)		(lvts_data->feature_bitmap |= (feature))
> +#define DISABLE_FEATURE(feature)	(lvts_data->feature_bitmap &= (~(feature)))
> +#define IS_ENABLE(feature)		(lvts_data->feature_bitmap & (feature))

IS_ENABLE => HAS_FEATURE

> +
> +#define DISABLE_THERMAL_HW_REBOOT (-274000)
> +
> +#define CLOCK_26MHZ_CYCLE_NS	(38)
> +#define BUS_ACCESS_US		(2)
> +
> +#define FEATURE_DEVICE_AUTO_RCK	(BIT(0))
> +#define FEATURE_CK26M_ACTIVE	(BIT(1))
> +#define CK26M_ACTIVE   (((lvts_data->feature_bitmap & FEATURE_CK26M_ACTIVE)    \
> +			? 1 : 0) << 30)

Do *NOT* hardcode variable names in macros!!!!!! This means that all functions that
will use these macros *need to* have a variable with that name, and that it also
has to be the struct that you expect. Just NO!

> +#define GET_BASE_ADDR(tc_id)	\
> +	(lvts_data->domain[lvts_data->tc[tc_id].domain_index].base	\
> +	+ lvts_data->tc[tc_id].addr_offset)
> +

Do **NOT** hardcode variable names in macros!!!!!!

> +#define SET_TC_SPEED_IN_US(pu, gd, fd, sd) \
> +	{	\
> +		.period_unit = (((pu) * 1000) / (256 * CLOCK_26MHZ_CYCLE_NS)),	\
> +		.group_interval_delay = ((gd) / (pu)),	\
> +		.filter_interval_delay = ((fd) / (pu)),	\
> +		.sensor_interval_delay = ((sd) / (pu)),	\
> +	}
> +
> +#define GET_CAL_DATA_BITMASK(index, h, l)	\
> +	(((index) < lvts_data->num_efuse_addr)	\
> +	? ((lvts_data->efuse[(index)] & GENMASK(h, l)) >> l)	\
> +	: 0)
> +

Do ***NOT*** hardcode variable names in macros!!!!!!

> +#define GET_CAL_DATA_BIT(index, bit)	\
> +	(((index) < lvts_data->num_efuse_addr)	\
> +	? ((lvts_data->efuse[index] & BIT(bit)) >> (bit))	\
> +	: 0)
> +

Do ****NOT**** hardcode variable names in macros!!!!!!

> +#define GET_TC_SENSOR_NUM(tc_id)	\
> +	(lvts_data->tc[tc_id].num_sensor)
> +

Do... N.. :-)

> +#define ONE_SAMPLE (lvts_data->counting_window_us + 2 * BUS_ACCESS_US)
> +
> +#define NUM_OF_SAMPLE(tc_id)	\
> +	((lvts_data->tc[tc_id].hw_filter < LVTS_FILTER_2) ? 1 :	\
> +	((lvts_data->tc[tc_id].hw_filter > LVTS_FILTER_16_OF_18) ? 1 :	\
> +	((lvts_data->tc[tc_id].hw_filter == LVTS_FILTER_16_OF_18) ? 18 :\
> +	((lvts_data->tc[tc_id].hw_filter == LVTS_FILTER_8_OF_10) ? 10 :	\
> +	(lvts_data->tc[tc_id].hw_filter * 2)))))
> +
> +#define PERIOD_UNIT_US(tc_id)	\
> +	((lvts_data->tc[tc_id].tc_speed.period_unit * 256 *	\
> +	CLOCK_26MHZ_CYCLE_NS) / 1000)
> +#define FILTER_INT_US(tc_id)	\
> +	(lvts_data->tc[tc_id].tc_speed.filter_interval_delay	\
> +	* PERIOD_UNIT_US(tc_id))
> +#define SENSOR_INT_US(tc_id)	\
> +	(lvts_data->tc[tc_id].tc_speed.sensor_interval_delay	\
> +	* PERIOD_UNIT_US(tc_id))
> +#define GROUP_INT_US(tc_id)	\
> +	(lvts_data->tc[tc_id].tc_speed.group_interval_delay	\
> +	* PERIOD_UNIT_US(tc_id))
> +
> +#define SENSOR_LATENCY_US(tc_id) \
> +	((NUM_OF_SAMPLE(tc_id) - 1) * FILTER_INT_US(tc_id)	\
> +	+ NUM_OF_SAMPLE(tc_id) * ONE_SAMPLE)
> +
> +#define GROUP_LATENCY_US(tc_id)	\
> +	(GET_TC_SENSOR_NUM(tc_id) * SENSOR_LATENCY_US(tc_id)	\
> +	+ (GET_TC_SENSOR_NUM(tc_id) - 1) * SENSOR_INT_US(tc_id)	\
> +	+ GROUP_INT_US(tc_id))
> +
> +static int lvts_raw_to_temp(struct formula_coeff *co, unsigned int msr_raw)
> +{
> +	/* This function returns degree mC */
> +
> +	int temp;
> +
> +	temp = (co->a * ((unsigned long long)msr_raw)) >> 14;
> +	temp = temp + co->golden_temp * 500 + co->b;
> +
> +	return temp;
> +}
> +
> +static unsigned int lvts_temp_to_raw(struct formula_coeff *co, int temp)
> +{
> +	unsigned int msr_raw;
> +
> +	msr_raw = div_s64((s64)((co->golden_temp * 500 + co->b - temp)) << 14,
> +			 (-1 * co->a));
> +
> +	return msr_raw;
> +}
> +
> +static int soc_temp_lvts_read_temp(void *data, int *temperature)
> +{
> +	struct soc_temp_tz *lvts_tz = (struct soc_temp_tz *)data;
> +	struct lvts_data *lvts_data = lvts_tz->lvts_data;
> +	unsigned int msr_raw;
> +
> +	msr_raw = readl(lvts_data->reg[lvts_tz->id]) & MRS_RAW_MASK;
> +	if (msr_raw == 0)
> +		return -EINVAL;
> +
> +	*temperature = lvts_raw_to_temp(&lvts_data->coeff, msr_raw);
> +
> +	return 0;
> +}
> +
> +static const struct thermal_zone_of_device_ops soc_temp_lvts_ops = {
> +	.get_temp = soc_temp_lvts_read_temp,
> +};
> +
> +static void lvts_write_device(struct lvts_data *lvts_data, unsigned int data,
> +			      int tc_id)
> +{
> +	void __iomem *base;
> +
> +	base = GET_BASE_ADDR(tc_id);
> +
> +	writel(data, LVTS_CONFIG_0 + base);
> +
> +	usleep_range(5, 15);
> +}
> +
> +static unsigned int lvts_read_device(struct lvts_data *lvts_data,
> +				     unsigned int reg_idx, int tc_id)
> +{
> +	struct device *dev = lvts_data->dev;
> +	void __iomem *base;
> +	unsigned int data;
> +	int ret;
> +
> +	base = GET_BASE_ADDR(tc_id);
> +	writel(READ_DEVICE_REG(reg_idx), LVTS_CONFIG_0 + base);
> +
> +	ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data,
> +				 !(data & DEVICE_ACCESS_STARTUS),
> +				 2, 200);
> +	if (ret)
> +		dev_err(dev,
> +			"Error: LVTS %d DEVICE_ACCESS_START didn't ready\n", tc_id);
> +
> +	data = readl(LVTSRDATA0_0 + base);
> +
> +	return data;
> +}
> +
> +static void wait_all_tc_sensing_point_idle(struct lvts_data *lvts_data)
> +{
> +	struct device *dev = lvts_data->dev;
> +	unsigned int mask, error_code, is_error;
> +	void __iomem *base;
> +	int i, cnt, ret;
> +
> +	mask = BIT(10) | BIT(7) | BIT(0);
> +
> +	for (cnt = 0; cnt < 2; cnt++) {
> +		is_error = 0;
> +		for (i = 0; i < lvts_data->num_tc; i++) {
> +			base = GET_BASE_ADDR(i);
> +			ret = readl_poll_timeout(LVTSMSRCTL1_0 + base, error_code,
> +						 !(error_code & mask), 2, 200);
> +			/*
> +			 * Error code
> +			 * 000: IDLE
> +			 * 001: Write transaction
> +			 * 010: Waiting for read after Write
> +			 * 011: Disable Continue fetching on Device
> +			 * 100: Read transaction
> +			 * 101: Set Device special Register for Voltage threshold
> +			 * 111: Set TSMCU number for Fetch
> +			 */

enum lvts_error_codes {
	IDLE = 0,
	ERR_WR_TRANSACTION,
	ERR_DEV_CNTFETCH_DIS,
	ERR_RD_TRANSACTION,
	......
};

static const char * const lvts_error_table[] = all error codes in strings here.


> +			error_code = ((error_code & BIT(10)) >> 8) +
> +				((error_code & BIT(7)) >> 6) +
> +				(error_code & BIT(0));
> +
> +			if (ret)
> +				dev_err(dev,
> +					"Error LVTS %d sensing points aren't idle, error_code %d\n",
> +					i, error_code);

				dev_err(dev, "LVTS %d error: %s\n",
					lvts_error_table[error_code]);

... that works better.

> +
> +			if (error_code != 0)
> +				is_error = 1;
> +		}
> +
> +		if (is_error == 0)
> +			break;
> +	}
> +}
> +


..snip..

> +
> +static void set_hw_filter(struct lvts_data *lvts_data, int tc_id)
> +{
> +	struct device *dev = lvts_data->dev;
> +	const struct tc_settings *tc = lvts_data->tc;
> +	unsigned int option;
> +	void __iomem *base;
> +
> +	base = GET_BASE_ADDR(tc_id);
> +	option = tc[tc_id].hw_filter & 0x7;
> +	/*
> +	 * hw filter
> +	 * 000: Get one sample
> +	 * 001: Get 2 samples and average them
> +	 * 010: Get 4 samples, drop max and min, then average the rest of 2 samples
> +	 * 011: Get 6 samples, drop max and min, then average the rest of 4 samples
> +	 * 100: Get 10 samples, drop max and min, then average the rest of 8 samples
> +	 * 101: Get 18 samples, drop max and min, then average the rest of 16 samples
> +	 */
> +	option = (option << 9) | (option << 6) | (option << 3) | option;
> +
> +	writel(option, LVTSMSRCTL0_0 + base);
> +	dev_info(dev, "%s %d, LVTSMSRCTL0_0= 0x%x\n",
> +		 __func__, tc_id, readl(LVTSMSRCTL0_0 + base));


That's not an informative message, it's for debugging purposes, so that's a
dev_dbg().

> +}
> +

..snip..


> +
> +static int prepare_calibration_data(struct lvts_data *lvts_data)
> +{
> +	struct device *dev = lvts_data->dev;
> +	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
> +	struct platform_ops *ops = &lvts_data->ops;
> +	int i, offset, size;
> +	char buffer[512];
> +
> +	cal_data->count_r = devm_kcalloc(dev, lvts_data->num_sensor,
> +					 sizeof(*cal_data->count_r), GFP_KERNEL);
> +	if (!cal_data->count_r)
> +		return -ENOMEM;
> +
> +	cal_data->count_rc = devm_kcalloc(dev, lvts_data->num_sensor,
> +					  sizeof(*cal_data->count_rc), GFP_KERNEL);
> +	if (!cal_data->count_rc)
> +		return -ENOMEM;
> +
> +	if (ops->efuse_to_cal_data)
> +		ops->efuse_to_cal_data(lvts_data);
> +
> +	cal_data->use_fake_efuse = 1;
> +	if (cal_data->golden_temp != 0) {
> +		cal_data->use_fake_efuse = 0;
> +	} else {
> +		for (i = 0; i < lvts_data->num_sensor; i++) {
> +			if (cal_data->count_r[i] != 0 ||
> +			    cal_data->count_rc[i] != 0) {
> +				cal_data->use_fake_efuse = 0;
> +				break;
> +			}
> +		}
> +	}
> +
> +	if (cal_data->use_fake_efuse) {
> +		/* It means all efuse data are equal to 0 */
> +		dev_err(dev,
> +			"[lvts_cal] This sample is not calibrated, fake !!\n");
> +
> +		cal_data->golden_temp = cal_data->default_golden_temp;
> +		for (i = 0; i < lvts_data->num_sensor; i++) {
> +			cal_data->count_r[i] = cal_data->default_count_r;
> +			cal_data->count_rc[i] = cal_data->default_count_rc;
> +		}
> +	}
> +
> +	lvts_data->coeff.golden_temp = cal_data->golden_temp;
> +
> +	dev_info(dev, "[lvts_cal] golden_temp = %d\n", cal_data->golden_temp);

This is dev_dbg() again... please recheck all prints and use the appropriate
level.

> +
> +	size = sizeof(buffer);
> +	offset = snprintf(buffer, size, "[lvts_cal] num:g_count:g_count_rc ");
> +	for (i = 0; i < lvts_data->num_sensor; i++)
> +		offset += snprintf(buffer + offset, size - offset, "%d:%d:%d ",
> +				   i, cal_data->count_r[i], cal_data->count_rc[i]);
> +
> +	buffer[offset] = '\0';
> +	dev_info(dev, "%s\n", buffer);

...and this is very annoying to see: if you want this kind of debugging, use
debugfs.

> +
> +	return 0;
> +}
> +

..snip..

> +static irqreturn_t irq_handler(int irq, void *dev_id)
> +{
> +	struct lvts_data *lvts_data = (struct lvts_data *)dev_id;
> +	struct device *dev = lvts_data->dev;
> +	const struct tc_settings *tc = lvts_data->tc;
> +	unsigned int i, *irq_bitmap;
> +	void __iomem *base;
> +
> +	irq_bitmap = kcalloc(lvts_data->num_domain, sizeof(*irq_bitmap), GFP_ATOMIC);
> +
> +	if (!irq_bitmap)
> +		return IRQ_NONE;
> +
> +	for (i = 0; i < lvts_data->num_domain; i++) {
> +		base = lvts_data->domain[i].base;
> +		irq_bitmap[i] = readl(THERMINTST + base);
> +		dev_info(dev, "%s : THERMINTST = 0x%x\n", __func__, irq_bitmap[i]);
> +	}
> +
> +	for (i = 0; i < lvts_data->num_tc; i++) {
> +		if ((irq_bitmap[tc[i].domain_index] & tc[i].irq_bit) == 0)
> +			tc_irq_handler(lvts_data, i);
> +	}
> +
> +	kfree(irq_bitmap);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int lvts_register_irq_handler(struct lvts_data *lvts_data)
> +{
> +	struct device *dev = lvts_data->dev;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < lvts_data->num_domain; i++) {
> +		ret = devm_request_irq(dev, lvts_data->domain[i].irq_num, irq_handler,
> +				       IRQF_TRIGGER_HIGH, "mtk_lvts", lvts_data);
> +
> +		if (ret) {
> +			dev_err(dev, "Failed to register LVTS IRQ, ret %d, domain %d irq_num %d\n",
> +				ret, i, lvts_data->domain[i].irq_num);
> +			lvts_close(lvts_data);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int lvts_register_thermal_zones(struct lvts_data *lvts_data)
> +{
> +	struct device *dev = lvts_data->dev;
> +	struct thermal_zone *tzdev;
> +	struct soc_temp_tz *lvts_tz;
> +	int i, ret;
> +
> +	for (i = 0; i < lvts_data->num_sensor; i++) {
> +		lvts_tz = devm_kzalloc(dev, sizeof(*lvts_tz), GFP_KERNEL);
> +		if (!lvts_tz) {
> +			lvts_close(lvts_data);
> +			return -ENOMEM;
> +		}
> +
> +		lvts_tz->id = i;
> +		lvts_tz->lvts_data = lvts_data;
> +
> +		tzdev = devm_thermal_zone_of_sensor_register(dev, lvts_tz->id,
> +							     lvts_tz, &soc_temp_lvts_ops);
> +
> +		if (IS_ERR(tzdev)) {
> +			if (lvts_tz->id != 0)
> +				return 0;
> +
> +			ret = PTR_ERR(tzdev);
> +			dev_err(dev, "Error: Failed to register lvts tz %d, ret = %d\n",
> +				lvts_tz->id, ret);
> +			lvts_close(lvts_data);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int lvts_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct lvts_data *lvts_data;
> +	int ret;
> +
> +	lvts_data = (struct lvts_data *)of_device_get_match_data(dev);
> +
> +	if (!lvts_data)	{
> +		dev_err(dev, "Error: Failed to get lvts platform data\n");
> +		return -ENODATA;
> +	}
> +
> +	lvts_data->dev = &pdev->dev;
> +
> +	ret = of_update_lvts_data(lvts_data, pdev);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, lvts_data);
> +
> +	ret = lvts_init(lvts_data);
> +	if (ret)
> +		return ret;
> +
> +	ret = lvts_register_irq_handler(lvts_data);
> +	if (ret)
> +		return ret;
> +
> +	ret = lvts_register_thermal_zones(lvts_data);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int lvts_remove(struct platform_device *pdev)
> +{
> +	struct lvts_data *lvts_data;
> +
> +	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
> +
> +	lvts_close(lvts_data);
> +
> +	return 0;
> +}
> +
> +static int lvts_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct lvts_data *lvts_data;
> +
> +	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
> +
> +	lvts_close(lvts_data);
> +
> +	return 0;
> +}
> +
> +static int lvts_resume(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct lvts_data *lvts_data;
> +
> +	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
> +
> +	ret = lvts_init(lvts_data);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void device_enable_and_init_v4(struct lvts_data *lvts_data)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < lvts_data->num_tc; i++) {
> +		lvts_write_device(lvts_data, STOP_COUNTING_V4, i);
> +		lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V4, i);
> +		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V4, i);
> +		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V4, i);
> +		lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4, i);
> +		lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4, i);
> +		lvts_write_device(lvts_data, SET_TS_RSV_V4, i);
> +		lvts_write_device(lvts_data, SET_TS_EN_V4, i);
> +		lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST1_V4, i);
> +		lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST2_V4, i);
> +	}
> +
> +	lvts_data->counting_window_us = 20;
> +}
> +
> +static void device_enable_auto_rck_v4(struct lvts_data *lvts_data)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < lvts_data->num_tc; i++)
> +		lvts_write_device(lvts_data, SET_LVTS_AUTO_RCK_V4, i);
> +}
> +
> +static int device_read_count_rc_n_v4(struct lvts_data *lvts_data)
> +{
> +	/* Resistor-Capacitor Calibration */
> +	/* count_RC_N: count RC now */
> +	struct device *dev = lvts_data->dev;
> +	const struct tc_settings *tc = lvts_data->tc;
> +	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
> +	unsigned int offset, size, s_index, data;
> +	void __iomem *base;
> +	int ret, i, j;
> +	char buffer[512];
> +
> +	cal_data->count_rc_now = devm_kcalloc(dev, lvts_data->num_sensor,
> +					      sizeof(*cal_data->count_rc_now), GFP_KERNEL);
> +	if (!cal_data->count_rc_now)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < lvts_data->num_tc; i++) {
> +		base = GET_BASE_ADDR(i);
> +		for (j = 0; j < tc[i].num_sensor; j++) {
> +			s_index = tc[i].sensor_map[j];
> +
> +			lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V4(j), i);
> +			lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V4, i);
> +			usleep_range(10, 20);
> +
> +			lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V4, i);
> +			usleep_range(30, 40);
> +
> +			ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data,
> +						 !(data & DEVICE_SENSING_STATUS), 2, 200);
> +			if (ret)
> +				dev_err(dev,
> +					"Error: LVTS %d DEVICE_SENSING_STATUS didn't ready\n", i);
> +
> +			data = lvts_read_device(lvts_data, 0x00, i);
> +
> +			cal_data->count_rc_now[s_index] = (data & GENMASK(23, 0));
> +		}
> +
> +		/* Recover Setting for Normal Access on
> +		 * temperature fetch
> +		 */
> +		lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V4, i);
> +		lvts_write_device(lvts_data, SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i);
> +	}
> +
> +	size = sizeof(buffer);
> +	offset = snprintf(buffer, size, "[COUNT_RC_NOW] ");
> +	for (i = 0; i < lvts_data->num_sensor; i++)
> +		offset += snprintf(buffer + offset, size - offset, "%d:%d ",
> +				   i, cal_data->count_rc_now[i]);
> +
> +	buffer[offset] = '\0';
> +	dev_info(dev, "%s\n", buffer);
> +
> +	return 0;
> +}
> +
> +static void set_calibration_data_v4(struct lvts_data *lvts_data)
> +{
> +	const struct tc_settings *tc = lvts_data->tc;
> +	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
> +	unsigned int i, j, s_index, e_data;
> +	void __iomem *base;
> +
> +	for (i = 0; i < lvts_data->num_tc; i++) {
> +		base = GET_BASE_ADDR(i);
> +
> +		for (j = 0; j < tc[i].num_sensor; j++) {
> +			s_index = tc[i].sensor_map[j];
> +			if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK))
> +				e_data = cal_data->count_r[s_index];
> +			else
> +				e_data = (((unsigned long long)
> +					cal_data->count_rc_now[s_index]) *
> +					cal_data->count_r[s_index]) >> 14;
> +
> +			writel(e_data, LVTSEDATA00_0 + base + 0x4 * j);
> +		}
> +	}
> +}
> +
> +static void init_controller_v4(struct lvts_data *lvts_data)
> +{
> +	struct device *dev = lvts_data->dev;
> +	unsigned int i;
> +	void __iomem *base;
> +
> +	for (i = 0; i < lvts_data->num_tc; i++) {
> +		base = GET_BASE_ADDR(i);
> +
> +		lvts_write_device(lvts_data, SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i);
> +
> +		writel(SET_SENSOR_INDEX, LVTSTSSEL_0 + base);
> +		writel(SET_CALC_SCALE_RULES, LVTSCALSCALE_0 + base);
> +
> +		set_polling_speed(lvts_data, i);
> +		set_hw_filter(lvts_data, i);
> +
> +		dev_info(dev, "lvts%d: read all %d sensors in %d us, one in %d us\n",
> +			 i, GET_TC_SENSOR_NUM(i), GROUP_LATENCY_US(i), SENSOR_LATENCY_US(i));
> +	}
> +}
> +
> +#define MT8192_NUM_LVTS (ARRAY_SIZE(mt8192_tc_settings))
> +

You don't need this definition.

> +enum mt8192_lvts_domain {
> +	MT8192_AP_DOMAIN,
> +	MT8192_MCU_DOMAIN,
> +	MT8192_NUM_DOMAIN
> +};
> +
> +enum mt8192_lvts_sensor_enum {
> +	MT8192_TS1_0,
> +	MT8192_TS1_1,
> +	MT8192_TS2_0,
> +	MT8192_TS2_1,
> +	MT8192_TS3_0,
> +	MT8192_TS3_1,
> +	MT8192_TS3_2,
> +	MT8192_TS3_3,
> +	MT8192_TS4_0,
> +	MT8192_TS4_1,
> +	MT8192_TS5_0,
> +	MT8192_TS5_1,
> +	MT8192_TS6_0,
> +	MT8192_TS6_1,
> +	MT8192_TS7_0,
> +	MT8192_TS7_1,
> +	MT8192_TS7_2,
> +	MT8192_NUM_TS
> +};
> +
> +static void mt8192_efuse_to_cal_data(struct lvts_data *lvts_data)
> +{
> +	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
> +
> +	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
> +	cal_data->count_r[MT8192_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0);
> +	cal_data->count_r[MT8192_TS1_1] = GET_CAL_DATA_BITMASK(2, 23, 0);
> +	cal_data->count_r[MT8192_TS2_0] = GET_CAL_DATA_BITMASK(3, 23, 0);
> +	cal_data->count_r[MT8192_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0);
> +	cal_data->count_r[MT8192_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0);
> +	cal_data->count_r[MT8192_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0);
> +	cal_data->count_r[MT8192_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
> +	cal_data->count_r[MT8192_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0);
> +	cal_data->count_r[MT8192_TS4_0] = GET_CAL_DATA_BITMASK(9, 23, 0);
> +	cal_data->count_r[MT8192_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0);
> +	cal_data->count_r[MT8192_TS5_0] = GET_CAL_DATA_BITMASK(11, 23, 0);
> +	cal_data->count_r[MT8192_TS5_1] = GET_CAL_DATA_BITMASK(12, 23, 0);
> +	cal_data->count_r[MT8192_TS6_0] = GET_CAL_DATA_BITMASK(13, 23, 0);
> +	cal_data->count_r[MT8192_TS6_1] = GET_CAL_DATA_BITMASK(14, 23, 0);
> +	cal_data->count_r[MT8192_TS7_0] = GET_CAL_DATA_BITMASK(15, 23, 0);
> +	cal_data->count_r[MT8192_TS7_1] = GET_CAL_DATA_BITMASK(16, 23, 0);
> +	cal_data->count_r[MT8192_TS7_2] = GET_CAL_DATA_BITMASK(17, 23, 0);

A for loop is definitely appropriate here..

> +
> +	cal_data->count_rc[MT8192_TS1_0] = GET_CAL_DATA_BITMASK(21, 23, 0);

Here it's not...

> +
> +	cal_data->count_rc[MT8192_TS2_0] = (GET_CAL_DATA_BITMASK(1, 31, 24) << 16) +
> +					   (GET_CAL_DATA_BITMASK(2, 31, 24) << 8) +
> +					    GET_CAL_DATA_BITMASK(3, 31, 24);
> +
> +	cal_data->count_rc[MT8192_TS3_0] = (GET_CAL_DATA_BITMASK(4, 31, 24) << 16) +
> +					   (GET_CAL_DATA_BITMASK(5, 31, 24) << 8) +
> +					    GET_CAL_DATA_BITMASK(6, 31, 24);
> +
> +	cal_data->count_rc[MT8192_TS4_0] = (GET_CAL_DATA_BITMASK(7, 31, 24) << 16) +
> +					   (GET_CAL_DATA_BITMASK(8, 31, 24) << 8) +
> +					    GET_CAL_DATA_BITMASK(9, 31, 24);
> +
> +	cal_data->count_rc[MT8192_TS5_0] = (GET_CAL_DATA_BITMASK(10, 31, 24) << 16) +
> +					   (GET_CAL_DATA_BITMASK(11, 31, 24) << 8) +
> +					    GET_CAL_DATA_BITMASK(12, 31, 24);
> +
> +	cal_data->count_rc[MT8192_TS6_0] = (GET_CAL_DATA_BITMASK(13, 31, 24) << 16) +
> +					   (GET_CAL_DATA_BITMASK(14, 31, 24) << 8) +
> +					    GET_CAL_DATA_BITMASK(15, 31, 24);
> +
> +	cal_data->count_rc[MT8192_TS7_0] = (GET_CAL_DATA_BITMASK(16, 31, 24) << 16) +
> +					   (GET_CAL_DATA_BITMASK(17, 31, 24) << 8) +
> +					    GET_CAL_DATA_BITMASK(18, 31, 24);

Here it's appropriate again, and like that, you won't need to use this odd macro
anymore.

> +}
> +
> +static const struct tc_settings mt8192_tc_settings[] = {
> +	[0] = {
> +		.domain_index = MT8192_MCU_DOMAIN,
> +		.addr_offset = 0x0,
> +		.num_sensor = 2,
> +		.sensor_map = {MT8192_TS1_0, MT8192_TS1_1},
> +		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),

That tc_speed is a no-go... change it to a pointer and then...

static const struct tc_settings tc_speed_mt8192 = {
	.period_unit = 12,
	.group_interval_delay = 1,
	.filter_interval_delay = 1,
	.sensor_interval_delay = 1,
};

		.tc_speed = &tc_speed_mt8192,

> +		.hw_filter = LVTS_FILTER_2_OF_4,
> +		.dominator_sensing_point = SENSING_POINT1,
> +		.hw_reboot_trip_point = 117000,
> +		.irq_bit = BIT(3),
> +	},

..snip..

> +
> +static const struct lvts_data mt8192_lvts_data = {
> +	.num_domain = MT8192_NUM_DOMAIN,
> +	.num_tc = MT8192_NUM_LVTS,
> +	.tc = mt8192_tc_settings,
> +	.num_sensor = MT8192_NUM_TS,
> +	.ops = {
> +		.efuse_to_cal_data = mt8192_efuse_to_cal_data,
> +		.device_enable_and_init = device_enable_and_init_v4,
> +		.device_enable_auto_rck = device_enable_auto_rck_v4,
> +		.device_read_count_rc_n = device_read_count_rc_n_v4,
> +		.set_cal_data = set_calibration_data_v4,
> +		.init_controller = init_controller_v4,
> +	},
> +	.feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
> +	.num_efuse_addr = 22,
> +	.num_efuse_block = 1,
> +	.cal_data = {
> +		.default_golden_temp = 50,
> +		.default_count_r = 35000,
> +		.default_count_rc = 2750,
> +	},
> +	.coeff = {
> +		.a = -250460,
> +		.b = 250460,
> +	},
> +};
> +
> +static const struct of_device_id lvts_of_match[] = {
> +	{
> +		.compatible = "mediatek,mt8192-lvts",
> +		.data = (void *)&mt8192_lvts_data,

You don't need a cast to void pointer... also, this fits in one line.

> +	},
> +	{
> +	},
> +};
> +MODULE_DEVICE_TABLE(of, lvts_of_match);
> +
> +static struct platform_driver soc_temp_lvts = {
> +	.probe = lvts_probe,
> +	.remove = lvts_remove,
> +	.suspend = lvts_suspend,
> +	.resume = lvts_resume,
> +	.driver = {
> +		.name = "mtk-soc-temp-lvts",
> +		.of_match_table = lvts_of_match,
> +	},
> +};
> +
> +module_platform_driver(soc_temp_lvts);
> +MODULE_AUTHOR("Yu-Chia Chang <ethan.chang@mediatek.com>");
> +MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
> +MODULE_DESCRIPTION("MediaTek soc temperature driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/thermal/mediatek/soc_temp_lvts.h b/drivers/thermal/mediatek/soc_temp_lvts.h
> new file mode 100644
> index 000000000000..8fc0d114b8d0
> --- /dev/null
> +++ b/drivers/thermal/mediatek/soc_temp_lvts.h
> @@ -0,0 +1,304 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
> + */
> +
> +#ifndef __MTK_SOC_TEMP_LVTS_H__
> +#define __MTK_SOC_TEMP_LVTS_H__
> +
> +/*
> + * LVTS HW filter settings
> + * 000: Get one sample
> + * 001: Get 2 samples and average them
> + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples
> + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples
> + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples
> + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples
> + */
> +enum lvts_hw_filter {
> +	LVTS_FILTER_1,
> +	LVTS_FILTER_2,
> +	LVTS_FILTER_2_OF_4,
> +	LVTS_FILTER_4_OF_6,
> +	LVTS_FILTER_8_OF_10,
> +	LVTS_FILTER_16_OF_18
> +};
> +
> +enum lvts_sensing_point {
> +	SENSING_POINT0,
> +	SENSING_POINT1,
> +	SENSING_POINT2,
> +	SENSING_POINT3,
> +	ALL_SENSING_POINTS
> +};
> +
> +struct lvts_data;
> +

Add documentation to this struct that explains how to calculate the params:

/**
  * struct speed_settings - blah description
  * @period_unit: ....
  * @all the vars...
  *
  * Calculation is achieved with the following equations:
  * For the period unit: (period_us * 1000) / (256 * clock_26mhz_cycle_ns)
  * For the interval delays: delay / period_us
  */

> +struct speed_settings {
> +	unsigned int period_unit;
> +	unsigned int group_interval_delay;
> +	unsigned int filter_interval_delay;
> +	unsigned int sensor_interval_delay;
> +};
> +
> +struct tc_settings {
> +	unsigned int domain_index;
> +	unsigned int addr_offset;
> +	unsigned int num_sensor;
> +	unsigned int sensor_map[ALL_SENSING_POINTS]; /* In sensor ID */
> +	struct speed_settings tc_speed;

tc_speed becomes a pointer... :)

Regards,
Angelo
AngeloGioacchino Del Regno May 26, 2022, 2:42 p.m. UTC | #4
Il 24/05/22 17:25, Alexandre Bailon ha scritto:
> This adds the efuse node. This will be required by the thermal driver
> to get the calibration data.
> 
> Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
> ---
>   arch/arm64/boot/dts/mediatek/mt8195.dtsi | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
> index 0011a8ba8f96..51443e83d906 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
> @@ -1238,6 +1238,23 @@ nor_flash: spi@1132c000 {
>   			status = "disabled";
>   		};
>   
> +		efuse: efuse@11c10000 {
> +			compatible = "mediatek,efuse";
> +			reg = <0 0x11c10000 0 0x1000>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +
> +			lvts_e_data1: data1 {

lvts1-calib@1bc

> +				reg = <0x1bc 0x14>;
> +			};
> +			lvts_e_data2: data1-1 {

lvts2-calib@1d0

> +				reg = <0x1d0 0x38>;
> +			};
> +			svs_calibration: calib@580 {
> +				reg = <0x580 0x64>;
> +			};
> +		};
> +
>   		u3phy2: t-phy@11c40000 {
>   			compatible = "mediatek,mt8195-tphy", "mediatek,generic-tphy-v3";
>   			#address-cells = <1>;