1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ST Thermal Sensor Driver core routines 4 * Author: Ajit Pal Singh <ajitpal.singh@st.com> 5 * 6 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_device.h> 13 14 #include "st_thermal.h" 15 #include "../thermal_hwmon.h" 16 17 /* The Thermal Framework expects millidegrees */ 18 #define mcelsius(temp) ((temp) * 1000) 19 20 /* 21 * Function to allocate regfields which are common 22 * between syscfg and memory mapped based sensors 23 */ 24 static int st_thermal_alloc_regfields(struct st_thermal_sensor *sensor) 25 { 26 struct device *dev = sensor->dev; 27 struct regmap *regmap = sensor->regmap; 28 const struct reg_field *reg_fields = sensor->cdata->reg_fields; 29 30 sensor->dcorrect = devm_regmap_field_alloc(dev, regmap, 31 reg_fields[DCORRECT]); 32 33 sensor->overflow = devm_regmap_field_alloc(dev, regmap, 34 reg_fields[OVERFLOW]); 35 36 sensor->temp_data = devm_regmap_field_alloc(dev, regmap, 37 reg_fields[DATA]); 38 39 if (IS_ERR(sensor->dcorrect) || 40 IS_ERR(sensor->overflow) || 41 IS_ERR(sensor->temp_data)) { 42 dev_err(dev, "failed to allocate common regfields\n"); 43 return -EINVAL; 44 } 45 46 return sensor->ops->alloc_regfields(sensor); 47 } 48 49 static int st_thermal_sensor_on(struct st_thermal_sensor *sensor) 50 { 51 int ret; 52 struct device *dev = sensor->dev; 53 54 ret = clk_prepare_enable(sensor->clk); 55 if (ret) { 56 dev_err(dev, "failed to enable clk\n"); 57 return ret; 58 } 59 60 ret = sensor->ops->power_ctrl(sensor, POWER_ON); 61 if (ret) { 62 dev_err(dev, "failed to power on sensor\n"); 63 clk_disable_unprepare(sensor->clk); 64 } 65 66 return ret; 67 } 68 69 static int st_thermal_sensor_off(struct st_thermal_sensor *sensor) 70 { 71 int ret; 72 73 ret = sensor->ops->power_ctrl(sensor, POWER_OFF); 74 if (ret) 75 return ret; 76 77 clk_disable_unprepare(sensor->clk); 78 79 return 0; 80 } 81 82 static int st_thermal_calibration(struct st_thermal_sensor *sensor) 83 { 84 int ret; 85 unsigned int val; 86 struct device *dev = sensor->dev; 87 88 /* Check if sensor calibration data is already written */ 89 ret = regmap_field_read(sensor->dcorrect, &val); 90 if (ret) { 91 dev_err(dev, "failed to read calibration data\n"); 92 return ret; 93 } 94 95 if (!val) { 96 /* 97 * Sensor calibration value not set by bootloader, 98 * default calibration data to be used 99 */ 100 ret = regmap_field_write(sensor->dcorrect, 101 sensor->cdata->calibration_val); 102 if (ret) 103 dev_err(dev, "failed to set calibration data\n"); 104 } 105 106 return ret; 107 } 108 109 /* Callback to get temperature from HW*/ 110 static int st_thermal_get_temp(struct thermal_zone_device *th, int *temperature) 111 { 112 struct st_thermal_sensor *sensor = thermal_zone_device_priv(th); 113 unsigned int temp; 114 unsigned int overflow; 115 int ret; 116 117 ret = regmap_field_read(sensor->overflow, &overflow); 118 if (ret) 119 return ret; 120 if (overflow) 121 return -EIO; 122 123 ret = regmap_field_read(sensor->temp_data, &temp); 124 if (ret) 125 return ret; 126 127 temp += sensor->cdata->temp_adjust_val; 128 temp = mcelsius(temp); 129 130 *temperature = temp; 131 132 return 0; 133 } 134 135 static struct thermal_zone_device_ops st_tz_ops = { 136 .get_temp = st_thermal_get_temp, 137 }; 138 139 int st_thermal_register(struct platform_device *pdev, 140 const struct of_device_id *st_thermal_of_match) 141 { 142 struct st_thermal_sensor *sensor; 143 struct device *dev = &pdev->dev; 144 struct device_node *np = dev->of_node; 145 const struct of_device_id *match; 146 147 int ret; 148 149 if (!np) { 150 dev_err(dev, "device tree node not found\n"); 151 return -EINVAL; 152 } 153 154 sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 155 if (!sensor) 156 return -ENOMEM; 157 158 sensor->dev = dev; 159 160 match = of_match_device(st_thermal_of_match, dev); 161 if (!(match && match->data)) 162 return -EINVAL; 163 164 sensor->cdata = match->data; 165 if (!sensor->cdata->ops) 166 return -EINVAL; 167 168 sensor->ops = sensor->cdata->ops; 169 170 ret = (sensor->ops->regmap_init)(sensor); 171 if (ret) 172 return ret; 173 174 ret = st_thermal_alloc_regfields(sensor); 175 if (ret) 176 return ret; 177 178 sensor->clk = devm_clk_get(dev, "thermal"); 179 if (IS_ERR(sensor->clk)) { 180 dev_err(dev, "failed to fetch clock\n"); 181 return PTR_ERR(sensor->clk); 182 } 183 184 if (sensor->ops->register_enable_irq) { 185 ret = sensor->ops->register_enable_irq(sensor); 186 if (ret) 187 return ret; 188 } 189 190 ret = st_thermal_sensor_on(sensor); 191 if (ret) 192 return ret; 193 194 ret = st_thermal_calibration(sensor); 195 if (ret) 196 goto sensor_off; 197 198 sensor->thermal_dev = 199 devm_thermal_of_zone_register(dev, 0, sensor, &st_tz_ops); 200 if (IS_ERR(sensor->thermal_dev)) { 201 dev_err(dev, "failed to register thermal of zone\n"); 202 ret = PTR_ERR(sensor->thermal_dev); 203 goto sensor_off; 204 } 205 206 platform_set_drvdata(pdev, sensor); 207 208 /* 209 * devm_thermal_of_zone_register() doesn't enable hwmon by default 210 * Enable it here 211 */ 212 devm_thermal_add_hwmon_sysfs(dev, sensor->thermal_dev); 213 214 return 0; 215 216 sensor_off: 217 st_thermal_sensor_off(sensor); 218 219 return ret; 220 } 221 EXPORT_SYMBOL_GPL(st_thermal_register); 222 223 void st_thermal_unregister(struct platform_device *pdev) 224 { 225 struct st_thermal_sensor *sensor = platform_get_drvdata(pdev); 226 227 st_thermal_sensor_off(sensor); 228 thermal_remove_hwmon_sysfs(sensor->thermal_dev); 229 devm_thermal_of_zone_unregister(sensor->dev, sensor->thermal_dev); 230 } 231 EXPORT_SYMBOL_GPL(st_thermal_unregister); 232 233 static int st_thermal_suspend(struct device *dev) 234 { 235 struct st_thermal_sensor *sensor = dev_get_drvdata(dev); 236 237 return st_thermal_sensor_off(sensor); 238 } 239 240 static int st_thermal_resume(struct device *dev) 241 { 242 int ret; 243 struct st_thermal_sensor *sensor = dev_get_drvdata(dev); 244 245 ret = st_thermal_sensor_on(sensor); 246 if (ret) 247 return ret; 248 249 ret = st_thermal_calibration(sensor); 250 if (ret) 251 return ret; 252 253 if (sensor->ops->enable_irq) { 254 ret = sensor->ops->enable_irq(sensor); 255 if (ret) 256 return ret; 257 } 258 259 return 0; 260 } 261 262 DEFINE_SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume); 263 EXPORT_SYMBOL_GPL(st_thermal_pm_ops); 264 265 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>"); 266 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver"); 267 MODULE_LICENSE("GPL v2"); 268