0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/bitfield.h>
0020 #include <linux/clk.h>
0021 #include <linux/io.h>
0022 #include <linux/mfd/syscon.h>
0023 #include <linux/module.h>
0024 #include <linux/of.h>
0025 #include <linux/of_address.h>
0026 #include <linux/of_device.h>
0027 #include <linux/platform_device.h>
0028 #include <linux/regmap.h>
0029 #include <linux/thermal.h>
0030
0031 #include "thermal_core.h"
0032 #include "thermal_hwmon.h"
0033
0034 #define TSENSOR_CFG_REG1 0x4
0035 #define TSENSOR_CFG_REG1_RSET_VBG BIT(12)
0036 #define TSENSOR_CFG_REG1_RSET_ADC BIT(11)
0037 #define TSENSOR_CFG_REG1_VCM_EN BIT(10)
0038 #define TSENSOR_CFG_REG1_VBG_EN BIT(9)
0039 #define TSENSOR_CFG_REG1_OUT_CTL BIT(6)
0040 #define TSENSOR_CFG_REG1_FILTER_EN BIT(5)
0041 #define TSENSOR_CFG_REG1_DEM_EN BIT(3)
0042 #define TSENSOR_CFG_REG1_CH_SEL GENMASK(1, 0)
0043 #define TSENSOR_CFG_REG1_ENABLE \
0044 (TSENSOR_CFG_REG1_FILTER_EN | \
0045 TSENSOR_CFG_REG1_VCM_EN | \
0046 TSENSOR_CFG_REG1_VBG_EN | \
0047 TSENSOR_CFG_REG1_DEM_EN | \
0048 TSENSOR_CFG_REG1_CH_SEL)
0049
0050 #define TSENSOR_STAT0 0x40
0051
0052 #define TSENSOR_STAT9 0x64
0053
0054 #define TSENSOR_READ_TEMP_MASK GENMASK(15, 0)
0055 #define TSENSOR_TEMP_MASK GENMASK(11, 0)
0056
0057 #define TSENSOR_TRIM_SIGN_MASK BIT(15)
0058 #define TSENSOR_TRIM_TEMP_MASK GENMASK(14, 0)
0059 #define TSENSOR_TRIM_VERSION_MASK GENMASK(31, 24)
0060
0061 #define TSENSOR_TRIM_VERSION(_version) \
0062 FIELD_GET(TSENSOR_TRIM_VERSION_MASK, _version)
0063
0064 #define TSENSOR_TRIM_CALIB_VALID_MASK (GENMASK(3, 2) | BIT(7))
0065
0066 #define TSENSOR_CALIB_OFFSET 1
0067 #define TSENSOR_CALIB_SHIFT 4
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 struct amlogic_thermal_soc_calib_data {
0079 int A;
0080 int B;
0081 int m;
0082 int n;
0083 };
0084
0085
0086
0087
0088
0089
0090
0091
0092 struct amlogic_thermal_data {
0093 int u_efuse_off;
0094 const struct amlogic_thermal_soc_calib_data *calibration_parameters;
0095 const struct regmap_config *regmap_config;
0096 };
0097
0098 struct amlogic_thermal {
0099 struct platform_device *pdev;
0100 const struct amlogic_thermal_data *data;
0101 struct regmap *regmap;
0102 struct regmap *sec_ao_map;
0103 struct clk *clk;
0104 struct thermal_zone_device *tzd;
0105 u32 trim_info;
0106 };
0107
0108
0109
0110
0111
0112 static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata,
0113 int temp_code)
0114 {
0115 const struct amlogic_thermal_soc_calib_data *param =
0116 pdata->data->calibration_parameters;
0117 int temp;
0118 s64 factor, Uptat, uefuse;
0119
0120 uefuse = pdata->trim_info & TSENSOR_TRIM_SIGN_MASK ?
0121 ~(pdata->trim_info & TSENSOR_TRIM_TEMP_MASK) + 1 :
0122 (pdata->trim_info & TSENSOR_TRIM_TEMP_MASK);
0123
0124 factor = param->n * temp_code;
0125 factor = div_s64(factor, 100);
0126
0127 Uptat = temp_code * param->m;
0128 Uptat = div_s64(Uptat, 100);
0129 Uptat = Uptat * BIT(16);
0130 Uptat = div_s64(Uptat, BIT(16) + factor);
0131
0132 temp = (Uptat + uefuse) * param->A;
0133 temp = div_s64(temp, BIT(16));
0134 temp = (temp - param->B) * 100;
0135
0136 return temp;
0137 }
0138
0139 static int amlogic_thermal_initialize(struct amlogic_thermal *pdata)
0140 {
0141 int ret = 0;
0142 int ver;
0143
0144 regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off,
0145 &pdata->trim_info);
0146
0147 ver = TSENSOR_TRIM_VERSION(pdata->trim_info);
0148
0149 if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) {
0150 ret = -EINVAL;
0151 dev_err(&pdata->pdev->dev,
0152 "tsensor thermal calibration not supported: 0x%x!\n",
0153 ver);
0154 }
0155
0156 return ret;
0157 }
0158
0159 static int amlogic_thermal_enable(struct amlogic_thermal *data)
0160 {
0161 int ret;
0162
0163 ret = clk_prepare_enable(data->clk);
0164 if (ret)
0165 return ret;
0166
0167 regmap_update_bits(data->regmap, TSENSOR_CFG_REG1,
0168 TSENSOR_CFG_REG1_ENABLE, TSENSOR_CFG_REG1_ENABLE);
0169
0170 return 0;
0171 }
0172
0173 static int amlogic_thermal_disable(struct amlogic_thermal *data)
0174 {
0175 regmap_update_bits(data->regmap, TSENSOR_CFG_REG1,
0176 TSENSOR_CFG_REG1_ENABLE, 0);
0177 clk_disable_unprepare(data->clk);
0178
0179 return 0;
0180 }
0181
0182 static int amlogic_thermal_get_temp(void *data, int *temp)
0183 {
0184 unsigned int tval;
0185 struct amlogic_thermal *pdata = data;
0186
0187 if (!data)
0188 return -EINVAL;
0189
0190 regmap_read(pdata->regmap, TSENSOR_STAT0, &tval);
0191 *temp =
0192 amlogic_thermal_code_to_millicelsius(pdata,
0193 tval & TSENSOR_READ_TEMP_MASK);
0194
0195 return 0;
0196 }
0197
0198 static const struct thermal_zone_of_device_ops amlogic_thermal_ops = {
0199 .get_temp = amlogic_thermal_get_temp,
0200 };
0201
0202 static const struct regmap_config amlogic_thermal_regmap_config_g12a = {
0203 .reg_bits = 8,
0204 .val_bits = 32,
0205 .reg_stride = 4,
0206 .max_register = TSENSOR_STAT9,
0207 };
0208
0209 static const struct amlogic_thermal_soc_calib_data amlogic_thermal_g12a = {
0210 .A = 9411,
0211 .B = 3159,
0212 .m = 424,
0213 .n = 324,
0214 };
0215
0216 static const struct amlogic_thermal_data amlogic_thermal_g12a_cpu_param = {
0217 .u_efuse_off = 0x128,
0218 .calibration_parameters = &amlogic_thermal_g12a,
0219 .regmap_config = &amlogic_thermal_regmap_config_g12a,
0220 };
0221
0222 static const struct amlogic_thermal_data amlogic_thermal_g12a_ddr_param = {
0223 .u_efuse_off = 0xf0,
0224 .calibration_parameters = &amlogic_thermal_g12a,
0225 .regmap_config = &amlogic_thermal_regmap_config_g12a,
0226 };
0227
0228 static const struct of_device_id of_amlogic_thermal_match[] = {
0229 {
0230 .compatible = "amlogic,g12a-ddr-thermal",
0231 .data = &amlogic_thermal_g12a_ddr_param,
0232 },
0233 {
0234 .compatible = "amlogic,g12a-cpu-thermal",
0235 .data = &amlogic_thermal_g12a_cpu_param,
0236 },
0237 { }
0238 };
0239 MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match);
0240
0241 static int amlogic_thermal_probe(struct platform_device *pdev)
0242 {
0243 struct amlogic_thermal *pdata;
0244 struct device *dev = &pdev->dev;
0245 void __iomem *base;
0246 int ret;
0247
0248 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
0249 if (!pdata)
0250 return -ENOMEM;
0251
0252 pdata->data = of_device_get_match_data(dev);
0253 pdata->pdev = pdev;
0254 platform_set_drvdata(pdev, pdata);
0255
0256 base = devm_platform_ioremap_resource(pdev, 0);
0257 if (IS_ERR(base))
0258 return PTR_ERR(base);
0259
0260 pdata->regmap = devm_regmap_init_mmio(dev, base,
0261 pdata->data->regmap_config);
0262 if (IS_ERR(pdata->regmap))
0263 return PTR_ERR(pdata->regmap);
0264
0265 pdata->clk = devm_clk_get(dev, NULL);
0266 if (IS_ERR(pdata->clk)) {
0267 if (PTR_ERR(pdata->clk) != -EPROBE_DEFER)
0268 dev_err(dev, "failed to get clock\n");
0269 return PTR_ERR(pdata->clk);
0270 }
0271
0272 pdata->sec_ao_map = syscon_regmap_lookup_by_phandle
0273 (pdev->dev.of_node, "amlogic,ao-secure");
0274 if (IS_ERR(pdata->sec_ao_map)) {
0275 dev_err(dev, "syscon regmap lookup failed.\n");
0276 return PTR_ERR(pdata->sec_ao_map);
0277 }
0278
0279 pdata->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
0280 0,
0281 pdata,
0282 &amlogic_thermal_ops);
0283 if (IS_ERR(pdata->tzd)) {
0284 ret = PTR_ERR(pdata->tzd);
0285 dev_err(dev, "Failed to register tsensor: %d\n", ret);
0286 return ret;
0287 }
0288
0289 if (devm_thermal_add_hwmon_sysfs(pdata->tzd))
0290 dev_warn(&pdev->dev, "Failed to add hwmon sysfs attributes\n");
0291
0292 ret = amlogic_thermal_initialize(pdata);
0293 if (ret)
0294 return ret;
0295
0296 ret = amlogic_thermal_enable(pdata);
0297
0298 return ret;
0299 }
0300
0301 static int amlogic_thermal_remove(struct platform_device *pdev)
0302 {
0303 struct amlogic_thermal *data = platform_get_drvdata(pdev);
0304
0305 return amlogic_thermal_disable(data);
0306 }
0307
0308 static int __maybe_unused amlogic_thermal_suspend(struct device *dev)
0309 {
0310 struct amlogic_thermal *data = dev_get_drvdata(dev);
0311
0312 return amlogic_thermal_disable(data);
0313 }
0314
0315 static int __maybe_unused amlogic_thermal_resume(struct device *dev)
0316 {
0317 struct amlogic_thermal *data = dev_get_drvdata(dev);
0318
0319 return amlogic_thermal_enable(data);
0320 }
0321
0322 static SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops,
0323 amlogic_thermal_suspend, amlogic_thermal_resume);
0324
0325 static struct platform_driver amlogic_thermal_driver = {
0326 .driver = {
0327 .name = "amlogic_thermal",
0328 .pm = &amlogic_thermal_pm_ops,
0329 .of_match_table = of_amlogic_thermal_match,
0330 },
0331 .probe = amlogic_thermal_probe,
0332 .remove = amlogic_thermal_remove,
0333 };
0334
0335 module_platform_driver(amlogic_thermal_driver);
0336
0337 MODULE_AUTHOR("Guillaume La Roque <glaroque@baylibre.com>");
0338 MODULE_DESCRIPTION("Amlogic thermal driver");
0339 MODULE_LICENSE("GPL v2");