thermal_of.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * of-thermal.c - Generic Thermal Management device tree support.
  4. *
  5. * Copyright (C) 2013 Texas Instruments
  6. * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
  7. */
  8. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9. #include <linux/err.h>
  10. #include <linux/export.h>
  11. #include <linux/of.h>
  12. #include <linux/slab.h>
  13. #include <linux/thermal.h>
  14. #include <linux/types.h>
  15. #include <linux/string.h>
  16. #include "thermal_core.h"
  17. /*** functions parsing device tree nodes ***/
  18. /*
  19. * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
  20. * into the device tree binding of 'trip', property type.
  21. */
  22. static const char * const trip_types[] = {
  23. [THERMAL_TRIP_ACTIVE] = "active",
  24. [THERMAL_TRIP_PASSIVE] = "passive",
  25. [THERMAL_TRIP_HOT] = "hot",
  26. [THERMAL_TRIP_CRITICAL] = "critical",
  27. };
  28. /**
  29. * thermal_of_get_trip_type - Get phy mode for given device_node
  30. * @np: Pointer to the given device_node
  31. * @type: Pointer to resulting trip type
  32. *
  33. * The function gets trip type string from property 'type',
  34. * and store its index in trip_types table in @type,
  35. *
  36. * Return: 0 on success, or errno in error case.
  37. */
  38. static int thermal_of_get_trip_type(struct device_node *np,
  39. enum thermal_trip_type *type)
  40. {
  41. const char *t;
  42. int err, i;
  43. err = of_property_read_string(np, "type", &t);
  44. if (err < 0)
  45. return err;
  46. for (i = 0; i < ARRAY_SIZE(trip_types); i++)
  47. if (!strcasecmp(t, trip_types[i])) {
  48. *type = i;
  49. return 0;
  50. }
  51. return -ENODEV;
  52. }
  53. static int thermal_of_populate_trip(struct device_node *np,
  54. struct thermal_trip *trip)
  55. {
  56. int prop;
  57. int ret;
  58. ret = of_property_read_u32(np, "temperature", &prop);
  59. if (ret < 0) {
  60. pr_err("missing temperature property\n");
  61. return ret;
  62. }
  63. trip->temperature = prop;
  64. ret = of_property_read_u32(np, "hysteresis", &prop);
  65. if (ret < 0) {
  66. pr_err("missing hysteresis property\n");
  67. return ret;
  68. }
  69. trip->hysteresis = prop;
  70. ret = thermal_of_get_trip_type(np, &trip->type);
  71. if (ret < 0) {
  72. pr_err("wrong trip type property\n");
  73. return ret;
  74. }
  75. trip->flags = THERMAL_TRIP_FLAG_RW_TEMP;
  76. trip->priv = np;
  77. return 0;
  78. }
  79. static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
  80. {
  81. int ret, count;
  82. *ntrips = 0;
  83. struct device_node *trips __free(device_node) = of_get_child_by_name(np, "trips");
  84. if (!trips)
  85. return NULL;
  86. count = of_get_child_count(trips);
  87. if (!count)
  88. return NULL;
  89. struct thermal_trip *tt __free(kfree) = kzalloc_objs(*tt, count);
  90. if (!tt)
  91. return ERR_PTR(-ENOMEM);
  92. count = 0;
  93. for_each_child_of_node_scoped(trips, trip) {
  94. ret = thermal_of_populate_trip(trip, &tt[count++]);
  95. if (ret)
  96. return ERR_PTR(ret);
  97. }
  98. *ntrips = count;
  99. return no_free_ptr(tt);
  100. }
  101. static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id)
  102. {
  103. struct of_phandle_args sensor_specs;
  104. struct device_node *np __free(device_node) = of_find_node_by_name(NULL, "thermal-zones");
  105. if (!np) {
  106. pr_debug("No thermal zones description\n");
  107. return ERR_PTR(-ENODEV);
  108. }
  109. /*
  110. * Search for each thermal zone, a defined sensor
  111. * corresponding to the one passed as parameter
  112. */
  113. for_each_available_child_of_node_scoped(np, child) {
  114. int count, i;
  115. count = of_count_phandle_with_args(child, "thermal-sensors",
  116. "#thermal-sensor-cells");
  117. if (count <= 0) {
  118. pr_err("%pOFn: missing thermal sensor\n", child);
  119. return ERR_PTR(-EINVAL);
  120. }
  121. for (i = 0; i < count; i++) {
  122. int ret;
  123. ret = of_parse_phandle_with_args(child, "thermal-sensors",
  124. "#thermal-sensor-cells",
  125. i, &sensor_specs);
  126. if (ret < 0) {
  127. pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", child, ret);
  128. return ERR_PTR(ret);
  129. }
  130. of_node_put(sensor_specs.np);
  131. if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
  132. sensor_specs.args[0] : 0)) {
  133. pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, child);
  134. return no_free_ptr(child);
  135. }
  136. }
  137. }
  138. return ERR_PTR(-ENODEV);
  139. }
  140. static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdelay)
  141. {
  142. int ret;
  143. ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
  144. if (ret == -EINVAL) {
  145. *pdelay = 0;
  146. } else if (ret < 0) {
  147. pr_err("%pOFn: Couldn't get polling-delay-passive: %d\n", np, ret);
  148. return ret;
  149. }
  150. ret = of_property_read_u32(np, "polling-delay", delay);
  151. if (ret == -EINVAL) {
  152. *delay = 0;
  153. } else if (ret < 0) {
  154. pr_err("%pOFn: Couldn't get polling-delay: %d\n", np, ret);
  155. return ret;
  156. }
  157. return 0;
  158. }
  159. static void thermal_of_parameters_init(struct device_node *np,
  160. struct thermal_zone_params *tzp)
  161. {
  162. int coef[2];
  163. int ncoef = ARRAY_SIZE(coef);
  164. int prop, ret;
  165. tzp->no_hwmon = true;
  166. if (!of_property_read_u32(np, "sustainable-power", &prop))
  167. tzp->sustainable_power = prop;
  168. /*
  169. * For now, the thermal framework supports only one sensor per
  170. * thermal zone. Thus, we are considering only the first two
  171. * values as slope and offset.
  172. */
  173. ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
  174. if (ret) {
  175. coef[0] = 1;
  176. coef[1] = 0;
  177. }
  178. tzp->slope = coef[0];
  179. tzp->offset = coef[1];
  180. }
  181. static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
  182. {
  183. struct device_node *np, *tz_np;
  184. np = of_find_node_by_name(NULL, "thermal-zones");
  185. if (!np)
  186. return ERR_PTR(-ENODEV);
  187. tz_np = of_get_child_by_name(np, tz->type);
  188. of_node_put(np);
  189. if (!tz_np)
  190. return ERR_PTR(-ENODEV);
  191. return tz_np;
  192. }
  193. static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
  194. struct thermal_cooling_device *cdev,
  195. struct cooling_spec *c)
  196. {
  197. struct of_phandle_args cooling_spec;
  198. int ret, weight = THERMAL_WEIGHT_DEFAULT;
  199. of_property_read_u32(map_np, "contribution", &weight);
  200. ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
  201. index, &cooling_spec);
  202. if (ret < 0) {
  203. pr_err("Invalid cooling-device entry\n");
  204. return false;
  205. }
  206. of_node_put(cooling_spec.np);
  207. if (cooling_spec.args_count < 2) {
  208. pr_err("wrong reference to cooling device, missing limits\n");
  209. return false;
  210. }
  211. if (cooling_spec.np != cdev->np)
  212. return false;
  213. c->lower = cooling_spec.args[0];
  214. c->upper = cooling_spec.args[1];
  215. c->weight = weight;
  216. return true;
  217. }
  218. static bool thermal_of_cm_lookup(struct device_node *cm_np,
  219. const struct thermal_trip *trip,
  220. struct thermal_cooling_device *cdev,
  221. struct cooling_spec *c)
  222. {
  223. for_each_child_of_node_scoped(cm_np, child) {
  224. int count, i;
  225. struct device_node *tr_np __free(device_node) =
  226. of_parse_phandle(child, "trip", 0);
  227. if (tr_np != trip->priv)
  228. continue;
  229. /* The trip has been found, look up the cdev. */
  230. count = of_count_phandle_with_args(child, "cooling-device",
  231. "#cooling-cells");
  232. if (count <= 0)
  233. pr_err("Add a cooling_device property with at least one device\n");
  234. for (i = 0; i < count; i++) {
  235. if (thermal_of_get_cooling_spec(child, i, cdev, c))
  236. return true;
  237. }
  238. }
  239. return false;
  240. }
  241. static bool thermal_of_should_bind(struct thermal_zone_device *tz,
  242. const struct thermal_trip *trip,
  243. struct thermal_cooling_device *cdev,
  244. struct cooling_spec *c)
  245. {
  246. struct device_node *tz_np, *cm_np;
  247. bool result = false;
  248. tz_np = thermal_of_zone_get_by_name(tz);
  249. if (IS_ERR(tz_np)) {
  250. pr_err("Failed to get node tz by name\n");
  251. return false;
  252. }
  253. cm_np = of_get_child_by_name(tz_np, "cooling-maps");
  254. if (!cm_np)
  255. goto out;
  256. /* Look up the trip and the cdev in the cooling maps. */
  257. result = thermal_of_cm_lookup(cm_np, trip, cdev, c);
  258. of_node_put(cm_np);
  259. out:
  260. of_node_put(tz_np);
  261. return result;
  262. }
  263. /**
  264. * thermal_of_zone_unregister - Cleanup the specific allocated ressources
  265. *
  266. * This function disables the thermal zone and frees the different
  267. * ressources allocated specific to the thermal OF.
  268. *
  269. * @tz: a pointer to the thermal zone structure
  270. */
  271. static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
  272. {
  273. thermal_zone_device_disable(tz);
  274. thermal_zone_device_unregister(tz);
  275. }
  276. /**
  277. * thermal_of_zone_register - Register a thermal zone with device node
  278. * sensor
  279. *
  280. * The thermal_of_zone_register() parses a device tree given a device
  281. * node sensor and identifier. It searches for the thermal zone
  282. * associated to the couple sensor/id and retrieves all the thermal
  283. * zone properties and registers new thermal zone with those
  284. * properties.
  285. *
  286. * @sensor: A device node pointer corresponding to the sensor in the device tree
  287. * @id: An integer as sensor identifier
  288. * @data: A private data to be stored in the thermal zone dedicated private area
  289. * @ops: A set of thermal sensor ops
  290. *
  291. * Return: a valid thermal zone structure pointer on success.
  292. * - EINVAL: if the device tree thermal description is malformed
  293. * - ENOMEM: if one structure can not be allocated
  294. * - Other negative errors are returned by the underlying called functions
  295. */
  296. static struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data,
  297. const struct thermal_zone_device_ops *ops)
  298. {
  299. struct thermal_zone_device_ops of_ops = *ops;
  300. struct thermal_zone_device *tz;
  301. struct thermal_trip *trips;
  302. struct thermal_zone_params tzp = {};
  303. struct device_node *np;
  304. const char *action;
  305. int delay, pdelay;
  306. int ntrips;
  307. int ret;
  308. np = of_thermal_zone_find(sensor, id);
  309. if (IS_ERR(np)) {
  310. if (PTR_ERR(np) != -ENODEV)
  311. pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
  312. return ERR_CAST(np);
  313. }
  314. trips = thermal_of_trips_init(np, &ntrips);
  315. if (IS_ERR(trips)) {
  316. pr_err("Failed to parse trip points for %pOFn id=%d\n", sensor, id);
  317. ret = PTR_ERR(trips);
  318. goto out_of_node_put;
  319. }
  320. if (!trips)
  321. pr_info("No trip points found for %pOFn id=%d\n", sensor, id);
  322. ret = thermal_of_monitor_init(np, &delay, &pdelay);
  323. if (ret) {
  324. pr_err("Failed to initialize monitoring delays from %pOFn\n", np);
  325. goto out_kfree_trips;
  326. }
  327. thermal_of_parameters_init(np, &tzp);
  328. of_ops.should_bind = thermal_of_should_bind;
  329. ret = of_property_read_string(np, "critical-action", &action);
  330. if (!ret && !of_ops.critical) {
  331. if (!strcasecmp(action, "reboot"))
  332. of_ops.critical = thermal_zone_device_critical_reboot;
  333. else if (!strcasecmp(action, "shutdown"))
  334. of_ops.critical = thermal_zone_device_critical_shutdown;
  335. }
  336. tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
  337. data, &of_ops, &tzp,
  338. pdelay, delay);
  339. if (IS_ERR(tz)) {
  340. ret = PTR_ERR(tz);
  341. pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret);
  342. goto out_kfree_trips;
  343. }
  344. of_node_put(np);
  345. kfree(trips);
  346. ret = thermal_zone_device_enable(tz);
  347. if (ret) {
  348. pr_err("Failed to enabled thermal zone '%s', id=%d: %d\n",
  349. tz->type, tz->id, ret);
  350. thermal_of_zone_unregister(tz);
  351. return ERR_PTR(ret);
  352. }
  353. return tz;
  354. out_kfree_trips:
  355. kfree(trips);
  356. out_of_node_put:
  357. of_node_put(np);
  358. return ERR_PTR(ret);
  359. }
  360. static void devm_thermal_of_zone_release(struct device *dev, void *res)
  361. {
  362. thermal_of_zone_unregister(*(struct thermal_zone_device **)res);
  363. }
  364. static int devm_thermal_of_zone_match(struct device *dev, void *res,
  365. void *data)
  366. {
  367. struct thermal_zone_device **r = res;
  368. if (WARN_ON(!r || !*r))
  369. return 0;
  370. return *r == data;
  371. }
  372. /**
  373. * devm_thermal_of_zone_register - register a thermal tied with the sensor life cycle
  374. *
  375. * This function is the device version of the thermal_of_zone_register() function.
  376. *
  377. * @dev: a device structure pointer to sensor to be tied with the thermal zone OF life cycle
  378. * @sensor_id: the sensor identifier
  379. * @data: a pointer to a private data to be stored in the thermal zone 'devdata' field
  380. * @ops: a pointer to the ops structure associated with the sensor
  381. */
  382. struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int sensor_id, void *data,
  383. const struct thermal_zone_device_ops *ops)
  384. {
  385. struct thermal_zone_device **ptr, *tzd;
  386. ptr = devres_alloc(devm_thermal_of_zone_release, sizeof(*ptr),
  387. GFP_KERNEL);
  388. if (!ptr)
  389. return ERR_PTR(-ENOMEM);
  390. tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops);
  391. if (IS_ERR(tzd)) {
  392. devres_free(ptr);
  393. return tzd;
  394. }
  395. *ptr = tzd;
  396. devres_add(dev, ptr);
  397. return tzd;
  398. }
  399. EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register);
  400. /**
  401. * devm_thermal_of_zone_unregister - Resource managed version of
  402. * thermal_of_zone_unregister().
  403. * @dev: Device for which which resource was allocated.
  404. * @tz: a pointer to struct thermal_zone where the sensor is registered.
  405. *
  406. * This function removes the sensor callbacks and private data from the
  407. * thermal zone device registered with devm_thermal_zone_of_sensor_register()
  408. * API. It will also silent the zone by remove the .get_temp() and .get_trend()
  409. * thermal zone device callbacks.
  410. * Normally this function will not need to be called and the resource
  411. * management code will ensure that the resource is freed.
  412. */
  413. void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz)
  414. {
  415. WARN_ON(devres_release(dev, devm_thermal_of_zone_release,
  416. devm_thermal_of_zone_match, tz));
  417. }
  418. EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);