Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Amlogic Thermal Sensor Driver
0004  *
0005  * Copyright (C) 2017 Huan Biao <huan.biao@amlogic.com>
0006  * Copyright (C) 2019 Guillaume La Roque <glaroque@baylibre.com>
0007  *
0008  * Register value to celsius temperature formulas:
0009  *  Read_Val        m * U
0010  * U = ---------, Uptat = ---------
0011  *  2^16          1 + n * U
0012  *
0013  * Temperature = A * ( Uptat + u_efuse / 2^16 )- B
0014  *
0015  *  A B m n : calibration parameters
0016  *  u_efuse : fused calibration value, it's a signed 16 bits value
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  * struct amlogic_thermal_soc_calib_data
0071  * @A: calibration parameters
0072  * @B: calibration parameters
0073  * @m: calibration parameters
0074  * @n: calibration parameters
0075  *
0076  * This structure is required for configuration of amlogic thermal driver.
0077  */
0078 struct amlogic_thermal_soc_calib_data {
0079     int A;
0080     int B;
0081     int m;
0082     int n;
0083 };
0084 
0085 /**
0086  * struct amlogic_thermal_data
0087  * @u_efuse_off: register offset to read fused calibration value
0088  * @calibration_parameters: calibration parameters structure pointer
0089  * @regmap_config: regmap config for the device
0090  * This structure is required for configuration of amlogic thermal driver.
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  * Calculate a temperature value from a temperature code.
0110  * The unit of the temperature is degree milliCelsius.
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     { /* sentinel */ }
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");