thermal-scmi.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-11-26 GuEe-GUI first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #define DBG_TAG "thermal.scmi"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. struct scmi_thermal
  16. {
  17. struct rt_thermal_zone_device parent;
  18. rt_uint32_t sensor_id;
  19. rt_uint32_t scale;
  20. struct rt_scmi_device *sdev;
  21. };
  22. #define raw_to_scmi_thermal(raw) rt_container_of(raw, struct scmi_thermal, parent)
  23. static rt_err_t scmi_thermal_zone_get_temp(struct rt_thermal_zone_device *zdev,
  24. int *out_temp)
  25. {
  26. int scale;
  27. rt_err_t err;
  28. rt_uint64_t value, factor = 1;
  29. struct scmi_thermal *st = raw_to_scmi_thermal(zdev);
  30. struct scmi_sensor_reading_in reading_in =
  31. {
  32. .id = rt_cpu_to_le32(st->sensor_id),
  33. .flags = rt_cpu_to_le32(0),
  34. };
  35. struct scmi_sensor_reading_out reading_out;
  36. struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_SENSOR_READING_GET, &reading_in, &reading_out);
  37. if ((err = rt_scmi_process_msg(st->sdev, &msg)))
  38. {
  39. return err;
  40. }
  41. value = rt_le32_to_cpu(reading_out.value_high);
  42. value <<= 32;
  43. value |= rt_le32_to_cpu(reading_out.value_low);
  44. scale = st->scale + 3;
  45. if (scale == 0)
  46. {
  47. goto _end;
  48. }
  49. if (scale > 19 || scale < -19)
  50. {
  51. return -RT_EIO;
  52. }
  53. for (int i = 0; i < rt_abs(scale); i++)
  54. {
  55. factor *= 10;
  56. }
  57. if (scale > 0)
  58. {
  59. value *= factor;
  60. }
  61. else
  62. {
  63. value = rt_div_u64(value, factor);
  64. }
  65. _end:
  66. *out_temp = (int)value;
  67. return err;
  68. }
  69. const static struct rt_thermal_zone_ops scmi_thermal_zone_ops =
  70. {
  71. .get_temp = scmi_thermal_zone_get_temp,
  72. };
  73. static rt_err_t scmi_thermal_probe(struct rt_scmi_device *sdev)
  74. {
  75. rt_err_t err;
  76. struct scmi_sensor_attributes attr = {};
  77. struct scmi_sensor_description_get_out *desc_out;
  78. struct rt_scmi_msg msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &attr);
  79. if ((err = rt_scmi_process_msg(sdev, &msg)))
  80. {
  81. return err;
  82. }
  83. desc_out = rt_malloc(sizeof(*desc_out) + sizeof(desc_out->desc[0]));
  84. if (!desc_out)
  85. {
  86. return -RT_ENOMEM;
  87. }
  88. for (int i = 0, ts_nr = 0; i < attr.num_sensors; ++i)
  89. {
  90. struct scmi_thermal *st;
  91. struct rt_thermal_zone_device *tz;
  92. struct scmi_sensor_description_get_in desc_in;
  93. desc_in.desc_index = i;
  94. msg = RT_SCMI_MSG_IN_OUT(SCMI_SENSOR_DESCRIPTION_GET, &desc_in, desc_out);
  95. if ((err = rt_scmi_process_msg(sdev, &msg)))
  96. {
  97. goto _end;
  98. }
  99. if (SCMI_SENSOR_TYPE(rt_le32_to_cpu(desc_out->desc[0].attributes_high)) !=
  100. SCMI_SENSOR_TYPE_TEMPERATURE_C)
  101. {
  102. continue;
  103. }
  104. if (!(st = rt_calloc(1, sizeof(*st))))
  105. {
  106. err = -RT_ENOMEM;
  107. goto _end;
  108. }
  109. st->sdev = sdev;
  110. st->sensor_id = rt_le32_to_cpu(desc_out->desc[0].id);
  111. st->scale = SCMI_SENSOR_SCALE(desc_out->desc[0].attributes_high);
  112. tz = &st->parent;
  113. tz->zone_id = ts_nr;
  114. tz->ops = &scmi_thermal_zone_ops;
  115. tz->parent.ofw_node = sdev->parent.ofw_node;
  116. rt_dm_dev_set_name(&tz->parent, "scmi-%s", desc_out->desc[0].name);
  117. rt_thermal_zone_device_register(tz);
  118. ++ts_nr;
  119. }
  120. _end:
  121. rt_free(desc_out);
  122. return err;
  123. }
  124. static const struct rt_scmi_device_id scmi_thermal_ids[] =
  125. {
  126. { SCMI_PROTOCOL_ID_SENSOR, "thermal" },
  127. { /* sentinel */ },
  128. };
  129. static struct rt_scmi_driver scmi_thermal_driver =
  130. {
  131. .name = "thermal-scmi",
  132. .ids = scmi_thermal_ids,
  133. .probe = scmi_thermal_probe,
  134. };
  135. RT_SCMI_DRIVER_EXPORT(scmi_thermal_driver);