0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/bitfield.h>
0009 #include <linux/clk.h>
0010 #include <linux/err.h>
0011 #include <linux/io.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_device.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/thermal.h>
0017
0018 #include "thermal_core.h"
0019
0020 #define TER 0x0
0021 #define TPS 0x4
0022 #define TRITSR 0x20
0023
0024 #define TER_ADC_PD BIT(30)
0025 #define TER_EN BIT(31)
0026 #define TRITSR_TEMP0_VAL_MASK 0xff
0027 #define TRITSR_TEMP1_VAL_MASK 0xff0000
0028
0029 #define PROBE_SEL_ALL GENMASK(31, 30)
0030
0031 #define probe_status_offset(x) (30 + x)
0032 #define SIGN_BIT BIT(7)
0033 #define TEMP_VAL_MASK GENMASK(6, 0)
0034
0035 #define VER1_TEMP_LOW_LIMIT 10000
0036 #define VER2_TEMP_LOW_LIMIT -40000
0037 #define VER2_TEMP_HIGH_LIMIT 125000
0038
0039 #define TMU_VER1 0x1
0040 #define TMU_VER2 0x2
0041
0042 struct thermal_soc_data {
0043 u32 num_sensors;
0044 u32 version;
0045 int (*get_temp)(void *, int *);
0046 };
0047
0048 struct tmu_sensor {
0049 struct imx8mm_tmu *priv;
0050 u32 hw_id;
0051 struct thermal_zone_device *tzd;
0052 };
0053
0054 struct imx8mm_tmu {
0055 void __iomem *base;
0056 struct clk *clk;
0057 const struct thermal_soc_data *socdata;
0058 struct tmu_sensor sensors[];
0059 };
0060
0061 static int imx8mm_tmu_get_temp(void *data, int *temp)
0062 {
0063 struct tmu_sensor *sensor = data;
0064 struct imx8mm_tmu *tmu = sensor->priv;
0065 u32 val;
0066
0067 val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;
0068 *temp = val * 1000;
0069 if (*temp < VER1_TEMP_LOW_LIMIT)
0070 return -EAGAIN;
0071
0072 return 0;
0073 }
0074
0075 static int imx8mp_tmu_get_temp(void *data, int *temp)
0076 {
0077 struct tmu_sensor *sensor = data;
0078 struct imx8mm_tmu *tmu = sensor->priv;
0079 unsigned long val;
0080 bool ready;
0081
0082 val = readl_relaxed(tmu->base + TRITSR);
0083 ready = test_bit(probe_status_offset(sensor->hw_id), &val);
0084 if (!ready)
0085 return -EAGAIN;
0086
0087 val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :
0088 FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);
0089 if (val & SIGN_BIT)
0090 val = (~(val & TEMP_VAL_MASK) + 1);
0091
0092 *temp = val * 1000;
0093 if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
0094 return -EAGAIN;
0095
0096 return 0;
0097 }
0098
0099 static int tmu_get_temp(void *data, int *temp)
0100 {
0101 struct tmu_sensor *sensor = data;
0102 struct imx8mm_tmu *tmu = sensor->priv;
0103
0104 return tmu->socdata->get_temp(data, temp);
0105 }
0106
0107 static struct thermal_zone_of_device_ops tmu_tz_ops = {
0108 .get_temp = tmu_get_temp,
0109 };
0110
0111 static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)
0112 {
0113 u32 val;
0114
0115 val = readl_relaxed(tmu->base + TER);
0116 val = enable ? (val | TER_EN) : (val & ~TER_EN);
0117 if (tmu->socdata->version == TMU_VER2)
0118 val = enable ? (val & ~TER_ADC_PD) : (val | TER_ADC_PD);
0119 writel_relaxed(val, tmu->base + TER);
0120 }
0121
0122 static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
0123 {
0124 u32 val;
0125
0126 val = readl_relaxed(tmu->base + TPS);
0127 val |= PROBE_SEL_ALL;
0128 writel_relaxed(val, tmu->base + TPS);
0129 }
0130
0131 static int imx8mm_tmu_probe(struct platform_device *pdev)
0132 {
0133 const struct thermal_soc_data *data;
0134 struct imx8mm_tmu *tmu;
0135 int ret;
0136 int i;
0137
0138 data = of_device_get_match_data(&pdev->dev);
0139
0140 tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
0141 data->num_sensors), GFP_KERNEL);
0142 if (!tmu)
0143 return -ENOMEM;
0144
0145 tmu->socdata = data;
0146
0147 tmu->base = devm_platform_ioremap_resource(pdev, 0);
0148 if (IS_ERR(tmu->base))
0149 return PTR_ERR(tmu->base);
0150
0151 tmu->clk = devm_clk_get(&pdev->dev, NULL);
0152 if (IS_ERR(tmu->clk))
0153 return dev_err_probe(&pdev->dev, PTR_ERR(tmu->clk),
0154 "failed to get tmu clock\n");
0155
0156 ret = clk_prepare_enable(tmu->clk);
0157 if (ret) {
0158 dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret);
0159 return ret;
0160 }
0161
0162
0163 imx8mm_tmu_enable(tmu, false);
0164
0165 for (i = 0; i < data->num_sensors; i++) {
0166 tmu->sensors[i].priv = tmu;
0167 tmu->sensors[i].tzd =
0168 devm_thermal_zone_of_sensor_register(&pdev->dev, i,
0169 &tmu->sensors[i],
0170 &tmu_tz_ops);
0171 if (IS_ERR(tmu->sensors[i].tzd)) {
0172 ret = PTR_ERR(tmu->sensors[i].tzd);
0173 dev_err(&pdev->dev,
0174 "failed to register thermal zone sensor[%d]: %d\n",
0175 i, ret);
0176 goto disable_clk;
0177 }
0178 tmu->sensors[i].hw_id = i;
0179 }
0180
0181 platform_set_drvdata(pdev, tmu);
0182
0183
0184 if (tmu->socdata->version == TMU_VER2)
0185 imx8mm_tmu_probe_sel_all(tmu);
0186
0187
0188 imx8mm_tmu_enable(tmu, true);
0189
0190 return 0;
0191
0192 disable_clk:
0193 clk_disable_unprepare(tmu->clk);
0194 return ret;
0195 }
0196
0197 static int imx8mm_tmu_remove(struct platform_device *pdev)
0198 {
0199 struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
0200
0201
0202 imx8mm_tmu_enable(tmu, false);
0203
0204 clk_disable_unprepare(tmu->clk);
0205 platform_set_drvdata(pdev, NULL);
0206
0207 return 0;
0208 }
0209
0210 static struct thermal_soc_data imx8mm_tmu_data = {
0211 .num_sensors = 1,
0212 .version = TMU_VER1,
0213 .get_temp = imx8mm_tmu_get_temp,
0214 };
0215
0216 static struct thermal_soc_data imx8mp_tmu_data = {
0217 .num_sensors = 2,
0218 .version = TMU_VER2,
0219 .get_temp = imx8mp_tmu_get_temp,
0220 };
0221
0222 static const struct of_device_id imx8mm_tmu_table[] = {
0223 { .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
0224 { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
0225 { },
0226 };
0227 MODULE_DEVICE_TABLE(of, imx8mm_tmu_table);
0228
0229 static struct platform_driver imx8mm_tmu = {
0230 .driver = {
0231 .name = "i.mx8mm_thermal",
0232 .of_match_table = imx8mm_tmu_table,
0233 },
0234 .probe = imx8mm_tmu_probe,
0235 .remove = imx8mm_tmu_remove,
0236 };
0237 module_platform_driver(imx8mm_tmu);
0238
0239 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
0240 MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");
0241 MODULE_LICENSE("GPL v2");