1f5f633b1SBalsam CHIHI // SPDX-License-Identifier: GPL-2.0-only
2f5f633b1SBalsam CHIHI /*
3f5f633b1SBalsam CHIHI * Copyright (c) 2023 MediaTek Inc.
4f5f633b1SBalsam CHIHI * Author: Balsam CHIHI <bchihi@baylibre.com>
5f5f633b1SBalsam CHIHI */
6f5f633b1SBalsam CHIHI
7f5f633b1SBalsam CHIHI #include <linux/clk.h>
8f5f633b1SBalsam CHIHI #include <linux/clk-provider.h>
9f5f633b1SBalsam CHIHI #include <linux/delay.h>
10f5f633b1SBalsam CHIHI #include <linux/debugfs.h>
11f5f633b1SBalsam CHIHI #include <linux/init.h>
12f5f633b1SBalsam CHIHI #include <linux/interrupt.h>
13f5f633b1SBalsam CHIHI #include <linux/iopoll.h>
14f5f633b1SBalsam CHIHI #include <linux/kernel.h>
15f5f633b1SBalsam CHIHI #include <linux/nvmem-consumer.h>
16f6a756e8SRob Herring #include <linux/of.h>
17f5f633b1SBalsam CHIHI #include <linux/platform_device.h>
18f5f633b1SBalsam CHIHI #include <linux/reset.h>
19f5f633b1SBalsam CHIHI #include <linux/thermal.h>
20f5f633b1SBalsam CHIHI #include <dt-bindings/thermal/mediatek,lvts-thermal.h>
21f5f633b1SBalsam CHIHI
2251c8e119SChen-Yu Tsai #include "../thermal_hwmon.h"
2351c8e119SChen-Yu Tsai
24f5f633b1SBalsam CHIHI #define LVTS_MONCTL0(__base) (__base + 0x0000)
25f5f633b1SBalsam CHIHI #define LVTS_MONCTL1(__base) (__base + 0x0004)
26f5f633b1SBalsam CHIHI #define LVTS_MONCTL2(__base) (__base + 0x0008)
27f5f633b1SBalsam CHIHI #define LVTS_MONINT(__base) (__base + 0x000C)
28f5f633b1SBalsam CHIHI #define LVTS_MONINTSTS(__base) (__base + 0x0010)
29f5f633b1SBalsam CHIHI #define LVTS_MONIDET0(__base) (__base + 0x0014)
30f5f633b1SBalsam CHIHI #define LVTS_MONIDET1(__base) (__base + 0x0018)
31f5f633b1SBalsam CHIHI #define LVTS_MONIDET2(__base) (__base + 0x001C)
32f5f633b1SBalsam CHIHI #define LVTS_MONIDET3(__base) (__base + 0x0020)
33f5f633b1SBalsam CHIHI #define LVTS_H2NTHRE(__base) (__base + 0x0024)
34f5f633b1SBalsam CHIHI #define LVTS_HTHRE(__base) (__base + 0x0028)
35f5f633b1SBalsam CHIHI #define LVTS_OFFSETH(__base) (__base + 0x0030)
36f5f633b1SBalsam CHIHI #define LVTS_OFFSETL(__base) (__base + 0x0034)
37f5f633b1SBalsam CHIHI #define LVTS_MSRCTL0(__base) (__base + 0x0038)
38f5f633b1SBalsam CHIHI #define LVTS_MSRCTL1(__base) (__base + 0x003C)
39f5f633b1SBalsam CHIHI #define LVTS_TSSEL(__base) (__base + 0x0040)
40f5f633b1SBalsam CHIHI #define LVTS_CALSCALE(__base) (__base + 0x0048)
41f5f633b1SBalsam CHIHI #define LVTS_ID(__base) (__base + 0x004C)
42f5f633b1SBalsam CHIHI #define LVTS_CONFIG(__base) (__base + 0x0050)
43f5f633b1SBalsam CHIHI #define LVTS_EDATA00(__base) (__base + 0x0054)
44f5f633b1SBalsam CHIHI #define LVTS_EDATA01(__base) (__base + 0x0058)
45f5f633b1SBalsam CHIHI #define LVTS_EDATA02(__base) (__base + 0x005C)
46f5f633b1SBalsam CHIHI #define LVTS_EDATA03(__base) (__base + 0x0060)
47f5f633b1SBalsam CHIHI #define LVTS_MSR0(__base) (__base + 0x0090)
48f5f633b1SBalsam CHIHI #define LVTS_MSR1(__base) (__base + 0x0094)
49f5f633b1SBalsam CHIHI #define LVTS_MSR2(__base) (__base + 0x0098)
50f5f633b1SBalsam CHIHI #define LVTS_MSR3(__base) (__base + 0x009C)
51f5f633b1SBalsam CHIHI #define LVTS_IMMD0(__base) (__base + 0x00A0)
52f5f633b1SBalsam CHIHI #define LVTS_IMMD1(__base) (__base + 0x00A4)
53f5f633b1SBalsam CHIHI #define LVTS_IMMD2(__base) (__base + 0x00A8)
54f5f633b1SBalsam CHIHI #define LVTS_IMMD3(__base) (__base + 0x00AC)
55f5f633b1SBalsam CHIHI #define LVTS_PROTCTL(__base) (__base + 0x00C0)
56f5f633b1SBalsam CHIHI #define LVTS_PROTTA(__base) (__base + 0x00C4)
57f5f633b1SBalsam CHIHI #define LVTS_PROTTB(__base) (__base + 0x00C8)
58f5f633b1SBalsam CHIHI #define LVTS_PROTTC(__base) (__base + 0x00CC)
59f5f633b1SBalsam CHIHI #define LVTS_CLKEN(__base) (__base + 0x00E4)
60f5f633b1SBalsam CHIHI
61185673caSNícolas F. R. A. Prado #define LVTS_PERIOD_UNIT 0
62185673caSNícolas F. R. A. Prado #define LVTS_GROUP_INTERVAL 0
63185673caSNícolas F. R. A. Prado #define LVTS_FILTER_INTERVAL 0
64185673caSNícolas F. R. A. Prado #define LVTS_SENSOR_INTERVAL 0
65185673caSNícolas F. R. A. Prado #define LVTS_HW_FILTER 0x0
66f5f633b1SBalsam CHIHI #define LVTS_TSSEL_CONF 0x13121110
67f5f633b1SBalsam CHIHI #define LVTS_CALSCALE_CONF 0x300
68487bf099SNícolas F. R. A. Prado #define LVTS_MONINT_CONF 0x8300318C
69f5f633b1SBalsam CHIHI
702bba1acfSNícolas F. R. A. Prado #define LVTS_MONINT_OFFSET_SENSOR0 0xC
712bba1acfSNícolas F. R. A. Prado #define LVTS_MONINT_OFFSET_SENSOR1 0x180
722bba1acfSNícolas F. R. A. Prado #define LVTS_MONINT_OFFSET_SENSOR2 0x3000
732bba1acfSNícolas F. R. A. Prado #define LVTS_MONINT_OFFSET_SENSOR3 0x3000000
742bba1acfSNícolas F. R. A. Prado
75f5f633b1SBalsam CHIHI #define LVTS_INT_SENSOR0 0x0009001F
7613f03bcdSChen-Yu Tsai #define LVTS_INT_SENSOR1 0x001203E0
77f5f633b1SBalsam CHIHI #define LVTS_INT_SENSOR2 0x00247C00
78f5f633b1SBalsam CHIHI #define LVTS_INT_SENSOR3 0x1FC00000
79f5f633b1SBalsam CHIHI
80f5f633b1SBalsam CHIHI #define LVTS_SENSOR_MAX 4
81f5f633b1SBalsam CHIHI #define LVTS_GOLDEN_TEMP_MAX 62
82f5f633b1SBalsam CHIHI #define LVTS_GOLDEN_TEMP_DEFAULT 50
83f5f633b1SBalsam CHIHI #define LVTS_COEFF_A -250460
84f5f633b1SBalsam CHIHI #define LVTS_COEFF_B 250460
85f5f633b1SBalsam CHIHI
86f5f633b1SBalsam CHIHI #define LVTS_MSR_IMMEDIATE_MODE 0
87f5f633b1SBalsam CHIHI #define LVTS_MSR_FILTERED_MODE 1
88f5f633b1SBalsam CHIHI
89185673caSNícolas F. R. A. Prado #define LVTS_MSR_READ_TIMEOUT_US 400
90185673caSNícolas F. R. A. Prado #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
91185673caSNícolas F. R. A. Prado
92f5f633b1SBalsam CHIHI #define LVTS_HW_SHUTDOWN_MT8195 105000
93f5f633b1SBalsam CHIHI
9477354eaeSNícolas F. R. A. Prado #define LVTS_MINIMUM_THRESHOLD 20000
9577354eaeSNícolas F. R. A. Prado
96f5f633b1SBalsam CHIHI static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
97f5f633b1SBalsam CHIHI static int coeff_b = LVTS_COEFF_B;
98f5f633b1SBalsam CHIHI
99f5f633b1SBalsam CHIHI struct lvts_sensor_data {
100f5f633b1SBalsam CHIHI int dt_id;
101f5f633b1SBalsam CHIHI };
102f5f633b1SBalsam CHIHI
103f5f633b1SBalsam CHIHI struct lvts_ctrl_data {
104f5f633b1SBalsam CHIHI struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
105f5f633b1SBalsam CHIHI int cal_offset[LVTS_SENSOR_MAX];
106f5f633b1SBalsam CHIHI int hw_tshut_temp;
107f5f633b1SBalsam CHIHI int num_lvts_sensor;
108f5f633b1SBalsam CHIHI int offset;
109f5f633b1SBalsam CHIHI int mode;
110f5f633b1SBalsam CHIHI };
111f5f633b1SBalsam CHIHI
112f5f633b1SBalsam CHIHI struct lvts_data {
113f5f633b1SBalsam CHIHI const struct lvts_ctrl_data *lvts_ctrl;
114f5f633b1SBalsam CHIHI int num_lvts_ctrl;
115f5f633b1SBalsam CHIHI };
116f5f633b1SBalsam CHIHI
117f5f633b1SBalsam CHIHI struct lvts_sensor {
118f5f633b1SBalsam CHIHI struct thermal_zone_device *tz;
119f5f633b1SBalsam CHIHI void __iomem *msr;
120f5f633b1SBalsam CHIHI void __iomem *base;
121f5f633b1SBalsam CHIHI int id;
122f5f633b1SBalsam CHIHI int dt_id;
1232bba1acfSNícolas F. R. A. Prado int low_thresh;
1242bba1acfSNícolas F. R. A. Prado int high_thresh;
125f5f633b1SBalsam CHIHI };
126f5f633b1SBalsam CHIHI
127f5f633b1SBalsam CHIHI struct lvts_ctrl {
128f5f633b1SBalsam CHIHI struct lvts_sensor sensors[LVTS_SENSOR_MAX];
129f5f633b1SBalsam CHIHI u32 calibration[LVTS_SENSOR_MAX];
130f5f633b1SBalsam CHIHI u32 hw_tshut_raw_temp;
131f5f633b1SBalsam CHIHI int num_lvts_sensor;
132f5f633b1SBalsam CHIHI int mode;
133f5f633b1SBalsam CHIHI void __iomem *base;
1342bba1acfSNícolas F. R. A. Prado int low_thresh;
1352bba1acfSNícolas F. R. A. Prado int high_thresh;
136f5f633b1SBalsam CHIHI };
137f5f633b1SBalsam CHIHI
138f5f633b1SBalsam CHIHI struct lvts_domain {
139f5f633b1SBalsam CHIHI struct lvts_ctrl *lvts_ctrl;
140f5f633b1SBalsam CHIHI struct reset_control *reset;
141f5f633b1SBalsam CHIHI struct clk *clk;
142f5f633b1SBalsam CHIHI int num_lvts_ctrl;
143f5f633b1SBalsam CHIHI void __iomem *base;
144f5f633b1SBalsam CHIHI size_t calib_len;
145f5f633b1SBalsam CHIHI u8 *calib;
146f5f633b1SBalsam CHIHI #ifdef CONFIG_DEBUG_FS
147f5f633b1SBalsam CHIHI struct dentry *dom_dentry;
148f5f633b1SBalsam CHIHI #endif
149f5f633b1SBalsam CHIHI };
150f5f633b1SBalsam CHIHI
151f5f633b1SBalsam CHIHI #ifdef CONFIG_MTK_LVTS_THERMAL_DEBUGFS
152f5f633b1SBalsam CHIHI
153f5f633b1SBalsam CHIHI #define LVTS_DEBUG_FS_REGS(__reg) \
154f5f633b1SBalsam CHIHI { \
155f5f633b1SBalsam CHIHI .name = __stringify(__reg), \
156f5f633b1SBalsam CHIHI .offset = __reg(0), \
157f5f633b1SBalsam CHIHI }
158f5f633b1SBalsam CHIHI
159f5f633b1SBalsam CHIHI static const struct debugfs_reg32 lvts_regs[] = {
160f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONCTL0),
161f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONCTL1),
162f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONCTL2),
163f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONINT),
164f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONINTSTS),
165f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONIDET0),
166f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONIDET1),
167f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONIDET2),
168f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MONIDET3),
169f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_H2NTHRE),
170f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_HTHRE),
171f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_OFFSETH),
172f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_OFFSETL),
173f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MSRCTL0),
174f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MSRCTL1),
175f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_TSSEL),
176f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_CALSCALE),
177f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_ID),
178f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_CONFIG),
179f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_EDATA00),
180f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_EDATA01),
181f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_EDATA02),
182f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_EDATA03),
183f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MSR0),
184f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MSR1),
185f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MSR2),
186f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_MSR3),
187f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_IMMD0),
188f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_IMMD1),
189f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_IMMD2),
190f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_IMMD3),
191f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_PROTCTL),
192f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_PROTTA),
193f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_PROTTB),
194f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_PROTTC),
195f5f633b1SBalsam CHIHI LVTS_DEBUG_FS_REGS(LVTS_CLKEN),
196f5f633b1SBalsam CHIHI };
197f5f633b1SBalsam CHIHI
lvts_debugfs_init(struct device * dev,struct lvts_domain * lvts_td)198f5f633b1SBalsam CHIHI static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
199f5f633b1SBalsam CHIHI {
200f5f633b1SBalsam CHIHI struct debugfs_regset32 *regset;
201f5f633b1SBalsam CHIHI struct lvts_ctrl *lvts_ctrl;
202f5f633b1SBalsam CHIHI struct dentry *dentry;
203f5f633b1SBalsam CHIHI char name[64];
204f5f633b1SBalsam CHIHI int i;
205f5f633b1SBalsam CHIHI
206f5f633b1SBalsam CHIHI lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL);
20719ad9f29SMinjie Du if (IS_ERR(lvts_td->dom_dentry))
208f5f633b1SBalsam CHIHI return 0;
209f5f633b1SBalsam CHIHI
210f5f633b1SBalsam CHIHI for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
211f5f633b1SBalsam CHIHI
212f5f633b1SBalsam CHIHI lvts_ctrl = &lvts_td->lvts_ctrl[i];
213f5f633b1SBalsam CHIHI
214f5f633b1SBalsam CHIHI sprintf(name, "controller%d", i);
215f5f633b1SBalsam CHIHI dentry = debugfs_create_dir(name, lvts_td->dom_dentry);
216f5f633b1SBalsam CHIHI if (!dentry)
217f5f633b1SBalsam CHIHI continue;
218f5f633b1SBalsam CHIHI
219f5f633b1SBalsam CHIHI regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
220f5f633b1SBalsam CHIHI if (!regset)
221f5f633b1SBalsam CHIHI continue;
222f5f633b1SBalsam CHIHI
223f5f633b1SBalsam CHIHI regset->base = lvts_ctrl->base;
224f5f633b1SBalsam CHIHI regset->regs = lvts_regs;
225f5f633b1SBalsam CHIHI regset->nregs = ARRAY_SIZE(lvts_regs);
226f5f633b1SBalsam CHIHI
227f5f633b1SBalsam CHIHI debugfs_create_regset32("registers", 0400, dentry, regset);
228f5f633b1SBalsam CHIHI }
229f5f633b1SBalsam CHIHI
230f5f633b1SBalsam CHIHI return 0;
231f5f633b1SBalsam CHIHI }
232f5f633b1SBalsam CHIHI
lvts_debugfs_exit(struct lvts_domain * lvts_td)233f5f633b1SBalsam CHIHI static void lvts_debugfs_exit(struct lvts_domain *lvts_td)
234f5f633b1SBalsam CHIHI {
235f5f633b1SBalsam CHIHI debugfs_remove_recursive(lvts_td->dom_dentry);
236f5f633b1SBalsam CHIHI }
237f5f633b1SBalsam CHIHI
238f5f633b1SBalsam CHIHI #else
239f5f633b1SBalsam CHIHI
lvts_debugfs_init(struct device * dev,struct lvts_domain * lvts_td)240f5f633b1SBalsam CHIHI static inline int lvts_debugfs_init(struct device *dev,
241f5f633b1SBalsam CHIHI struct lvts_domain *lvts_td)
242f5f633b1SBalsam CHIHI {
243f5f633b1SBalsam CHIHI return 0;
244f5f633b1SBalsam CHIHI }
245f5f633b1SBalsam CHIHI
lvts_debugfs_exit(struct lvts_domain * lvts_td)246f5f633b1SBalsam CHIHI static void lvts_debugfs_exit(struct lvts_domain *lvts_td) { }
247f5f633b1SBalsam CHIHI
248f5f633b1SBalsam CHIHI #endif
249f5f633b1SBalsam CHIHI
lvts_raw_to_temp(u32 raw_temp)250f5f633b1SBalsam CHIHI static int lvts_raw_to_temp(u32 raw_temp)
251f5f633b1SBalsam CHIHI {
252f5f633b1SBalsam CHIHI int temperature;
253f5f633b1SBalsam CHIHI
254f5f633b1SBalsam CHIHI temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14;
255f5f633b1SBalsam CHIHI temperature += coeff_b;
256f5f633b1SBalsam CHIHI
257f5f633b1SBalsam CHIHI return temperature;
258f5f633b1SBalsam CHIHI }
259f5f633b1SBalsam CHIHI
lvts_temp_to_raw(int temperature)260f5f633b1SBalsam CHIHI static u32 lvts_temp_to_raw(int temperature)
261f5f633b1SBalsam CHIHI {
262f5f633b1SBalsam CHIHI u32 raw_temp = ((s64)(coeff_b - temperature)) << 14;
263f5f633b1SBalsam CHIHI
264f5f633b1SBalsam CHIHI raw_temp = div_s64(raw_temp, -LVTS_COEFF_A);
265f5f633b1SBalsam CHIHI
266f5f633b1SBalsam CHIHI return raw_temp;
267f5f633b1SBalsam CHIHI }
268f5f633b1SBalsam CHIHI
lvts_get_temp(struct thermal_zone_device * tz,int * temp)269f5f633b1SBalsam CHIHI static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
270f5f633b1SBalsam CHIHI {
2715f68d078SDaniel Lezcano struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
272f5f633b1SBalsam CHIHI void __iomem *msr = lvts_sensor->msr;
273f5f633b1SBalsam CHIHI u32 value;
274185673caSNícolas F. R. A. Prado int rc;
275f5f633b1SBalsam CHIHI
276f5f633b1SBalsam CHIHI /*
277f5f633b1SBalsam CHIHI * Measurement registers:
278f5f633b1SBalsam CHIHI *
279f5f633b1SBalsam CHIHI * LVTS_MSR[0-3] / LVTS_IMMD[0-3]
280f5f633b1SBalsam CHIHI *
281f5f633b1SBalsam CHIHI * Bits:
282f5f633b1SBalsam CHIHI *
283f5f633b1SBalsam CHIHI * 32-17: Unused
284f5f633b1SBalsam CHIHI * 16 : Valid temperature
285f5f633b1SBalsam CHIHI * 15-0 : Raw temperature
286f5f633b1SBalsam CHIHI */
287185673caSNícolas F. R. A. Prado rc = readl_poll_timeout(msr, value, value & BIT(16),
288185673caSNícolas F. R. A. Prado LVTS_MSR_READ_WAIT_US, LVTS_MSR_READ_TIMEOUT_US);
289f5f633b1SBalsam CHIHI
290f5f633b1SBalsam CHIHI /*
291f5f633b1SBalsam CHIHI * As the thermal zone temperature will read before the
292f5f633b1SBalsam CHIHI * hardware sensor is fully initialized, we have to check the
293f5f633b1SBalsam CHIHI * validity of the temperature returned when reading the
294f5f633b1SBalsam CHIHI * measurement register. The thermal controller will set the
295f5f633b1SBalsam CHIHI * valid bit temperature only when it is totally initialized.
296f5f633b1SBalsam CHIHI *
297f5f633b1SBalsam CHIHI * Otherwise, we may end up with garbage values out of the
298f5f633b1SBalsam CHIHI * functionning temperature and directly jump to a system
299f5f633b1SBalsam CHIHI * shutdown.
300f5f633b1SBalsam CHIHI */
301185673caSNícolas F. R. A. Prado if (rc)
302f5f633b1SBalsam CHIHI return -EAGAIN;
303f5f633b1SBalsam CHIHI
304f5f633b1SBalsam CHIHI *temp = lvts_raw_to_temp(value & 0xFFFF);
305f5f633b1SBalsam CHIHI
306f5f633b1SBalsam CHIHI return 0;
307f5f633b1SBalsam CHIHI }
308f5f633b1SBalsam CHIHI
lvts_update_irq_mask(struct lvts_ctrl * lvts_ctrl)3092bba1acfSNícolas F. R. A. Prado static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl)
3102bba1acfSNícolas F. R. A. Prado {
3112bba1acfSNícolas F. R. A. Prado u32 masks[] = {
3122bba1acfSNícolas F. R. A. Prado LVTS_MONINT_OFFSET_SENSOR0,
3132bba1acfSNícolas F. R. A. Prado LVTS_MONINT_OFFSET_SENSOR1,
3142bba1acfSNícolas F. R. A. Prado LVTS_MONINT_OFFSET_SENSOR2,
3152bba1acfSNícolas F. R. A. Prado LVTS_MONINT_OFFSET_SENSOR3,
3162bba1acfSNícolas F. R. A. Prado };
3172bba1acfSNícolas F. R. A. Prado u32 value = 0;
3182bba1acfSNícolas F. R. A. Prado int i;
3192bba1acfSNícolas F. R. A. Prado
3202bba1acfSNícolas F. R. A. Prado value = readl(LVTS_MONINT(lvts_ctrl->base));
3212bba1acfSNícolas F. R. A. Prado
3222bba1acfSNícolas F. R. A. Prado for (i = 0; i < ARRAY_SIZE(masks); i++) {
3232bba1acfSNícolas F. R. A. Prado if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
3242bba1acfSNícolas F. R. A. Prado && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
3252bba1acfSNícolas F. R. A. Prado value |= masks[i];
3262bba1acfSNícolas F. R. A. Prado else
3272bba1acfSNícolas F. R. A. Prado value &= ~masks[i];
3282bba1acfSNícolas F. R. A. Prado }
3292bba1acfSNícolas F. R. A. Prado
3302bba1acfSNícolas F. R. A. Prado writel(value, LVTS_MONINT(lvts_ctrl->base));
3312bba1acfSNícolas F. R. A. Prado }
3322bba1acfSNícolas F. R. A. Prado
lvts_should_update_thresh(struct lvts_ctrl * lvts_ctrl,int high)3332bba1acfSNícolas F. R. A. Prado static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high)
3342bba1acfSNícolas F. R. A. Prado {
3352bba1acfSNícolas F. R. A. Prado int i;
3362bba1acfSNícolas F. R. A. Prado
3372bba1acfSNícolas F. R. A. Prado if (high > lvts_ctrl->high_thresh)
3382bba1acfSNícolas F. R. A. Prado return true;
3392bba1acfSNícolas F. R. A. Prado
3402bba1acfSNícolas F. R. A. Prado for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++)
3412bba1acfSNícolas F. R. A. Prado if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
3422bba1acfSNícolas F. R. A. Prado && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
3432bba1acfSNícolas F. R. A. Prado return false;
3442bba1acfSNícolas F. R. A. Prado
3452bba1acfSNícolas F. R. A. Prado return true;
3462bba1acfSNícolas F. R. A. Prado }
3472bba1acfSNícolas F. R. A. Prado
lvts_set_trips(struct thermal_zone_device * tz,int low,int high)348f5f633b1SBalsam CHIHI static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
349f5f633b1SBalsam CHIHI {
3505f68d078SDaniel Lezcano struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
3512bba1acfSNícolas F. R. A. Prado struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
352f5f633b1SBalsam CHIHI void __iomem *base = lvts_sensor->base;
35377354eaeSNícolas F. R. A. Prado u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
354f5f633b1SBalsam CHIHI u32 raw_high = lvts_temp_to_raw(high);
3552bba1acfSNícolas F. R. A. Prado bool should_update_thresh;
3562bba1acfSNícolas F. R. A. Prado
3572bba1acfSNícolas F. R. A. Prado lvts_sensor->low_thresh = low;
3582bba1acfSNícolas F. R. A. Prado lvts_sensor->high_thresh = high;
3592bba1acfSNícolas F. R. A. Prado
3602bba1acfSNícolas F. R. A. Prado should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high);
3612bba1acfSNícolas F. R. A. Prado if (should_update_thresh) {
3622bba1acfSNícolas F. R. A. Prado lvts_ctrl->high_thresh = high;
3632bba1acfSNícolas F. R. A. Prado lvts_ctrl->low_thresh = low;
3642bba1acfSNícolas F. R. A. Prado }
3652bba1acfSNícolas F. R. A. Prado lvts_update_irq_mask(lvts_ctrl);
3662bba1acfSNícolas F. R. A. Prado
3672bba1acfSNícolas F. R. A. Prado if (!should_update_thresh)
3682bba1acfSNícolas F. R. A. Prado return 0;
369f5f633b1SBalsam CHIHI
370f5f633b1SBalsam CHIHI /*
371f79e996cSNícolas F. R. A. Prado * Low offset temperature threshold
372f5f633b1SBalsam CHIHI *
373f79e996cSNícolas F. R. A. Prado * LVTS_OFFSETL
374f5f633b1SBalsam CHIHI *
375f5f633b1SBalsam CHIHI * Bits:
376f5f633b1SBalsam CHIHI *
377f5f633b1SBalsam CHIHI * 14-0 : Raw temperature for threshold
378f5f633b1SBalsam CHIHI */
379dbb0ea15SDaniel Lezcano pr_debug("%s: Setting low limit temperature interrupt: %d\n",
380dbb0ea15SDaniel Lezcano thermal_zone_device_type(tz), low);
381f79e996cSNícolas F. R. A. Prado writel(raw_low, LVTS_OFFSETL(base));
382f5f633b1SBalsam CHIHI
383f5f633b1SBalsam CHIHI /*
384f79e996cSNícolas F. R. A. Prado * High offset temperature threshold
385f5f633b1SBalsam CHIHI *
386f79e996cSNícolas F. R. A. Prado * LVTS_OFFSETH
387f5f633b1SBalsam CHIHI *
388f5f633b1SBalsam CHIHI * Bits:
389f5f633b1SBalsam CHIHI *
390f5f633b1SBalsam CHIHI * 14-0 : Raw temperature for threshold
391f5f633b1SBalsam CHIHI */
392dbb0ea15SDaniel Lezcano pr_debug("%s: Setting high limit temperature interrupt: %d\n",
393dbb0ea15SDaniel Lezcano thermal_zone_device_type(tz), high);
394f79e996cSNícolas F. R. A. Prado writel(raw_high, LVTS_OFFSETH(base));
395f5f633b1SBalsam CHIHI
396f5f633b1SBalsam CHIHI return 0;
397f5f633b1SBalsam CHIHI }
398f5f633b1SBalsam CHIHI
lvts_ctrl_irq_handler(struct lvts_ctrl * lvts_ctrl)399f5f633b1SBalsam CHIHI static irqreturn_t lvts_ctrl_irq_handler(struct lvts_ctrl *lvts_ctrl)
400f5f633b1SBalsam CHIHI {
401f5f633b1SBalsam CHIHI irqreturn_t iret = IRQ_NONE;
402f5f633b1SBalsam CHIHI u32 value;
403f5f633b1SBalsam CHIHI u32 masks[] = {
404f5f633b1SBalsam CHIHI LVTS_INT_SENSOR0,
405f5f633b1SBalsam CHIHI LVTS_INT_SENSOR1,
406f5f633b1SBalsam CHIHI LVTS_INT_SENSOR2,
407f5f633b1SBalsam CHIHI LVTS_INT_SENSOR3
408f5f633b1SBalsam CHIHI };
409f5f633b1SBalsam CHIHI int i;
410f5f633b1SBalsam CHIHI
411f5f633b1SBalsam CHIHI /*
412f5f633b1SBalsam CHIHI * Interrupt monitoring status
413f5f633b1SBalsam CHIHI *
414f5f633b1SBalsam CHIHI * LVTS_MONINTST
415f5f633b1SBalsam CHIHI *
416f5f633b1SBalsam CHIHI * Bits:
417f5f633b1SBalsam CHIHI *
418f5f633b1SBalsam CHIHI * 31 : Interrupt for stage 3
419f5f633b1SBalsam CHIHI * 30 : Interrupt for stage 2
420f5f633b1SBalsam CHIHI * 29 : Interrupt for state 1
421f5f633b1SBalsam CHIHI * 28 : Interrupt using filter on sensor 3
422f5f633b1SBalsam CHIHI *
423f5f633b1SBalsam CHIHI * 27 : Interrupt using immediate on sensor 3
424f5f633b1SBalsam CHIHI * 26 : Interrupt normal to hot on sensor 3
425f5f633b1SBalsam CHIHI * 25 : Interrupt high offset on sensor 3
426f5f633b1SBalsam CHIHI * 24 : Interrupt low offset on sensor 3
427f5f633b1SBalsam CHIHI *
428f5f633b1SBalsam CHIHI * 23 : Interrupt hot threshold on sensor 3
429f5f633b1SBalsam CHIHI * 22 : Interrupt cold threshold on sensor 3
430f5f633b1SBalsam CHIHI * 21 : Interrupt using filter on sensor 2
431f5f633b1SBalsam CHIHI * 20 : Interrupt using filter on sensor 1
432f5f633b1SBalsam CHIHI *
433f5f633b1SBalsam CHIHI * 19 : Interrupt using filter on sensor 0
434f5f633b1SBalsam CHIHI * 18 : Interrupt using immediate on sensor 2
435f5f633b1SBalsam CHIHI * 17 : Interrupt using immediate on sensor 1
436f5f633b1SBalsam CHIHI * 16 : Interrupt using immediate on sensor 0
437f5f633b1SBalsam CHIHI *
438f5f633b1SBalsam CHIHI * 15 : Interrupt device access timeout interrupt
439f5f633b1SBalsam CHIHI * 14 : Interrupt normal to hot on sensor 2
440f5f633b1SBalsam CHIHI * 13 : Interrupt high offset interrupt on sensor 2
441f5f633b1SBalsam CHIHI * 12 : Interrupt low offset interrupt on sensor 2
442f5f633b1SBalsam CHIHI *
443f5f633b1SBalsam CHIHI * 11 : Interrupt hot threshold on sensor 2
444f5f633b1SBalsam CHIHI * 10 : Interrupt cold threshold on sensor 2
445f5f633b1SBalsam CHIHI * 9 : Interrupt normal to hot on sensor 1
446f5f633b1SBalsam CHIHI * 8 : Interrupt high offset interrupt on sensor 1
447f5f633b1SBalsam CHIHI *
448f5f633b1SBalsam CHIHI * 7 : Interrupt low offset interrupt on sensor 1
449f5f633b1SBalsam CHIHI * 6 : Interrupt hot threshold on sensor 1
450f5f633b1SBalsam CHIHI * 5 : Interrupt cold threshold on sensor 1
451f5f633b1SBalsam CHIHI * 4 : Interrupt normal to hot on sensor 0
452f5f633b1SBalsam CHIHI *
453f5f633b1SBalsam CHIHI * 3 : Interrupt high offset interrupt on sensor 0
454f5f633b1SBalsam CHIHI * 2 : Interrupt low offset interrupt on sensor 0
455f5f633b1SBalsam CHIHI * 1 : Interrupt hot threshold on sensor 0
456f5f633b1SBalsam CHIHI * 0 : Interrupt cold threshold on sensor 0
457f5f633b1SBalsam CHIHI *
458f5f633b1SBalsam CHIHI * We are interested in the sensor(s) responsible of the
459f5f633b1SBalsam CHIHI * interrupt event. We update the thermal framework with the
460f5f633b1SBalsam CHIHI * thermal zone associated with the sensor. The framework will
461f5f633b1SBalsam CHIHI * take care of the rest whatever the kind of interrupt, we
462f5f633b1SBalsam CHIHI * are only interested in which sensor raised the interrupt.
463f5f633b1SBalsam CHIHI *
464f5f633b1SBalsam CHIHI * sensor 3 interrupt: 0001 1111 1100 0000 0000 0000 0000 0000
465f5f633b1SBalsam CHIHI * => 0x1FC00000
466f5f633b1SBalsam CHIHI * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000
467f5f633b1SBalsam CHIHI * => 0x00247C00
46813f03bcdSChen-Yu Tsai * sensor 1 interrupt: 0000 0000 0001 0010 0000 0011 1110 0000
46913f03bcdSChen-Yu Tsai * => 0X001203E0
470f5f633b1SBalsam CHIHI * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111
471f5f633b1SBalsam CHIHI * => 0x0009001F
472f5f633b1SBalsam CHIHI */
473f5f633b1SBalsam CHIHI value = readl(LVTS_MONINTSTS(lvts_ctrl->base));
474f5f633b1SBalsam CHIHI
475f5f633b1SBalsam CHIHI /*
476f5f633b1SBalsam CHIHI * Let's figure out which sensors raised the interrupt
477f5f633b1SBalsam CHIHI *
478f5f633b1SBalsam CHIHI * NOTE: the masks array must be ordered with the index
479f5f633b1SBalsam CHIHI * corresponding to the sensor id eg. index=0, mask for
480f5f633b1SBalsam CHIHI * sensor0.
481f5f633b1SBalsam CHIHI */
482f5f633b1SBalsam CHIHI for (i = 0; i < ARRAY_SIZE(masks); i++) {
483f5f633b1SBalsam CHIHI
484f5f633b1SBalsam CHIHI if (!(value & masks[i]))
485f5f633b1SBalsam CHIHI continue;
486f5f633b1SBalsam CHIHI
487f5f633b1SBalsam CHIHI thermal_zone_device_update(lvts_ctrl->sensors[i].tz,
488f5f633b1SBalsam CHIHI THERMAL_TRIP_VIOLATED);
489f5f633b1SBalsam CHIHI iret = IRQ_HANDLED;
490f5f633b1SBalsam CHIHI }
491f5f633b1SBalsam CHIHI
492f5f633b1SBalsam CHIHI /*
493f5f633b1SBalsam CHIHI * Write back to clear the interrupt status (W1C)
494f5f633b1SBalsam CHIHI */
495f5f633b1SBalsam CHIHI writel(value, LVTS_MONINTSTS(lvts_ctrl->base));
496f5f633b1SBalsam CHIHI
497f5f633b1SBalsam CHIHI return iret;
498f5f633b1SBalsam CHIHI }
499f5f633b1SBalsam CHIHI
500f5f633b1SBalsam CHIHI /*
501f5f633b1SBalsam CHIHI * Temperature interrupt handler. Even if the driver supports more
502f5f633b1SBalsam CHIHI * interrupt modes, we use the interrupt when the temperature crosses
503f5f633b1SBalsam CHIHI * the hot threshold the way up and the way down (modulo the
504f5f633b1SBalsam CHIHI * hysteresis).
505f5f633b1SBalsam CHIHI *
506f5f633b1SBalsam CHIHI * Each thermal domain has a couple of interrupts, one for hardware
507f5f633b1SBalsam CHIHI * reset and another one for all the thermal events happening on the
508f5f633b1SBalsam CHIHI * different sensors.
509f5f633b1SBalsam CHIHI *
510f5f633b1SBalsam CHIHI * The interrupt is configured for thermal events when crossing the
511f5f633b1SBalsam CHIHI * hot temperature limit. At each interrupt, we check in every
512f5f633b1SBalsam CHIHI * controller if there is an interrupt pending.
513f5f633b1SBalsam CHIHI */
lvts_irq_handler(int irq,void * data)514f5f633b1SBalsam CHIHI static irqreturn_t lvts_irq_handler(int irq, void *data)
515f5f633b1SBalsam CHIHI {
516f5f633b1SBalsam CHIHI struct lvts_domain *lvts_td = data;
517f5f633b1SBalsam CHIHI irqreturn_t aux, iret = IRQ_NONE;
518f5f633b1SBalsam CHIHI int i;
519f5f633b1SBalsam CHIHI
520f5f633b1SBalsam CHIHI for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
521f5f633b1SBalsam CHIHI
522cbd8c5aaSNícolas F. R. A. Prado aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]);
523f5f633b1SBalsam CHIHI if (aux != IRQ_HANDLED)
524f5f633b1SBalsam CHIHI continue;
525f5f633b1SBalsam CHIHI
526f5f633b1SBalsam CHIHI iret = IRQ_HANDLED;
527f5f633b1SBalsam CHIHI }
528f5f633b1SBalsam CHIHI
529f5f633b1SBalsam CHIHI return iret;
530f5f633b1SBalsam CHIHI }
531f5f633b1SBalsam CHIHI
532f5f633b1SBalsam CHIHI static struct thermal_zone_device_ops lvts_ops = {
533f5f633b1SBalsam CHIHI .get_temp = lvts_get_temp,
534f5f633b1SBalsam CHIHI .set_trips = lvts_set_trips,
535f5f633b1SBalsam CHIHI };
536f5f633b1SBalsam CHIHI
lvts_sensor_init(struct device * dev,struct lvts_ctrl * lvts_ctrl,const struct lvts_ctrl_data * lvts_ctrl_data)537f5f633b1SBalsam CHIHI static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
538f5f633b1SBalsam CHIHI const struct lvts_ctrl_data *lvts_ctrl_data)
539f5f633b1SBalsam CHIHI {
540f5f633b1SBalsam CHIHI struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors;
541f5f633b1SBalsam CHIHI void __iomem *msr_regs[] = {
542f5f633b1SBalsam CHIHI LVTS_MSR0(lvts_ctrl->base),
543f5f633b1SBalsam CHIHI LVTS_MSR1(lvts_ctrl->base),
544f5f633b1SBalsam CHIHI LVTS_MSR2(lvts_ctrl->base),
545f5f633b1SBalsam CHIHI LVTS_MSR3(lvts_ctrl->base)
546f5f633b1SBalsam CHIHI };
547f5f633b1SBalsam CHIHI
548f5f633b1SBalsam CHIHI void __iomem *imm_regs[] = {
549f5f633b1SBalsam CHIHI LVTS_IMMD0(lvts_ctrl->base),
550f5f633b1SBalsam CHIHI LVTS_IMMD1(lvts_ctrl->base),
551f5f633b1SBalsam CHIHI LVTS_IMMD2(lvts_ctrl->base),
552f5f633b1SBalsam CHIHI LVTS_IMMD3(lvts_ctrl->base)
553f5f633b1SBalsam CHIHI };
554f5f633b1SBalsam CHIHI
555f5f633b1SBalsam CHIHI int i;
556f5f633b1SBalsam CHIHI
557f5f633b1SBalsam CHIHI for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) {
558f5f633b1SBalsam CHIHI
559f5f633b1SBalsam CHIHI int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id;
560f5f633b1SBalsam CHIHI
561f5f633b1SBalsam CHIHI /*
562f5f633b1SBalsam CHIHI * At this point, we don't know which id matches which
563f5f633b1SBalsam CHIHI * sensor. Let's set arbitrally the id from the index.
564f5f633b1SBalsam CHIHI */
565f5f633b1SBalsam CHIHI lvts_sensor[i].id = i;
566f5f633b1SBalsam CHIHI
567f5f633b1SBalsam CHIHI /*
568f5f633b1SBalsam CHIHI * The thermal zone registration will set the trip
569f5f633b1SBalsam CHIHI * point interrupt in the thermal controller
570f5f633b1SBalsam CHIHI * register. But this one will be reset in the
571f5f633b1SBalsam CHIHI * initialization after. So we need to post pone the
572f5f633b1SBalsam CHIHI * thermal zone creation after the controller is
573f5f633b1SBalsam CHIHI * setup. For this reason, we store the device tree
574f5f633b1SBalsam CHIHI * node id from the data in the sensor structure
575f5f633b1SBalsam CHIHI */
576f5f633b1SBalsam CHIHI lvts_sensor[i].dt_id = dt_id;
577f5f633b1SBalsam CHIHI
578f5f633b1SBalsam CHIHI /*
579f5f633b1SBalsam CHIHI * We assign the base address of the thermal
580f5f633b1SBalsam CHIHI * controller as a back pointer. So it will be
581f5f633b1SBalsam CHIHI * accessible from the different thermal framework ops
582f5f633b1SBalsam CHIHI * as we pass the lvts_sensor pointer as thermal zone
583f5f633b1SBalsam CHIHI * private data.
584f5f633b1SBalsam CHIHI */
585f5f633b1SBalsam CHIHI lvts_sensor[i].base = lvts_ctrl->base;
586f5f633b1SBalsam CHIHI
587f5f633b1SBalsam CHIHI /*
588f5f633b1SBalsam CHIHI * Each sensor has its own register address to read from.
589f5f633b1SBalsam CHIHI */
590f5f633b1SBalsam CHIHI lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
591f5f633b1SBalsam CHIHI imm_regs[i] : msr_regs[i];
5922bba1acfSNícolas F. R. A. Prado
5932bba1acfSNícolas F. R. A. Prado lvts_sensor[i].low_thresh = INT_MIN;
5942bba1acfSNícolas F. R. A. Prado lvts_sensor[i].high_thresh = INT_MIN;
595f5f633b1SBalsam CHIHI };
596f5f633b1SBalsam CHIHI
597f5f633b1SBalsam CHIHI lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
598f5f633b1SBalsam CHIHI
599f5f633b1SBalsam CHIHI return 0;
600f5f633b1SBalsam CHIHI }
601f5f633b1SBalsam CHIHI
602f5f633b1SBalsam CHIHI /*
603f5f633b1SBalsam CHIHI * The efuse blob values follows the sensor enumeration per thermal
604f5f633b1SBalsam CHIHI * controller. The decoding of the stream is as follow:
605f5f633b1SBalsam CHIHI *
606561538f7SBalsam CHIHI * stream index map for MCU Domain :
607f5f633b1SBalsam CHIHI *
608561538f7SBalsam CHIHI * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
609561538f7SBalsam CHIHI * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09
610f5f633b1SBalsam CHIHI *
611561538f7SBalsam CHIHI * <-----mcu-tc#1-----> <-----sensor#2-----> <-----sensor#3----->
612561538f7SBalsam CHIHI * 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12
613f5f633b1SBalsam CHIHI *
614561538f7SBalsam CHIHI * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
615561538f7SBalsam CHIHI * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21
616561538f7SBalsam CHIHI *
617561538f7SBalsam CHIHI * stream index map for AP Domain :
618561538f7SBalsam CHIHI *
619561538f7SBalsam CHIHI * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1----->
620561538f7SBalsam CHIHI * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A
621561538f7SBalsam CHIHI *
622561538f7SBalsam CHIHI * <-----ap--tc#1-----> <-----sensor#2-----> <-----sensor#3----->
623561538f7SBalsam CHIHI * 0x2B | 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33
624561538f7SBalsam CHIHI *
625561538f7SBalsam CHIHI * <-----ap--tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6----->
626561538f7SBalsam CHIHI * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F
627561538f7SBalsam CHIHI *
628561538f7SBalsam CHIHI * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8----->
629561538f7SBalsam CHIHI * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48
630f5f633b1SBalsam CHIHI *
631f5f633b1SBalsam CHIHI * The data description gives the offset of the calibration data in
632f5f633b1SBalsam CHIHI * this bytes stream for each sensor.
633f5f633b1SBalsam CHIHI */
lvts_calibration_init(struct device * dev,struct lvts_ctrl * lvts_ctrl,const struct lvts_ctrl_data * lvts_ctrl_data,u8 * efuse_calibration)634f5f633b1SBalsam CHIHI static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
635f5f633b1SBalsam CHIHI const struct lvts_ctrl_data *lvts_ctrl_data,
636f5f633b1SBalsam CHIHI u8 *efuse_calibration)
637f5f633b1SBalsam CHIHI {
638f5f633b1SBalsam CHIHI int i;
639f5f633b1SBalsam CHIHI
640f5f633b1SBalsam CHIHI for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++)
641f5f633b1SBalsam CHIHI memcpy(&lvts_ctrl->calibration[i],
642f5f633b1SBalsam CHIHI efuse_calibration + lvts_ctrl_data->cal_offset[i], 2);
643f5f633b1SBalsam CHIHI
644f5f633b1SBalsam CHIHI return 0;
645f5f633b1SBalsam CHIHI }
646f5f633b1SBalsam CHIHI
647f5f633b1SBalsam CHIHI /*
648f5f633b1SBalsam CHIHI * The efuse bytes stream can be split into different chunk of
649f5f633b1SBalsam CHIHI * nvmems. This function reads and concatenate those into a single
650f5f633b1SBalsam CHIHI * buffer so it can be read sequentially when initializing the
651f5f633b1SBalsam CHIHI * calibration data.
652f5f633b1SBalsam CHIHI */
lvts_calibration_read(struct device * dev,struct lvts_domain * lvts_td,const struct lvts_data * lvts_data)653f5f633b1SBalsam CHIHI static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td,
654f5f633b1SBalsam CHIHI const struct lvts_data *lvts_data)
655f5f633b1SBalsam CHIHI {
656f5f633b1SBalsam CHIHI struct device_node *np = dev_of_node(dev);
657f5f633b1SBalsam CHIHI struct nvmem_cell *cell;
658f5f633b1SBalsam CHIHI struct property *prop;
659f5f633b1SBalsam CHIHI const char *cell_name;
660f5f633b1SBalsam CHIHI
661f5f633b1SBalsam CHIHI of_property_for_each_string(np, "nvmem-cell-names", prop, cell_name) {
662f5f633b1SBalsam CHIHI size_t len;
663f5f633b1SBalsam CHIHI u8 *efuse;
664f5f633b1SBalsam CHIHI
665f5f633b1SBalsam CHIHI cell = of_nvmem_cell_get(np, cell_name);
666f5f633b1SBalsam CHIHI if (IS_ERR(cell)) {
667f5f633b1SBalsam CHIHI dev_err(dev, "Failed to get cell '%s'\n", cell_name);
668f5f633b1SBalsam CHIHI return PTR_ERR(cell);
669f5f633b1SBalsam CHIHI }
670f5f633b1SBalsam CHIHI
671f5f633b1SBalsam CHIHI efuse = nvmem_cell_read(cell, &len);
672f5f633b1SBalsam CHIHI
673f5f633b1SBalsam CHIHI nvmem_cell_put(cell);
674f5f633b1SBalsam CHIHI
675f5f633b1SBalsam CHIHI if (IS_ERR(efuse)) {
676f5f633b1SBalsam CHIHI dev_err(dev, "Failed to read cell '%s'\n", cell_name);
677f5f633b1SBalsam CHIHI return PTR_ERR(efuse);
678f5f633b1SBalsam CHIHI }
679f5f633b1SBalsam CHIHI
680f5f633b1SBalsam CHIHI lvts_td->calib = devm_krealloc(dev, lvts_td->calib,
681f5f633b1SBalsam CHIHI lvts_td->calib_len + len, GFP_KERNEL);
6822db869daSChristophe JAILLET if (!lvts_td->calib) {
6832db869daSChristophe JAILLET kfree(efuse);
684f5f633b1SBalsam CHIHI return -ENOMEM;
6852db869daSChristophe JAILLET }
686f5f633b1SBalsam CHIHI
687f5f633b1SBalsam CHIHI memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len);
688f5f633b1SBalsam CHIHI
689f5f633b1SBalsam CHIHI lvts_td->calib_len += len;
690f5f633b1SBalsam CHIHI
691f5f633b1SBalsam CHIHI kfree(efuse);
692f5f633b1SBalsam CHIHI }
693f5f633b1SBalsam CHIHI
694f5f633b1SBalsam CHIHI return 0;
695f5f633b1SBalsam CHIHI }
696f5f633b1SBalsam CHIHI
lvts_golden_temp_init(struct device * dev,u32 * value)697f5f633b1SBalsam CHIHI static int lvts_golden_temp_init(struct device *dev, u32 *value)
698f5f633b1SBalsam CHIHI {
699f5f633b1SBalsam CHIHI u32 gt;
700f5f633b1SBalsam CHIHI
701f5f633b1SBalsam CHIHI gt = (*value) >> 24;
702f5f633b1SBalsam CHIHI
70390d29da1SJulien Panis /* A zero value for gt means that device has invalid efuse data */
70490d29da1SJulien Panis if (!gt)
70590d29da1SJulien Panis return -ENODATA;
70690d29da1SJulien Panis
70790d29da1SJulien Panis if (gt < LVTS_GOLDEN_TEMP_MAX)
708f5f633b1SBalsam CHIHI golden_temp = gt;
709f5f633b1SBalsam CHIHI
710f5f633b1SBalsam CHIHI coeff_b = golden_temp * 500 + LVTS_COEFF_B;
711f5f633b1SBalsam CHIHI
712f5f633b1SBalsam CHIHI return 0;
713f5f633b1SBalsam CHIHI }
714f5f633b1SBalsam CHIHI
lvts_ctrl_init(struct device * dev,struct lvts_domain * lvts_td,const struct lvts_data * lvts_data)715f5f633b1SBalsam CHIHI static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
716f5f633b1SBalsam CHIHI const struct lvts_data *lvts_data)
717f5f633b1SBalsam CHIHI {
718f5f633b1SBalsam CHIHI size_t size = sizeof(*lvts_td->lvts_ctrl) * lvts_data->num_lvts_ctrl;
719f5f633b1SBalsam CHIHI struct lvts_ctrl *lvts_ctrl;
720f5f633b1SBalsam CHIHI int i, ret;
721f5f633b1SBalsam CHIHI
722f5f633b1SBalsam CHIHI /*
723f5f633b1SBalsam CHIHI * Create the calibration bytes stream from efuse data
724f5f633b1SBalsam CHIHI */
725f5f633b1SBalsam CHIHI ret = lvts_calibration_read(dev, lvts_td, lvts_data);
726f5f633b1SBalsam CHIHI if (ret)
727f5f633b1SBalsam CHIHI return ret;
728f5f633b1SBalsam CHIHI
729f5f633b1SBalsam CHIHI /*
730f5f633b1SBalsam CHIHI * The golden temp information is contained in the first chunk
731f5f633b1SBalsam CHIHI * of efuse data.
732f5f633b1SBalsam CHIHI */
733f5f633b1SBalsam CHIHI ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib);
734f5f633b1SBalsam CHIHI if (ret)
735f5f633b1SBalsam CHIHI return ret;
736f5f633b1SBalsam CHIHI
737f5f633b1SBalsam CHIHI lvts_ctrl = devm_kzalloc(dev, size, GFP_KERNEL);
738f5f633b1SBalsam CHIHI if (!lvts_ctrl)
739f5f633b1SBalsam CHIHI return -ENOMEM;
740f5f633b1SBalsam CHIHI
741f5f633b1SBalsam CHIHI for (i = 0; i < lvts_data->num_lvts_ctrl; i++) {
742f5f633b1SBalsam CHIHI
743f5f633b1SBalsam CHIHI lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset;
744f5f633b1SBalsam CHIHI
745f5f633b1SBalsam CHIHI ret = lvts_sensor_init(dev, &lvts_ctrl[i],
746f5f633b1SBalsam CHIHI &lvts_data->lvts_ctrl[i]);
747f5f633b1SBalsam CHIHI if (ret)
748f5f633b1SBalsam CHIHI return ret;
749f5f633b1SBalsam CHIHI
750f5f633b1SBalsam CHIHI ret = lvts_calibration_init(dev, &lvts_ctrl[i],
751f5f633b1SBalsam CHIHI &lvts_data->lvts_ctrl[i],
752f5f633b1SBalsam CHIHI lvts_td->calib);
753f5f633b1SBalsam CHIHI if (ret)
754f5f633b1SBalsam CHIHI return ret;
755f5f633b1SBalsam CHIHI
756f5f633b1SBalsam CHIHI /*
757f5f633b1SBalsam CHIHI * The mode the ctrl will use to read the temperature
758f5f633b1SBalsam CHIHI * (filtered or immediate)
759f5f633b1SBalsam CHIHI */
760f5f633b1SBalsam CHIHI lvts_ctrl[i].mode = lvts_data->lvts_ctrl[i].mode;
761f5f633b1SBalsam CHIHI
762f5f633b1SBalsam CHIHI /*
763f5f633b1SBalsam CHIHI * The temperature to raw temperature must be done
764f5f633b1SBalsam CHIHI * after initializing the calibration.
765f5f633b1SBalsam CHIHI */
766f5f633b1SBalsam CHIHI lvts_ctrl[i].hw_tshut_raw_temp =
767f5f633b1SBalsam CHIHI lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
7682bba1acfSNícolas F. R. A. Prado
7692bba1acfSNícolas F. R. A. Prado lvts_ctrl[i].low_thresh = INT_MIN;
7702bba1acfSNícolas F. R. A. Prado lvts_ctrl[i].high_thresh = INT_MIN;
771f5f633b1SBalsam CHIHI }
772f5f633b1SBalsam CHIHI
773f5f633b1SBalsam CHIHI /*
774f5f633b1SBalsam CHIHI * We no longer need the efuse bytes stream, let's free it
775f5f633b1SBalsam CHIHI */
776f5f633b1SBalsam CHIHI devm_kfree(dev, lvts_td->calib);
777f5f633b1SBalsam CHIHI
778f5f633b1SBalsam CHIHI lvts_td->lvts_ctrl = lvts_ctrl;
779f5f633b1SBalsam CHIHI lvts_td->num_lvts_ctrl = lvts_data->num_lvts_ctrl;
780f5f633b1SBalsam CHIHI
781f5f633b1SBalsam CHIHI return 0;
782f5f633b1SBalsam CHIHI }
783f5f633b1SBalsam CHIHI
784f5f633b1SBalsam CHIHI /*
785f5f633b1SBalsam CHIHI * At this point the configuration register is the only place in the
786f5f633b1SBalsam CHIHI * driver where we write multiple values. Per hardware constraint,
787f5f633b1SBalsam CHIHI * each write in the configuration register must be separated by a
788f5f633b1SBalsam CHIHI * delay of 2 us.
789f5f633b1SBalsam CHIHI */
lvts_write_config(struct lvts_ctrl * lvts_ctrl,u32 * cmds,int nr_cmds)790f5f633b1SBalsam CHIHI static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, u32 *cmds, int nr_cmds)
791f5f633b1SBalsam CHIHI {
792f5f633b1SBalsam CHIHI int i;
793f5f633b1SBalsam CHIHI
794f5f633b1SBalsam CHIHI /*
795f5f633b1SBalsam CHIHI * Configuration register
796f5f633b1SBalsam CHIHI */
797f5f633b1SBalsam CHIHI for (i = 0; i < nr_cmds; i++) {
798f5f633b1SBalsam CHIHI writel(cmds[i], LVTS_CONFIG(lvts_ctrl->base));
799f5f633b1SBalsam CHIHI usleep_range(2, 4);
800f5f633b1SBalsam CHIHI }
801f5f633b1SBalsam CHIHI }
802f5f633b1SBalsam CHIHI
lvts_irq_init(struct lvts_ctrl * lvts_ctrl)803f5f633b1SBalsam CHIHI static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
804f5f633b1SBalsam CHIHI {
805f5f633b1SBalsam CHIHI /*
806f5f633b1SBalsam CHIHI * LVTS_PROTCTL : Thermal Protection Sensor Selection
807f5f633b1SBalsam CHIHI *
808f5f633b1SBalsam CHIHI * Bits:
809f5f633b1SBalsam CHIHI *
810f5f633b1SBalsam CHIHI * 19-18 : Sensor to base the protection on
811f5f633b1SBalsam CHIHI * 17-16 : Strategy:
812f5f633b1SBalsam CHIHI * 00 : Average of 4 sensors
813f5f633b1SBalsam CHIHI * 01 : Max of 4 sensors
814f5f633b1SBalsam CHIHI * 10 : Selected sensor with bits 19-18
815f5f633b1SBalsam CHIHI * 11 : Reserved
816f5f633b1SBalsam CHIHI */
817f5f633b1SBalsam CHIHI writel(BIT(16), LVTS_PROTCTL(lvts_ctrl->base));
818f5f633b1SBalsam CHIHI
819f5f633b1SBalsam CHIHI /*
820f5f633b1SBalsam CHIHI * LVTS_PROTTA : Stage 1 temperature threshold
821f5f633b1SBalsam CHIHI * LVTS_PROTTB : Stage 2 temperature threshold
822f5f633b1SBalsam CHIHI * LVTS_PROTTC : Stage 3 temperature threshold
823f5f633b1SBalsam CHIHI *
824f5f633b1SBalsam CHIHI * Bits:
825f5f633b1SBalsam CHIHI *
826f5f633b1SBalsam CHIHI * 14-0: Raw temperature threshold
827f5f633b1SBalsam CHIHI *
828f5f633b1SBalsam CHIHI * writel(0x0, LVTS_PROTTA(lvts_ctrl->base));
829f5f633b1SBalsam CHIHI * writel(0x0, LVTS_PROTTB(lvts_ctrl->base));
830f5f633b1SBalsam CHIHI */
831f5f633b1SBalsam CHIHI writel(lvts_ctrl->hw_tshut_raw_temp, LVTS_PROTTC(lvts_ctrl->base));
832f5f633b1SBalsam CHIHI
833f5f633b1SBalsam CHIHI /*
834f5f633b1SBalsam CHIHI * LVTS_MONINT : Interrupt configuration register
835f5f633b1SBalsam CHIHI *
836f5f633b1SBalsam CHIHI * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS
837f5f633b1SBalsam CHIHI * register, except we set the bits to enable the interrupt.
838f5f633b1SBalsam CHIHI */
839f5f633b1SBalsam CHIHI writel(LVTS_MONINT_CONF, LVTS_MONINT(lvts_ctrl->base));
840f5f633b1SBalsam CHIHI
841f5f633b1SBalsam CHIHI return 0;
842f5f633b1SBalsam CHIHI }
843f5f633b1SBalsam CHIHI
lvts_domain_reset(struct device * dev,struct reset_control * reset)844f5f633b1SBalsam CHIHI static int lvts_domain_reset(struct device *dev, struct reset_control *reset)
845f5f633b1SBalsam CHIHI {
846f5f633b1SBalsam CHIHI int ret;
847f5f633b1SBalsam CHIHI
848f5f633b1SBalsam CHIHI ret = reset_control_assert(reset);
849f5f633b1SBalsam CHIHI if (ret)
850f5f633b1SBalsam CHIHI return ret;
851f5f633b1SBalsam CHIHI
852f5f633b1SBalsam CHIHI return reset_control_deassert(reset);
853f5f633b1SBalsam CHIHI }
854f5f633b1SBalsam CHIHI
855f5f633b1SBalsam CHIHI /*
856f5f633b1SBalsam CHIHI * Enable or disable the clocks of a specified thermal controller
857f5f633b1SBalsam CHIHI */
lvts_ctrl_set_enable(struct lvts_ctrl * lvts_ctrl,int enable)858f5f633b1SBalsam CHIHI static int lvts_ctrl_set_enable(struct lvts_ctrl *lvts_ctrl, int enable)
859f5f633b1SBalsam CHIHI {
860f5f633b1SBalsam CHIHI /*
861f5f633b1SBalsam CHIHI * LVTS_CLKEN : Internal LVTS clock
862f5f633b1SBalsam CHIHI *
863f5f633b1SBalsam CHIHI * Bits:
864f5f633b1SBalsam CHIHI *
865f5f633b1SBalsam CHIHI * 0 : enable / disable clock
866f5f633b1SBalsam CHIHI */
867f5f633b1SBalsam CHIHI writel(enable, LVTS_CLKEN(lvts_ctrl->base));
868f5f633b1SBalsam CHIHI
869f5f633b1SBalsam CHIHI return 0;
870f5f633b1SBalsam CHIHI }
871f5f633b1SBalsam CHIHI
lvts_ctrl_connect(struct device * dev,struct lvts_ctrl * lvts_ctrl)872f5f633b1SBalsam CHIHI static int lvts_ctrl_connect(struct device *dev, struct lvts_ctrl *lvts_ctrl)
873f5f633b1SBalsam CHIHI {
874f5f633b1SBalsam CHIHI u32 id, cmds[] = { 0xC103FFFF, 0xC502FF55 };
875f5f633b1SBalsam CHIHI
876f5f633b1SBalsam CHIHI lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
877f5f633b1SBalsam CHIHI
878f5f633b1SBalsam CHIHI /*
879f5f633b1SBalsam CHIHI * LVTS_ID : Get ID and status of the thermal controller
880f5f633b1SBalsam CHIHI *
881f5f633b1SBalsam CHIHI * Bits:
882f5f633b1SBalsam CHIHI *
883f5f633b1SBalsam CHIHI * 0-5 : thermal controller id
884f5f633b1SBalsam CHIHI * 7 : thermal controller connection is valid
885f5f633b1SBalsam CHIHI */
886f5f633b1SBalsam CHIHI id = readl(LVTS_ID(lvts_ctrl->base));
887f5f633b1SBalsam CHIHI if (!(id & BIT(7)))
888f5f633b1SBalsam CHIHI return -EIO;
889f5f633b1SBalsam CHIHI
890f5f633b1SBalsam CHIHI return 0;
891f5f633b1SBalsam CHIHI }
892f5f633b1SBalsam CHIHI
lvts_ctrl_initialize(struct device * dev,struct lvts_ctrl * lvts_ctrl)893f5f633b1SBalsam CHIHI static int lvts_ctrl_initialize(struct device *dev, struct lvts_ctrl *lvts_ctrl)
894f5f633b1SBalsam CHIHI {
895f5f633b1SBalsam CHIHI /*
896f5f633b1SBalsam CHIHI * Write device mask: 0xC1030000
897f5f633b1SBalsam CHIHI */
898f5f633b1SBalsam CHIHI u32 cmds[] = {
899f5f633b1SBalsam CHIHI 0xC1030E01, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1,
900f5f633b1SBalsam CHIHI 0xC10307A6, 0xC10306B8, 0xC1030500, 0xC1030420, 0xC1030300,
901f5f633b1SBalsam CHIHI 0xC1030030, 0xC10300F6, 0xC1030050, 0xC1030060, 0xC10300AC,
902f5f633b1SBalsam CHIHI 0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
903f5f633b1SBalsam CHIHI };
904f5f633b1SBalsam CHIHI
905f5f633b1SBalsam CHIHI lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
906f5f633b1SBalsam CHIHI
907f5f633b1SBalsam CHIHI return 0;
908f5f633b1SBalsam CHIHI }
909f5f633b1SBalsam CHIHI
lvts_ctrl_calibrate(struct device * dev,struct lvts_ctrl * lvts_ctrl)910f5f633b1SBalsam CHIHI static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
911f5f633b1SBalsam CHIHI {
912f5f633b1SBalsam CHIHI int i;
913f5f633b1SBalsam CHIHI void __iomem *lvts_edata[] = {
914f5f633b1SBalsam CHIHI LVTS_EDATA00(lvts_ctrl->base),
915f5f633b1SBalsam CHIHI LVTS_EDATA01(lvts_ctrl->base),
916f5f633b1SBalsam CHIHI LVTS_EDATA02(lvts_ctrl->base),
917f5f633b1SBalsam CHIHI LVTS_EDATA03(lvts_ctrl->base)
918f5f633b1SBalsam CHIHI };
919f5f633b1SBalsam CHIHI
920f5f633b1SBalsam CHIHI /*
921f5f633b1SBalsam CHIHI * LVTS_EDATA0X : Efuse calibration reference value for sensor X
922f5f633b1SBalsam CHIHI *
923f5f633b1SBalsam CHIHI * Bits:
924f5f633b1SBalsam CHIHI *
925f5f633b1SBalsam CHIHI * 20-0 : Efuse value for normalization data
926f5f633b1SBalsam CHIHI */
927f5f633b1SBalsam CHIHI for (i = 0; i < LVTS_SENSOR_MAX; i++)
928f5f633b1SBalsam CHIHI writel(lvts_ctrl->calibration[i], lvts_edata[i]);
929f5f633b1SBalsam CHIHI
930f5f633b1SBalsam CHIHI return 0;
931f5f633b1SBalsam CHIHI }
932f5f633b1SBalsam CHIHI
lvts_ctrl_configure(struct device * dev,struct lvts_ctrl * lvts_ctrl)933f5f633b1SBalsam CHIHI static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
934f5f633b1SBalsam CHIHI {
935f5f633b1SBalsam CHIHI u32 value;
936f5f633b1SBalsam CHIHI
937f5f633b1SBalsam CHIHI /*
938f5f633b1SBalsam CHIHI * LVTS_TSSEL : Sensing point index numbering
939f5f633b1SBalsam CHIHI *
940f5f633b1SBalsam CHIHI * Bits:
941f5f633b1SBalsam CHIHI *
942f5f633b1SBalsam CHIHI * 31-24: ADC Sense 3
943f5f633b1SBalsam CHIHI * 23-16: ADC Sense 2
944f5f633b1SBalsam CHIHI * 15-8 : ADC Sense 1
945f5f633b1SBalsam CHIHI * 7-0 : ADC Sense 0
946f5f633b1SBalsam CHIHI */
947f5f633b1SBalsam CHIHI value = LVTS_TSSEL_CONF;
948f5f633b1SBalsam CHIHI writel(value, LVTS_TSSEL(lvts_ctrl->base));
949f5f633b1SBalsam CHIHI
950f5f633b1SBalsam CHIHI /*
951f5f633b1SBalsam CHIHI * LVTS_CALSCALE : ADC voltage round
952f5f633b1SBalsam CHIHI */
953f5f633b1SBalsam CHIHI value = 0x300;
954f5f633b1SBalsam CHIHI value = LVTS_CALSCALE_CONF;
955f5f633b1SBalsam CHIHI
956f5f633b1SBalsam CHIHI /*
957f5f633b1SBalsam CHIHI * LVTS_MSRCTL0 : Sensor filtering strategy
958f5f633b1SBalsam CHIHI *
959f5f633b1SBalsam CHIHI * Filters:
960f5f633b1SBalsam CHIHI *
961f5f633b1SBalsam CHIHI * 000 : One sample
962f5f633b1SBalsam CHIHI * 001 : Avg 2 samples
963f5f633b1SBalsam CHIHI * 010 : 4 samples, drop min and max, avg 2 samples
964f5f633b1SBalsam CHIHI * 011 : 6 samples, drop min and max, avg 4 samples
965f5f633b1SBalsam CHIHI * 100 : 10 samples, drop min and max, avg 8 samples
966f5f633b1SBalsam CHIHI * 101 : 18 samples, drop min and max, avg 16 samples
967f5f633b1SBalsam CHIHI *
968f5f633b1SBalsam CHIHI * Bits:
969f5f633b1SBalsam CHIHI *
970f5f633b1SBalsam CHIHI * 0-2 : Sensor0 filter
971f5f633b1SBalsam CHIHI * 3-5 : Sensor1 filter
972f5f633b1SBalsam CHIHI * 6-8 : Sensor2 filter
973f5f633b1SBalsam CHIHI * 9-11 : Sensor3 filter
974f5f633b1SBalsam CHIHI */
975f5f633b1SBalsam CHIHI value = LVTS_HW_FILTER << 9 | LVTS_HW_FILTER << 6 |
976f5f633b1SBalsam CHIHI LVTS_HW_FILTER << 3 | LVTS_HW_FILTER;
977f5f633b1SBalsam CHIHI writel(value, LVTS_MSRCTL0(lvts_ctrl->base));
978f5f633b1SBalsam CHIHI
979f5f633b1SBalsam CHIHI /*
980f5f633b1SBalsam CHIHI * LVTS_MONCTL1 : Period unit and group interval configuration
981f5f633b1SBalsam CHIHI *
982f5f633b1SBalsam CHIHI * The clock source of LVTS thermal controller is 26MHz.
983f5f633b1SBalsam CHIHI *
984f5f633b1SBalsam CHIHI * The period unit is a time base for all the interval delays
985f5f633b1SBalsam CHIHI * specified in the registers. By default we use 12. The time
986f5f633b1SBalsam CHIHI * conversion is done by multiplying by 256 and 1/26.10^6
987f5f633b1SBalsam CHIHI *
988f5f633b1SBalsam CHIHI * An interval delay multiplied by the period unit gives the
989f5f633b1SBalsam CHIHI * duration in seconds.
990f5f633b1SBalsam CHIHI *
991f5f633b1SBalsam CHIHI * - Filter interval delay is a delay between two samples of
992f5f633b1SBalsam CHIHI * the same sensor.
993f5f633b1SBalsam CHIHI *
994f5f633b1SBalsam CHIHI * - Sensor interval delay is a delay between two samples of
995f5f633b1SBalsam CHIHI * different sensors.
996f5f633b1SBalsam CHIHI *
997f5f633b1SBalsam CHIHI * - Group interval delay is a delay between different rounds.
998f5f633b1SBalsam CHIHI *
999f5f633b1SBalsam CHIHI * For example:
1000f5f633b1SBalsam CHIHI * If Period unit = C, filter delay = 1, sensor delay = 2, group delay = 1,
1001f5f633b1SBalsam CHIHI * and two sensors, TS1 and TS2, are in a LVTS thermal controller
1002f5f633b1SBalsam CHIHI * and then
1003f5f633b1SBalsam CHIHI * Period unit time = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us
1004f5f633b1SBalsam CHIHI * Filter interval delay = 1 * Period unit = 118.149us
1005f5f633b1SBalsam CHIHI * Sensor interval delay = 2 * Period unit = 236.298us
1006f5f633b1SBalsam CHIHI * Group interval delay = 1 * Period unit = 118.149us
1007f5f633b1SBalsam CHIHI *
1008f5f633b1SBalsam CHIHI * TS1 TS1 ... TS1 TS2 TS2 ... TS2 TS1...
1009f5f633b1SBalsam CHIHI * <--> Filter interval delay
1010f5f633b1SBalsam CHIHI * <--> Sensor interval delay
1011f5f633b1SBalsam CHIHI * <--> Group interval delay
1012f5f633b1SBalsam CHIHI * Bits:
1013f5f633b1SBalsam CHIHI * 29 - 20 : Group interval
1014f5f633b1SBalsam CHIHI * 16 - 13 : Send a single interrupt when crossing the hot threshold (1)
1015f5f633b1SBalsam CHIHI * or an interrupt everytime the hot threshold is crossed (0)
1016f5f633b1SBalsam CHIHI * 9 - 0 : Period unit
1017f5f633b1SBalsam CHIHI *
1018f5f633b1SBalsam CHIHI */
1019f5f633b1SBalsam CHIHI value = LVTS_GROUP_INTERVAL << 20 | LVTS_PERIOD_UNIT;
1020f5f633b1SBalsam CHIHI writel(value, LVTS_MONCTL1(lvts_ctrl->base));
1021f5f633b1SBalsam CHIHI
1022f5f633b1SBalsam CHIHI /*
1023f5f633b1SBalsam CHIHI * LVTS_MONCTL2 : Filtering and sensor interval
1024f5f633b1SBalsam CHIHI *
1025f5f633b1SBalsam CHIHI * Bits:
1026f5f633b1SBalsam CHIHI *
1027f5f633b1SBalsam CHIHI * 25-16 : Interval unit in PERIOD_UNIT between sample on
1028f5f633b1SBalsam CHIHI * the same sensor, filter interval
1029f5f633b1SBalsam CHIHI * 9-0 : Interval unit in PERIOD_UNIT between each sensor
1030f5f633b1SBalsam CHIHI *
1031f5f633b1SBalsam CHIHI */
1032f5f633b1SBalsam CHIHI value = LVTS_FILTER_INTERVAL << 16 | LVTS_SENSOR_INTERVAL;
1033f5f633b1SBalsam CHIHI writel(value, LVTS_MONCTL2(lvts_ctrl->base));
1034f5f633b1SBalsam CHIHI
1035f5f633b1SBalsam CHIHI return lvts_irq_init(lvts_ctrl);
1036f5f633b1SBalsam CHIHI }
1037f5f633b1SBalsam CHIHI
lvts_ctrl_start(struct device * dev,struct lvts_ctrl * lvts_ctrl)1038f5f633b1SBalsam CHIHI static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
1039f5f633b1SBalsam CHIHI {
1040f5f633b1SBalsam CHIHI struct lvts_sensor *lvts_sensors = lvts_ctrl->sensors;
1041f5f633b1SBalsam CHIHI struct thermal_zone_device *tz;
1042f5f633b1SBalsam CHIHI u32 sensor_map = 0;
1043f5f633b1SBalsam CHIHI int i;
104464de162eSNícolas F. R. A. Prado /*
104564de162eSNícolas F. R. A. Prado * Bitmaps to enable each sensor on immediate and filtered modes, as
104664de162eSNícolas F. R. A. Prado * described in MSRCTL1 and MONCTL0 registers below, respectively.
104764de162eSNícolas F. R. A. Prado */
104864de162eSNícolas F. R. A. Prado u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) };
104964de162eSNícolas F. R. A. Prado u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) };
105064de162eSNícolas F. R. A. Prado
105164de162eSNícolas F. R. A. Prado u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ?
105264de162eSNícolas F. R. A. Prado sensor_imm_bitmap : sensor_filt_bitmap;
1053f5f633b1SBalsam CHIHI
1054f5f633b1SBalsam CHIHI for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
1055f5f633b1SBalsam CHIHI
1056f5f633b1SBalsam CHIHI int dt_id = lvts_sensors[i].dt_id;
1057f5f633b1SBalsam CHIHI
1058f5f633b1SBalsam CHIHI tz = devm_thermal_of_zone_register(dev, dt_id, &lvts_sensors[i],
1059f5f633b1SBalsam CHIHI &lvts_ops);
1060f5f633b1SBalsam CHIHI if (IS_ERR(tz)) {
1061f5f633b1SBalsam CHIHI /*
1062f5f633b1SBalsam CHIHI * This thermal zone is not described in the
1063f5f633b1SBalsam CHIHI * device tree. It is not an error from the
1064f5f633b1SBalsam CHIHI * thermal OF code POV, we just continue.
1065f5f633b1SBalsam CHIHI */
1066f5f633b1SBalsam CHIHI if (PTR_ERR(tz) == -ENODEV)
1067f5f633b1SBalsam CHIHI continue;
1068f5f633b1SBalsam CHIHI
1069f5f633b1SBalsam CHIHI return PTR_ERR(tz);
1070f5f633b1SBalsam CHIHI }
1071f5f633b1SBalsam CHIHI
107227cc5be1SYangtao Li devm_thermal_add_hwmon_sysfs(dev, tz);
107351c8e119SChen-Yu Tsai
1074f5f633b1SBalsam CHIHI /*
1075f5f633b1SBalsam CHIHI * The thermal zone pointer will be needed in the
1076f5f633b1SBalsam CHIHI * interrupt handler, we store it in the sensor
1077f5f633b1SBalsam CHIHI * structure. The thermal domain structure will be
1078f5f633b1SBalsam CHIHI * passed to the interrupt handler private data as the
1079f5f633b1SBalsam CHIHI * interrupt is shared for all the controller
1080f5f633b1SBalsam CHIHI * belonging to the thermal domain.
1081f5f633b1SBalsam CHIHI */
1082f5f633b1SBalsam CHIHI lvts_sensors[i].tz = tz;
1083f5f633b1SBalsam CHIHI
1084f5f633b1SBalsam CHIHI /*
1085f5f633b1SBalsam CHIHI * This sensor was correctly associated with a thermal
1086f5f633b1SBalsam CHIHI * zone, let's set the corresponding bit in the sensor
1087f5f633b1SBalsam CHIHI * map, so we can enable the temperature monitoring in
1088f5f633b1SBalsam CHIHI * the hardware thermal controller.
1089f5f633b1SBalsam CHIHI */
109064de162eSNícolas F. R. A. Prado sensor_map |= sensor_bitmap[i];
1091f5f633b1SBalsam CHIHI }
1092f5f633b1SBalsam CHIHI
1093f5f633b1SBalsam CHIHI /*
1094f5f633b1SBalsam CHIHI * The initialization of the thermal zones give us
1095f5f633b1SBalsam CHIHI * which sensor point to enable. If any thermal zone
1096f5f633b1SBalsam CHIHI * was not described in the device tree, it won't be
1097f5f633b1SBalsam CHIHI * enabled here in the sensor map.
1098f5f633b1SBalsam CHIHI */
109964de162eSNícolas F. R. A. Prado if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
110064de162eSNícolas F. R. A. Prado /*
110164de162eSNícolas F. R. A. Prado * LVTS_MSRCTL1 : Measurement control
110264de162eSNícolas F. R. A. Prado *
110364de162eSNícolas F. R. A. Prado * Bits:
110464de162eSNícolas F. R. A. Prado *
110564de162eSNícolas F. R. A. Prado * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
110664de162eSNícolas F. R. A. Prado * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
110764de162eSNícolas F. R. A. Prado * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
110864de162eSNícolas F. R. A. Prado * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
110964de162eSNícolas F. R. A. Prado *
111064de162eSNícolas F. R. A. Prado * That configuration will ignore the filtering and the delays
111164de162eSNícolas F. R. A. Prado * introduced in MONCTL1 and MONCTL2
111264de162eSNícolas F. R. A. Prado */
111364de162eSNícolas F. R. A. Prado writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base));
111464de162eSNícolas F. R. A. Prado } else {
111564de162eSNícolas F. R. A. Prado /*
111664de162eSNícolas F. R. A. Prado * Bits:
111764de162eSNícolas F. R. A. Prado * 9: Single point access flow
111864de162eSNícolas F. R. A. Prado * 0-3: Enable sensing point 0-3
111964de162eSNícolas F. R. A. Prado */
1120f5f633b1SBalsam CHIHI writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
112164de162eSNícolas F. R. A. Prado }
1122f5f633b1SBalsam CHIHI
1123f5f633b1SBalsam CHIHI return 0;
1124f5f633b1SBalsam CHIHI }
1125f5f633b1SBalsam CHIHI
lvts_domain_init(struct device * dev,struct lvts_domain * lvts_td,const struct lvts_data * lvts_data)1126f5f633b1SBalsam CHIHI static int lvts_domain_init(struct device *dev, struct lvts_domain *lvts_td,
1127f5f633b1SBalsam CHIHI const struct lvts_data *lvts_data)
1128f5f633b1SBalsam CHIHI {
1129f5f633b1SBalsam CHIHI struct lvts_ctrl *lvts_ctrl;
1130f5f633b1SBalsam CHIHI int i, ret;
1131f5f633b1SBalsam CHIHI
1132f5f633b1SBalsam CHIHI ret = lvts_ctrl_init(dev, lvts_td, lvts_data);
1133f5f633b1SBalsam CHIHI if (ret)
1134f5f633b1SBalsam CHIHI return ret;
1135f5f633b1SBalsam CHIHI
1136f5f633b1SBalsam CHIHI ret = lvts_domain_reset(dev, lvts_td->reset);
1137f5f633b1SBalsam CHIHI if (ret) {
1138f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to reset domain");
1139f5f633b1SBalsam CHIHI return ret;
1140f5f633b1SBalsam CHIHI }
1141f5f633b1SBalsam CHIHI
1142f5f633b1SBalsam CHIHI for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
1143f5f633b1SBalsam CHIHI
1144f5f633b1SBalsam CHIHI lvts_ctrl = &lvts_td->lvts_ctrl[i];
1145f5f633b1SBalsam CHIHI
1146f5f633b1SBalsam CHIHI /*
1147f5f633b1SBalsam CHIHI * Initialization steps:
1148f5f633b1SBalsam CHIHI *
1149f5f633b1SBalsam CHIHI * - Enable the clock
1150f5f633b1SBalsam CHIHI * - Connect to the LVTS
1151f5f633b1SBalsam CHIHI * - Initialize the LVTS
1152f5f633b1SBalsam CHIHI * - Prepare the calibration data
1153f5f633b1SBalsam CHIHI * - Select monitored sensors
1154f5f633b1SBalsam CHIHI * [ Configure sampling ]
1155f5f633b1SBalsam CHIHI * [ Configure the interrupt ]
1156f5f633b1SBalsam CHIHI * - Start measurement
1157f5f633b1SBalsam CHIHI */
1158f5f633b1SBalsam CHIHI ret = lvts_ctrl_set_enable(lvts_ctrl, true);
1159f5f633b1SBalsam CHIHI if (ret) {
1160f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to enable LVTS clock");
1161f5f633b1SBalsam CHIHI return ret;
1162f5f633b1SBalsam CHIHI }
1163f5f633b1SBalsam CHIHI
1164f5f633b1SBalsam CHIHI ret = lvts_ctrl_connect(dev, lvts_ctrl);
1165f5f633b1SBalsam CHIHI if (ret) {
1166f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to connect to LVTS controller");
1167f5f633b1SBalsam CHIHI return ret;
1168f5f633b1SBalsam CHIHI }
1169f5f633b1SBalsam CHIHI
1170f5f633b1SBalsam CHIHI ret = lvts_ctrl_initialize(dev, lvts_ctrl);
1171f5f633b1SBalsam CHIHI if (ret) {
1172f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to initialize controller");
1173f5f633b1SBalsam CHIHI return ret;
1174f5f633b1SBalsam CHIHI }
1175f5f633b1SBalsam CHIHI
1176f5f633b1SBalsam CHIHI ret = lvts_ctrl_calibrate(dev, lvts_ctrl);
1177f5f633b1SBalsam CHIHI if (ret) {
1178f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to calibrate controller");
1179f5f633b1SBalsam CHIHI return ret;
1180f5f633b1SBalsam CHIHI }
1181f5f633b1SBalsam CHIHI
1182f5f633b1SBalsam CHIHI ret = lvts_ctrl_configure(dev, lvts_ctrl);
1183f5f633b1SBalsam CHIHI if (ret) {
1184f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to configure controller");
1185f5f633b1SBalsam CHIHI return ret;
1186f5f633b1SBalsam CHIHI }
1187f5f633b1SBalsam CHIHI
1188f5f633b1SBalsam CHIHI ret = lvts_ctrl_start(dev, lvts_ctrl);
1189f5f633b1SBalsam CHIHI if (ret) {
1190f5f633b1SBalsam CHIHI dev_dbg(dev, "Failed to start controller");
1191f5f633b1SBalsam CHIHI return ret;
1192f5f633b1SBalsam CHIHI }
1193f5f633b1SBalsam CHIHI }
1194f5f633b1SBalsam CHIHI
1195f5f633b1SBalsam CHIHI return lvts_debugfs_init(dev, lvts_td);
1196f5f633b1SBalsam CHIHI }
1197f5f633b1SBalsam CHIHI
lvts_probe(struct platform_device * pdev)1198f5f633b1SBalsam CHIHI static int lvts_probe(struct platform_device *pdev)
1199f5f633b1SBalsam CHIHI {
1200f5f633b1SBalsam CHIHI const struct lvts_data *lvts_data;
1201f5f633b1SBalsam CHIHI struct lvts_domain *lvts_td;
1202f5f633b1SBalsam CHIHI struct device *dev = &pdev->dev;
1203f5f633b1SBalsam CHIHI struct resource *res;
1204f5f633b1SBalsam CHIHI int irq, ret;
1205f5f633b1SBalsam CHIHI
1206f5f633b1SBalsam CHIHI lvts_td = devm_kzalloc(dev, sizeof(*lvts_td), GFP_KERNEL);
1207f5f633b1SBalsam CHIHI if (!lvts_td)
1208f5f633b1SBalsam CHIHI return -ENOMEM;
1209f5f633b1SBalsam CHIHI
1210f5f633b1SBalsam CHIHI lvts_data = of_device_get_match_data(dev);
1211*79ef1a55SJulien Panis if (!lvts_data)
1212*79ef1a55SJulien Panis return -ENODEV;
1213f5f633b1SBalsam CHIHI
1214f5f633b1SBalsam CHIHI lvts_td->clk = devm_clk_get_enabled(dev, NULL);
1215f5f633b1SBalsam CHIHI if (IS_ERR(lvts_td->clk))
1216f5f633b1SBalsam CHIHI return dev_err_probe(dev, PTR_ERR(lvts_td->clk), "Failed to retrieve clock\n");
1217f5f633b1SBalsam CHIHI
1218f5f633b1SBalsam CHIHI res = platform_get_mem_or_io(pdev, 0);
1219f5f633b1SBalsam CHIHI if (!res)
1220f5f633b1SBalsam CHIHI return dev_err_probe(dev, (-ENXIO), "No IO resource\n");
1221f5f633b1SBalsam CHIHI
1222f5f633b1SBalsam CHIHI lvts_td->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
1223f5f633b1SBalsam CHIHI if (IS_ERR(lvts_td->base))
1224f5f633b1SBalsam CHIHI return dev_err_probe(dev, PTR_ERR(lvts_td->base), "Failed to map io resource\n");
1225f5f633b1SBalsam CHIHI
1226f5f633b1SBalsam CHIHI lvts_td->reset = devm_reset_control_get_by_index(dev, 0);
1227f5f633b1SBalsam CHIHI if (IS_ERR(lvts_td->reset))
1228f5f633b1SBalsam CHIHI return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n");
1229f5f633b1SBalsam CHIHI
1230f5f633b1SBalsam CHIHI irq = platform_get_irq(pdev, 0);
1231f5f633b1SBalsam CHIHI if (irq < 0)
1232e9b1de73SChen Jiahao return irq;
1233f5f633b1SBalsam CHIHI
1234f5f633b1SBalsam CHIHI ret = lvts_domain_init(dev, lvts_td, lvts_data);
1235f5f633b1SBalsam CHIHI if (ret)
1236f5f633b1SBalsam CHIHI return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n");
1237f5f633b1SBalsam CHIHI
1238f5f633b1SBalsam CHIHI /*
1239f5f633b1SBalsam CHIHI * At this point the LVTS is initialized and enabled. We can
1240f5f633b1SBalsam CHIHI * safely enable the interrupt.
1241f5f633b1SBalsam CHIHI */
1242f5f633b1SBalsam CHIHI ret = devm_request_threaded_irq(dev, irq, NULL, lvts_irq_handler,
1243f5f633b1SBalsam CHIHI IRQF_ONESHOT, dev_name(dev), lvts_td);
1244f5f633b1SBalsam CHIHI if (ret)
1245f5f633b1SBalsam CHIHI return dev_err_probe(dev, ret, "Failed to request interrupt\n");
1246f5f633b1SBalsam CHIHI
1247f5f633b1SBalsam CHIHI platform_set_drvdata(pdev, lvts_td);
1248f5f633b1SBalsam CHIHI
1249f5f633b1SBalsam CHIHI return 0;
1250f5f633b1SBalsam CHIHI }
1251f5f633b1SBalsam CHIHI
lvts_remove(struct platform_device * pdev)1252f5f633b1SBalsam CHIHI static int lvts_remove(struct platform_device *pdev)
1253f5f633b1SBalsam CHIHI {
1254f5f633b1SBalsam CHIHI struct lvts_domain *lvts_td;
1255f5f633b1SBalsam CHIHI int i;
1256f5f633b1SBalsam CHIHI
1257f5f633b1SBalsam CHIHI lvts_td = platform_get_drvdata(pdev);
1258f5f633b1SBalsam CHIHI
1259f5f633b1SBalsam CHIHI for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
1260f5f633b1SBalsam CHIHI lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
1261f5f633b1SBalsam CHIHI
1262f5f633b1SBalsam CHIHI lvts_debugfs_exit(lvts_td);
1263f5f633b1SBalsam CHIHI
1264f5f633b1SBalsam CHIHI return 0;
1265f5f633b1SBalsam CHIHI }
1266f5f633b1SBalsam CHIHI
1267561538f7SBalsam CHIHI static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
1268f5f633b1SBalsam CHIHI {
1269f5f633b1SBalsam CHIHI .cal_offset = { 0x04, 0x07 },
1270f5f633b1SBalsam CHIHI .lvts_sensor = {
1271f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_BIG_CPU0 },
1272f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_BIG_CPU1 }
1273f5f633b1SBalsam CHIHI },
1274f5f633b1SBalsam CHIHI .num_lvts_sensor = 2,
1275f5f633b1SBalsam CHIHI .offset = 0x0,
1276f5f633b1SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1277f5f633b1SBalsam CHIHI },
1278f5f633b1SBalsam CHIHI {
1279f5f633b1SBalsam CHIHI .cal_offset = { 0x0d, 0x10 },
1280f5f633b1SBalsam CHIHI .lvts_sensor = {
1281f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_BIG_CPU2 },
1282f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_BIG_CPU3 }
1283f5f633b1SBalsam CHIHI },
1284f5f633b1SBalsam CHIHI .num_lvts_sensor = 2,
1285f5f633b1SBalsam CHIHI .offset = 0x100,
1286f5f633b1SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1287f5f633b1SBalsam CHIHI },
1288f5f633b1SBalsam CHIHI {
1289f5f633b1SBalsam CHIHI .cal_offset = { 0x16, 0x19, 0x1c, 0x1f },
1290f5f633b1SBalsam CHIHI .lvts_sensor = {
1291f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_LITTLE_CPU0 },
1292f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_LITTLE_CPU1 },
1293f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_LITTLE_CPU2 },
1294f5f633b1SBalsam CHIHI { .dt_id = MT8195_MCU_LITTLE_CPU3 }
1295f5f633b1SBalsam CHIHI },
1296f5f633b1SBalsam CHIHI .num_lvts_sensor = 4,
1297f5f633b1SBalsam CHIHI .offset = 0x200,
1298f5f633b1SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1299f5f633b1SBalsam CHIHI }
1300f5f633b1SBalsam CHIHI };
1301f5f633b1SBalsam CHIHI
1302561538f7SBalsam CHIHI static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
1303561538f7SBalsam CHIHI {
1304561538f7SBalsam CHIHI .cal_offset = { 0x25, 0x28 },
1305561538f7SBalsam CHIHI .lvts_sensor = {
1306561538f7SBalsam CHIHI { .dt_id = MT8195_AP_VPU0 },
1307561538f7SBalsam CHIHI { .dt_id = MT8195_AP_VPU1 }
1308561538f7SBalsam CHIHI },
1309561538f7SBalsam CHIHI .num_lvts_sensor = 2,
1310561538f7SBalsam CHIHI .offset = 0x0,
1311561538f7SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1312561538f7SBalsam CHIHI },
1313561538f7SBalsam CHIHI {
1314561538f7SBalsam CHIHI .cal_offset = { 0x2e, 0x31 },
1315561538f7SBalsam CHIHI .lvts_sensor = {
1316561538f7SBalsam CHIHI { .dt_id = MT8195_AP_GPU0 },
1317561538f7SBalsam CHIHI { .dt_id = MT8195_AP_GPU1 }
1318561538f7SBalsam CHIHI },
1319561538f7SBalsam CHIHI .num_lvts_sensor = 2,
1320561538f7SBalsam CHIHI .offset = 0x100,
1321561538f7SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1322561538f7SBalsam CHIHI },
1323561538f7SBalsam CHIHI {
1324561538f7SBalsam CHIHI .cal_offset = { 0x37, 0x3a, 0x3d },
1325561538f7SBalsam CHIHI .lvts_sensor = {
1326561538f7SBalsam CHIHI { .dt_id = MT8195_AP_VDEC },
1327561538f7SBalsam CHIHI { .dt_id = MT8195_AP_IMG },
1328561538f7SBalsam CHIHI { .dt_id = MT8195_AP_INFRA },
1329561538f7SBalsam CHIHI },
1330561538f7SBalsam CHIHI .num_lvts_sensor = 3,
1331561538f7SBalsam CHIHI .offset = 0x200,
1332561538f7SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1333561538f7SBalsam CHIHI },
1334561538f7SBalsam CHIHI {
1335561538f7SBalsam CHIHI .cal_offset = { 0x43, 0x46 },
1336561538f7SBalsam CHIHI .lvts_sensor = {
1337561538f7SBalsam CHIHI { .dt_id = MT8195_AP_CAM0 },
1338561538f7SBalsam CHIHI { .dt_id = MT8195_AP_CAM1 }
1339561538f7SBalsam CHIHI },
1340561538f7SBalsam CHIHI .num_lvts_sensor = 2,
1341561538f7SBalsam CHIHI .offset = 0x300,
1342561538f7SBalsam CHIHI .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
1343561538f7SBalsam CHIHI }
1344561538f7SBalsam CHIHI };
1345561538f7SBalsam CHIHI
1346f5f633b1SBalsam CHIHI static const struct lvts_data mt8195_lvts_mcu_data = {
1347561538f7SBalsam CHIHI .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
1348561538f7SBalsam CHIHI .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
1349561538f7SBalsam CHIHI };
1350561538f7SBalsam CHIHI
1351561538f7SBalsam CHIHI static const struct lvts_data mt8195_lvts_ap_data = {
1352561538f7SBalsam CHIHI .lvts_ctrl = mt8195_lvts_ap_data_ctrl,
1353561538f7SBalsam CHIHI .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
1354f5f633b1SBalsam CHIHI };
1355f5f633b1SBalsam CHIHI
1356f5f633b1SBalsam CHIHI static const struct of_device_id lvts_of_match[] = {
1357f5f633b1SBalsam CHIHI { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
1358561538f7SBalsam CHIHI { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
1359f5f633b1SBalsam CHIHI {},
1360f5f633b1SBalsam CHIHI };
1361f5f633b1SBalsam CHIHI MODULE_DEVICE_TABLE(of, lvts_of_match);
1362f5f633b1SBalsam CHIHI
1363f5f633b1SBalsam CHIHI static struct platform_driver lvts_driver = {
1364f5f633b1SBalsam CHIHI .probe = lvts_probe,
1365f5f633b1SBalsam CHIHI .remove = lvts_remove,
1366f5f633b1SBalsam CHIHI .driver = {
1367f5f633b1SBalsam CHIHI .name = "mtk-lvts-thermal",
1368f5f633b1SBalsam CHIHI .of_match_table = lvts_of_match,
1369f5f633b1SBalsam CHIHI },
1370f5f633b1SBalsam CHIHI };
1371f5f633b1SBalsam CHIHI module_platform_driver(lvts_driver);
1372f5f633b1SBalsam CHIHI
1373f5f633b1SBalsam CHIHI MODULE_AUTHOR("Balsam CHIHI <bchihi@baylibre.com>");
1374f5f633b1SBalsam CHIHI MODULE_DESCRIPTION("MediaTek LVTS Thermal Driver");
1375f5f633b1SBalsam CHIHI MODULE_LICENSE("GPL");
1376