0006-surface-sam.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. From 1336f715db65f12890442d46d85b6afbd28ffa38 Mon Sep 17 00:00:00 2001
  2. From: Maximilian Luz <luzmaximilian@gmail.com>
  3. Date: Sun, 22 Oct 2023 14:57:11 +0200
  4. Subject: [PATCH] platform/surface: aggregator_registry: Add support for
  5. Surface Laptop Go 3
  6. Add SAM client device nodes for the Surface Laptop Go 3. It seems to use
  7. the same SAM client devices as the Surface Laptop Go 1 and 2, so re-use
  8. their node group.
  9. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  10. Patchset: surface-sam
  11. ---
  12. drivers/platform/surface/surface_aggregator_registry.c | 3 +++
  13. 1 file changed, 3 insertions(+)
  14. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  15. index 0fe5be5396525..0d8c8395c5886 100644
  16. --- a/drivers/platform/surface/surface_aggregator_registry.c
  17. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  18. @@ -367,6 +367,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
  19. /* Surface Laptop Go 2 */
  20. { "MSHW0290", (unsigned long)ssam_node_group_slg1 },
  21. + /* Surface Laptop Go 3 */
  22. + { "MSHW0440", (unsigned long)ssam_node_group_slg1 },
  23. +
  24. /* Surface Laptop Studio */
  25. { "MSHW0123", (unsigned long)ssam_node_group_sls },
  26. --
  27. 2.43.0
  28. From 04a113aa335b566860380818090ed0ce606377c0 Mon Sep 17 00:00:00 2001
  29. From: Maximilian Luz <luzmaximilian@gmail.com>
  30. Date: Mon, 20 Nov 2023 19:47:00 +0100
  31. Subject: [PATCH] platform/surface: aggregator_registry: Add support for
  32. Surface Laptop Studio 2
  33. Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The
  34. SLS2 is quite similar to the SLS1, but it does not provide the touchpad
  35. as a SAM-HID device. Therefore, add a new node group for the SLS2 and
  36. update the comments accordingly
  37. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  38. Patchset: surface-sam
  39. ---
  40. .../surface/surface_aggregator_registry.c | 25 ++++++++++++++++---
  41. 1 file changed, 21 insertions(+), 4 deletions(-)
  42. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  43. index 0d8c8395c5886..530db4db71aba 100644
  44. --- a/drivers/platform/surface/surface_aggregator_registry.c
  45. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  46. @@ -247,8 +247,8 @@ static const struct software_node *ssam_node_group_sl5[] = {
  47. NULL,
  48. };
  49. -/* Devices for Surface Laptop Studio. */
  50. -static const struct software_node *ssam_node_group_sls[] = {
  51. +/* Devices for Surface Laptop Studio 1. */
  52. +static const struct software_node *ssam_node_group_sls1[] = {
  53. &ssam_node_root,
  54. &ssam_node_bat_ac,
  55. &ssam_node_bat_main,
  56. @@ -263,6 +263,20 @@ static const struct software_node *ssam_node_group_sls[] = {
  57. NULL,
  58. };
  59. +/* Devices for Surface Laptop Studio 2. */
  60. +static const struct software_node *ssam_node_group_sls2[] = {
  61. + &ssam_node_root,
  62. + &ssam_node_bat_ac,
  63. + &ssam_node_bat_main,
  64. + &ssam_node_tmp_pprof,
  65. + &ssam_node_pos_tablet_switch,
  66. + &ssam_node_hid_sam_keyboard,
  67. + &ssam_node_hid_sam_penstash,
  68. + &ssam_node_hid_sam_sensors,
  69. + &ssam_node_hid_sam_ucm_ucsi,
  70. + NULL,
  71. +};
  72. +
  73. /* Devices for Surface Laptop Go. */
  74. static const struct software_node *ssam_node_group_slg1[] = {
  75. &ssam_node_root,
  76. @@ -370,8 +384,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
  77. /* Surface Laptop Go 3 */
  78. { "MSHW0440", (unsigned long)ssam_node_group_slg1 },
  79. - /* Surface Laptop Studio */
  80. - { "MSHW0123", (unsigned long)ssam_node_group_sls },
  81. + /* Surface Laptop Studio 1 */
  82. + { "MSHW0123", (unsigned long)ssam_node_group_sls1 },
  83. +
  84. + /* Surface Laptop Studio 2 */
  85. + { "MSHW0360", (unsigned long)ssam_node_group_sls2 },
  86. { },
  87. };
  88. --
  89. 2.43.0
  90. From 31253c1714eef54d147ff70886be3e0b86301656 Mon Sep 17 00:00:00 2001
  91. From: Ivor Wanders <ivor@iwanders.net>
  92. Date: Mon, 18 Dec 2023 19:21:32 -0500
  93. Subject: [PATCH] platform/surface: aggregator_registry: add entry for fan
  94. speed
  95. Add an entry for the fan speed function.
  96. Add this new entry to the Surface Pro 9 group.
  97. Signed-off-by: Ivor Wanders <ivor@iwanders.net>
  98. Link: https://github.com/linux-surface/kernel/pull/144
  99. Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
  100. Patchset: surface-sam
  101. ---
  102. drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++
  103. 1 file changed, 7 insertions(+)
  104. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  105. index 530db4db71aba..b0db25886c996 100644
  106. --- a/drivers/platform/surface/surface_aggregator_registry.c
  107. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  108. @@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = {
  109. .parent = &ssam_node_root,
  110. };
  111. +/* Fan speed function. */
  112. +static const struct software_node ssam_node_fan_speed = {
  113. + .name = "ssam:01:05:01:01:01",
  114. + .parent = &ssam_node_root,
  115. +};
  116. +
  117. /* Tablet-mode switch via KIP subsystem. */
  118. static const struct software_node ssam_node_kip_tablet_switch = {
  119. .name = "ssam:01:0e:01:00:01",
  120. @@ -319,6 +325,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
  121. &ssam_node_bat_ac,
  122. &ssam_node_bat_main,
  123. &ssam_node_tmp_pprof,
  124. + &ssam_node_fan_speed,
  125. &ssam_node_pos_tablet_switch,
  126. &ssam_node_hid_kip_keyboard,
  127. &ssam_node_hid_kip_penstash,
  128. --
  129. 2.43.0
  130. From ba442037211d245c84dcd4cd1ec81a09468305e6 Mon Sep 17 00:00:00 2001
  131. From: Ivor Wanders <ivor@iwanders.net>
  132. Date: Thu, 30 Nov 2023 20:20:24 -0500
  133. Subject: [PATCH] hwmon: add fan speed monitoring driver for Surface devices
  134. Adds a driver that provides read only access to the fan speed for Microsoft
  135. Surface Pro devices. The fan speed is always regulated by the EC and cannot
  136. be influenced directly.
  137. Signed-off-by: Ivor Wanders <ivor@iwanders.net>
  138. Link: https://github.com/linux-surface/kernel/pull/144
  139. Patchset: surface-sam
  140. ---
  141. Documentation/hwmon/index.rst | 1 +
  142. Documentation/hwmon/surface_fan.rst | 25 ++++++++
  143. MAINTAINERS | 8 +++
  144. drivers/hwmon/Kconfig | 13 ++++
  145. drivers/hwmon/Makefile | 1 +
  146. drivers/hwmon/surface_fan.c | 93 +++++++++++++++++++++++++++++
  147. 6 files changed, 141 insertions(+)
  148. create mode 100644 Documentation/hwmon/surface_fan.rst
  149. create mode 100644 drivers/hwmon/surface_fan.c
  150. diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
  151. index 88dadea85cfcd..266edff78972d 100644
  152. --- a/Documentation/hwmon/index.rst
  153. +++ b/Documentation/hwmon/index.rst
  154. @@ -202,6 +202,7 @@ Hardware Monitoring Kernel Drivers
  155. smsc47m1
  156. sparx5-temp
  157. stpddc60
  158. + surface_fan
  159. sy7636a-hwmon
  160. tc654
  161. tc74
  162. diff --git a/Documentation/hwmon/surface_fan.rst b/Documentation/hwmon/surface_fan.rst
  163. new file mode 100644
  164. index 0000000000000..07942574c4f0c
  165. --- /dev/null
  166. +++ b/Documentation/hwmon/surface_fan.rst
  167. @@ -0,0 +1,25 @@
  168. +.. SPDX-License-Identifier: GPL-2.0-or-later
  169. +
  170. +Kernel driver surface_fan
  171. +=========================
  172. +
  173. +Supported Devices:
  174. +
  175. + * Microsoft Surface Pro 9
  176. +
  177. +Author: Ivor Wanders <ivor@iwanders.net>
  178. +
  179. +Description
  180. +-----------
  181. +
  182. +This provides monitoring of the fan found in some Microsoft Surface Pro devices,
  183. +like the Surface Pro 9. The fan is always controlled by the onboard controller.
  184. +
  185. +Sysfs interface
  186. +---------------
  187. +
  188. +======================= ======= =========================================
  189. +Name Perm Description
  190. +======================= ======= =========================================
  191. +``fan1_input`` RO Current fan speed in RPM.
  192. +======================= ======= =========================================
  193. diff --git a/MAINTAINERS b/MAINTAINERS
  194. index dd5de540ec0b5..63c3f93279277 100644
  195. --- a/MAINTAINERS
  196. +++ b/MAINTAINERS
  197. @@ -14203,6 +14203,14 @@ F: Documentation/driver-api/surface_aggregator/clients/dtx.rst
  198. F: drivers/platform/surface/surface_dtx.c
  199. F: include/uapi/linux/surface_aggregator/dtx.h
  200. +MICROSOFT SURFACE SENSOR FAN DRIVER
  201. +M: Maximilian Luz <luzmaximilian@gmail.com>
  202. +M: Ivor Wanders <ivor@iwanders.net>
  203. +L: linux-hwmon@vger.kernel.org
  204. +S: Maintained
  205. +F: Documentation/hwmon/surface_fan.rst
  206. +F: drivers/hwmon/surface_fan.c
  207. +
  208. MICROSOFT SURFACE GPE LID SUPPORT DRIVER
  209. M: Maximilian Luz <luzmaximilian@gmail.com>
  210. L: platform-driver-x86@vger.kernel.org
  211. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
  212. index ec38c88921589..b5267a2fbe5f3 100644
  213. --- a/drivers/hwmon/Kconfig
  214. +++ b/drivers/hwmon/Kconfig
  215. @@ -1961,6 +1961,19 @@ config SENSORS_SFCTEMP
  216. This driver can also be built as a module. If so, the module
  217. will be called sfctemp.
  218. +config SENSORS_SURFACE_FAN
  219. + tristate "Surface Fan Driver"
  220. + depends on SURFACE_AGGREGATOR
  221. + help
  222. + Driver that provides monitoring of the fan on Surface Pro devices that
  223. + have a fan, like the Surface Pro 9.
  224. +
  225. + This makes the fan's current speed accessible through the hwmon
  226. + system. It does not provide control over the fan, the firmware is
  227. + responsible for that, this driver merely provides monitoring.
  228. +
  229. + Select M or Y here, if you want to be able to read the fan's speed.
  230. +
  231. config SENSORS_ADC128D818
  232. tristate "Texas Instruments ADC128D818"
  233. depends on I2C
  234. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
  235. index 4ac9452b54304..208f7345f296e 100644
  236. --- a/drivers/hwmon/Makefile
  237. +++ b/drivers/hwmon/Makefile
  238. @@ -198,6 +198,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
  239. obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
  240. obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
  241. obj-$(CONFIG_SENSORS_STTS751) += stts751.o
  242. +obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o
  243. obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o
  244. obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
  245. obj-$(CONFIG_SENSORS_TC74) += tc74.o
  246. diff --git a/drivers/hwmon/surface_fan.c b/drivers/hwmon/surface_fan.c
  247. new file mode 100644
  248. index 0000000000000..7c2e3ae3eb40e
  249. --- /dev/null
  250. +++ b/drivers/hwmon/surface_fan.c
  251. @@ -0,0 +1,93 @@
  252. +// SPDX-License-Identifier: GPL-2.0+
  253. +/*
  254. + * Surface Fan driver for Surface System Aggregator Module. It provides access
  255. + * to the fan's rpm through the hwmon system.
  256. + *
  257. + * Copyright (C) 2023 Ivor Wanders <ivor@iwanders.net>
  258. + */
  259. +
  260. +#include <linux/hwmon.h>
  261. +#include <linux/kernel.h>
  262. +#include <linux/module.h>
  263. +#include <linux/surface_aggregator/device.h>
  264. +#include <linux/types.h>
  265. +
  266. +// SSAM
  267. +SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, {
  268. + .target_category = SSAM_SSH_TC_FAN,
  269. + .command_id = 0x01,
  270. +});
  271. +
  272. +// hwmon
  273. +umode_t surface_fan_hwmon_is_visible(const void *drvdata,
  274. + enum hwmon_sensor_types type, u32 attr,
  275. + int channel)
  276. +{
  277. + return 0444;
  278. +}
  279. +
  280. +static int surface_fan_hwmon_read(struct device *dev,
  281. + enum hwmon_sensor_types type, u32 attr,
  282. + int channel, long *val)
  283. +{
  284. + struct ssam_device *sdev = dev_get_drvdata(dev);
  285. + int ret;
  286. + __le16 value;
  287. +
  288. + ret = __ssam_fan_rpm_get(sdev, &value);
  289. + if (ret)
  290. + return ret;
  291. +
  292. + *val = le16_to_cpu(value);
  293. +
  294. + return ret;
  295. +}
  296. +
  297. +static const struct hwmon_channel_info *const surface_fan_info[] = {
  298. + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
  299. + NULL
  300. +};
  301. +
  302. +static const struct hwmon_ops surface_fan_hwmon_ops = {
  303. + .is_visible = surface_fan_hwmon_is_visible,
  304. + .read = surface_fan_hwmon_read,
  305. +};
  306. +
  307. +static const struct hwmon_chip_info surface_fan_chip_info = {
  308. + .ops = &surface_fan_hwmon_ops,
  309. + .info = surface_fan_info,
  310. +};
  311. +
  312. +static int surface_fan_probe(struct ssam_device *sdev)
  313. +{
  314. + struct device *hdev;
  315. +
  316. + hdev = devm_hwmon_device_register_with_info(&sdev->dev,
  317. + "surface_fan", sdev,
  318. + &surface_fan_chip_info,
  319. + NULL);
  320. + if (IS_ERR(hdev))
  321. + return PTR_ERR(hdev);
  322. +
  323. + return 0;
  324. +}
  325. +
  326. +static const struct ssam_device_id ssam_fan_match[] = {
  327. + { SSAM_SDEV(FAN, SAM, 0x01, 0x01) },
  328. + {},
  329. +};
  330. +MODULE_DEVICE_TABLE(ssam, ssam_fan_match);
  331. +
  332. +static struct ssam_device_driver surface_fan = {
  333. + .probe = surface_fan_probe,
  334. + .match_table = ssam_fan_match,
  335. + .driver = {
  336. + .name = "surface_fan",
  337. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  338. + },
  339. +};
  340. +module_ssam_device_driver(surface_fan);
  341. +
  342. +MODULE_AUTHOR("Ivor Wanders <ivor@iwanders.net>");
  343. +MODULE_DESCRIPTION("Fan Driver for Surface System Aggregator Module");
  344. +MODULE_LICENSE("GPL");
  345. --
  346. 2.43.0
  347. From e44dd763f976360449d9f15ed2bb756cc18d843b Mon Sep 17 00:00:00 2001
  348. From: Maximilian Luz <luzmaximilian@gmail.com>
  349. Date: Sat, 30 Dec 2023 18:07:54 +0100
  350. Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator
  351. Module
  352. Some of the newer Microsoft Surface devices (such as the Surface Book
  353. 3 and Pro 9) have thermal sensors connected via the Surface Aggregator
  354. Module (the embedded controller on those devices). Add a basic driver
  355. to read out the temperature values of those sensors.
  356. Link: https://github.com/linux-surface/surface-aggregator-module/issues/59
  357. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  358. Patchset: surface-sam
  359. ---
  360. drivers/hwmon/Kconfig | 10 +++
  361. drivers/hwmon/Makefile | 1 +
  362. drivers/hwmon/surface_temp.c | 165 +++++++++++++++++++++++++++++++++++
  363. 3 files changed, 176 insertions(+)
  364. create mode 100644 drivers/hwmon/surface_temp.c
  365. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
  366. index b5267a2fbe5f3..2eedbe85d18ab 100644
  367. --- a/drivers/hwmon/Kconfig
  368. +++ b/drivers/hwmon/Kconfig
  369. @@ -1974,6 +1974,16 @@ config SENSORS_SURFACE_FAN
  370. Select M or Y here, if you want to be able to read the fan's speed.
  371. +config SENSORS_SURFACE_TEMP
  372. + tristate "Microsoft Surface Thermal Sensor Driver"
  373. + depends on SURFACE_AGGREGATOR
  374. + help
  375. + Driver for monitoring thermal sensors connected via the Surface
  376. + Aggregator Module (embedded controller) on Microsoft Surface devices.
  377. +
  378. + This driver can also be built as a module. If so, the module
  379. + will be called surface_temp.
  380. +
  381. config SENSORS_ADC128D818
  382. tristate "Texas Instruments ADC128D818"
  383. depends on I2C
  384. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
  385. index 208f7345f296e..310d7a2e0f069 100644
  386. --- a/drivers/hwmon/Makefile
  387. +++ b/drivers/hwmon/Makefile
  388. @@ -199,6 +199,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
  389. obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
  390. obj-$(CONFIG_SENSORS_STTS751) += stts751.o
  391. obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o
  392. +obj-$(CONFIG_SENSORS_SURFACE_TEMP)+= surface_temp.o
  393. obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o
  394. obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
  395. obj-$(CONFIG_SENSORS_TC74) += tc74.o
  396. diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c
  397. new file mode 100644
  398. index 0000000000000..48c3e826713f6
  399. --- /dev/null
  400. +++ b/drivers/hwmon/surface_temp.c
  401. @@ -0,0 +1,165 @@
  402. +// SPDX-License-Identifier: GPL-2.0+
  403. +/*
  404. + * Thermal sensor subsystem driver for Surface System Aggregator Module (SSAM).
  405. + *
  406. + * Copyright (C) 2022-2023 Maximilian Luz <luzmaximilian@gmail.com>
  407. + */
  408. +
  409. +#include <linux/bitops.h>
  410. +#include <linux/hwmon.h>
  411. +#include <linux/kernel.h>
  412. +#include <linux/module.h>
  413. +#include <linux/types.h>
  414. +
  415. +#include <linux/surface_aggregator/controller.h>
  416. +#include <linux/surface_aggregator/device.h>
  417. +
  418. +
  419. +/* -- SAM interface. -------------------------------------------------------- */
  420. +
  421. +SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, {
  422. + .target_category = SSAM_SSH_TC_TMP,
  423. + .command_id = 0x04,
  424. +});
  425. +
  426. +SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, {
  427. + .target_category = SSAM_SSH_TC_TMP,
  428. + .command_id = 0x01,
  429. +});
  430. +
  431. +static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors)
  432. +{
  433. + __le16 sensors_le;
  434. + int status;
  435. +
  436. + status = __ssam_tmp_get_available_sensors(sdev, &sensors_le);
  437. + if (status)
  438. + return status;
  439. +
  440. + *sensors = le16_to_cpu(sensors_le);
  441. + return 0;
  442. +}
  443. +
  444. +static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temperature)
  445. +{
  446. + __le16 temp_le;
  447. + int status;
  448. +
  449. + status = __ssam_tmp_get_temperature(sdev->ctrl, sdev->uid.target, iid, &temp_le);
  450. + if (status)
  451. + return status;
  452. +
  453. + /* Convert 1/10 °K to 1/1000 °C */
  454. + *temperature = (le16_to_cpu(temp_le) - 2731) * 100L;
  455. + return 0;
  456. +}
  457. +
  458. +
  459. +/* -- Driver.---------------------------------------------------------------- */
  460. +
  461. +struct ssam_temp {
  462. + struct ssam_device *sdev;
  463. + s16 sensors;
  464. +};
  465. +
  466. +static umode_t ssam_temp_hwmon_is_visible(const void *data,
  467. + enum hwmon_sensor_types type,
  468. + u32 attr, int channel)
  469. +{
  470. + const struct ssam_temp *ssam_temp = data;
  471. +
  472. + if (!(ssam_temp->sensors & BIT(channel)))
  473. + return 0;
  474. +
  475. + return 0444;
  476. +}
  477. +
  478. +static int ssam_temp_hwmon_read(struct device *dev,
  479. + enum hwmon_sensor_types type,
  480. + u32 attr, int channel, long *value)
  481. +{
  482. + const struct ssam_temp *ssam_temp = dev_get_drvdata(dev);
  483. +
  484. + return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value);
  485. +}
  486. +
  487. +static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = {
  488. + HWMON_CHANNEL_INFO(chip,
  489. + HWMON_C_REGISTER_TZ),
  490. + /* We have at most 16 thermal sensor channels. */
  491. + HWMON_CHANNEL_INFO(temp,
  492. + HWMON_T_INPUT,
  493. + HWMON_T_INPUT,
  494. + HWMON_T_INPUT,
  495. + HWMON_T_INPUT,
  496. + HWMON_T_INPUT,
  497. + HWMON_T_INPUT,
  498. + HWMON_T_INPUT,
  499. + HWMON_T_INPUT,
  500. + HWMON_T_INPUT,
  501. + HWMON_T_INPUT,
  502. + HWMON_T_INPUT,
  503. + HWMON_T_INPUT,
  504. + HWMON_T_INPUT,
  505. + HWMON_T_INPUT,
  506. + HWMON_T_INPUT,
  507. + HWMON_T_INPUT),
  508. + NULL
  509. +};
  510. +
  511. +static const struct hwmon_ops ssam_temp_hwmon_ops = {
  512. + .is_visible = ssam_temp_hwmon_is_visible,
  513. + .read = ssam_temp_hwmon_read,
  514. +};
  515. +
  516. +static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = {
  517. + .ops = &ssam_temp_hwmon_ops,
  518. + .info = ssam_temp_hwmon_info,
  519. +};
  520. +
  521. +static int ssam_temp_probe(struct ssam_device *sdev)
  522. +{
  523. + struct ssam_temp *ssam_temp;
  524. + struct device *hwmon_dev;
  525. + s16 sensors;
  526. + int status;
  527. +
  528. + status = ssam_tmp_get_available_sensors(sdev, &sensors);
  529. + if (status)
  530. + return status;
  531. +
  532. + ssam_temp = devm_kzalloc(&sdev->dev, sizeof(*ssam_temp), GFP_KERNEL);
  533. + if (!ssam_temp)
  534. + return -ENOMEM;
  535. +
  536. + ssam_temp->sdev = sdev;
  537. + ssam_temp->sensors = sensors;
  538. +
  539. + hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev,
  540. + "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info,
  541. + NULL);
  542. + if (IS_ERR(hwmon_dev))
  543. + return PTR_ERR(hwmon_dev);
  544. +
  545. + return 0;
  546. +}
  547. +
  548. +static const struct ssam_device_id ssam_temp_match[] = {
  549. + { SSAM_SDEV(TMP, SAM, 0x00, 0x02) },
  550. + { },
  551. +};
  552. +MODULE_DEVICE_TABLE(ssam, ssam_temp_match);
  553. +
  554. +static struct ssam_device_driver ssam_temp = {
  555. + .probe = ssam_temp_probe,
  556. + .match_table = ssam_temp_match,
  557. + .driver = {
  558. + .name = "surface_temp",
  559. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  560. + },
  561. +};
  562. +module_ssam_device_driver(ssam_temp);
  563. +
  564. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  565. +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module");
  566. +MODULE_LICENSE("GPL");
  567. --
  568. 2.43.0
  569. From 41399077b077cff19e9b9133955ed81b6d7aa527 Mon Sep 17 00:00:00 2001
  570. From: Maximilian Luz <luzmaximilian@gmail.com>
  571. Date: Sat, 30 Dec 2023 18:12:23 +0100
  572. Subject: [PATCH] hwmon: surface_temp: Add support for sensor names
  573. The thermal subsystem of the Surface Aggregator Module allows us to
  574. query the names of the respective thermal sensors. Forward those to
  575. userspace.
  576. Signed-off-by: Ivor Wanders <ivor@iwanders.net>
  577. Co-Developed-by: Maximilian Luz <luzmaximilian@gmail.com>
  578. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  579. Patchset: surface-sam
  580. ---
  581. drivers/hwmon/surface_temp.c | 113 +++++++++++++++++++++++++++++------
  582. 1 file changed, 96 insertions(+), 17 deletions(-)
  583. diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c
  584. index 48c3e826713f6..4c08926139dbf 100644
  585. --- a/drivers/hwmon/surface_temp.c
  586. +++ b/drivers/hwmon/surface_temp.c
  587. @@ -17,6 +17,27 @@
  588. /* -- SAM interface. -------------------------------------------------------- */
  589. +/*
  590. + * Available sensors are indicated by a 16-bit bitfield, where a 1 marks the
  591. + * presence of a sensor. So we have at most 16 possible sensors/channels.
  592. + */
  593. +#define SSAM_TMP_SENSOR_MAX_COUNT 16
  594. +
  595. +/*
  596. + * All names observed so far are 6 characters long, but there's only
  597. + * zeros after the name, so perhaps they can be longer. This number reflects
  598. + * the maximum zero-padded space observed in the returned buffer.
  599. + */
  600. +#define SSAM_TMP_SENSOR_NAME_LENGTH 18
  601. +
  602. +struct ssam_tmp_get_name_rsp {
  603. + __le16 unknown1;
  604. + char unknown2;
  605. + char name[SSAM_TMP_SENSOR_NAME_LENGTH];
  606. +} __packed;
  607. +
  608. +static_assert(sizeof(struct ssam_tmp_get_name_rsp) == 21);
  609. +
  610. SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, {
  611. .target_category = SSAM_SSH_TC_TMP,
  612. .command_id = 0x04,
  613. @@ -27,6 +48,11 @@ SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, {
  614. .command_id = 0x01,
  615. });
  616. +SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_name, struct ssam_tmp_get_name_rsp, {
  617. + .target_category = SSAM_SSH_TC_TMP,
  618. + .command_id = 0x0e,
  619. +});
  620. +
  621. static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors)
  622. {
  623. __le16 sensors_le;
  624. @@ -54,12 +80,37 @@ static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temp
  625. return 0;
  626. }
  627. +static int ssam_tmp_get_name(struct ssam_device *sdev, u8 iid, char *buf, size_t buf_len)
  628. +{
  629. + struct ssam_tmp_get_name_rsp name_rsp;
  630. + int status;
  631. +
  632. + status = __ssam_tmp_get_name(sdev->ctrl, sdev->uid.target, iid, &name_rsp);
  633. + if (status)
  634. + return status;
  635. +
  636. + /*
  637. + * This should not fail unless the name in the returned struct is not
  638. + * null-terminated or someone changed something in the struct
  639. + * definitions above, since our buffer and struct have the same
  640. + * capacity by design. So if this fails blow this up with a warning.
  641. + * Since the more likely cause is that the returned string isn't
  642. + * null-terminated, we might have received garbage (as opposed to just
  643. + * an incomplete string), so also fail the function.
  644. + */
  645. + status = strscpy(buf, name_rsp.name, buf_len);
  646. + WARN_ON(status < 0);
  647. +
  648. + return status < 0 ? status : 0;
  649. +}
  650. +
  651. /* -- Driver.---------------------------------------------------------------- */
  652. struct ssam_temp {
  653. struct ssam_device *sdev;
  654. s16 sensors;
  655. + char names[SSAM_TMP_SENSOR_MAX_COUNT][SSAM_TMP_SENSOR_NAME_LENGTH];
  656. };
  657. static umode_t ssam_temp_hwmon_is_visible(const void *data,
  658. @@ -83,33 +134,47 @@ static int ssam_temp_hwmon_read(struct device *dev,
  659. return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value);
  660. }
  661. +static int ssam_temp_hwmon_read_string(struct device *dev,
  662. + enum hwmon_sensor_types type,
  663. + u32 attr, int channel, const char **str)
  664. +{
  665. + const struct ssam_temp *ssam_temp = dev_get_drvdata(dev);
  666. +
  667. + *str = ssam_temp->names[channel];
  668. + return 0;
  669. +}
  670. +
  671. static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = {
  672. HWMON_CHANNEL_INFO(chip,
  673. HWMON_C_REGISTER_TZ),
  674. - /* We have at most 16 thermal sensor channels. */
  675. + /*
  676. + * We have at most SSAM_TMP_SENSOR_MAX_COUNT = 16 thermal sensor
  677. + * channels.
  678. + */
  679. HWMON_CHANNEL_INFO(temp,
  680. - HWMON_T_INPUT,
  681. - HWMON_T_INPUT,
  682. - HWMON_T_INPUT,
  683. - HWMON_T_INPUT,
  684. - HWMON_T_INPUT,
  685. - HWMON_T_INPUT,
  686. - HWMON_T_INPUT,
  687. - HWMON_T_INPUT,
  688. - HWMON_T_INPUT,
  689. - HWMON_T_INPUT,
  690. - HWMON_T_INPUT,
  691. - HWMON_T_INPUT,
  692. - HWMON_T_INPUT,
  693. - HWMON_T_INPUT,
  694. - HWMON_T_INPUT,
  695. - HWMON_T_INPUT),
  696. + HWMON_T_INPUT | HWMON_T_LABEL,
  697. + HWMON_T_INPUT | HWMON_T_LABEL,
  698. + HWMON_T_INPUT | HWMON_T_LABEL,
  699. + HWMON_T_INPUT | HWMON_T_LABEL,
  700. + HWMON_T_INPUT | HWMON_T_LABEL,
  701. + HWMON_T_INPUT | HWMON_T_LABEL,
  702. + HWMON_T_INPUT | HWMON_T_LABEL,
  703. + HWMON_T_INPUT | HWMON_T_LABEL,
  704. + HWMON_T_INPUT | HWMON_T_LABEL,
  705. + HWMON_T_INPUT | HWMON_T_LABEL,
  706. + HWMON_T_INPUT | HWMON_T_LABEL,
  707. + HWMON_T_INPUT | HWMON_T_LABEL,
  708. + HWMON_T_INPUT | HWMON_T_LABEL,
  709. + HWMON_T_INPUT | HWMON_T_LABEL,
  710. + HWMON_T_INPUT | HWMON_T_LABEL,
  711. + HWMON_T_INPUT | HWMON_T_LABEL),
  712. NULL
  713. };
  714. static const struct hwmon_ops ssam_temp_hwmon_ops = {
  715. .is_visible = ssam_temp_hwmon_is_visible,
  716. .read = ssam_temp_hwmon_read,
  717. + .read_string = ssam_temp_hwmon_read_string,
  718. };
  719. static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = {
  720. @@ -122,6 +187,7 @@ static int ssam_temp_probe(struct ssam_device *sdev)
  721. struct ssam_temp *ssam_temp;
  722. struct device *hwmon_dev;
  723. s16 sensors;
  724. + int channel;
  725. int status;
  726. status = ssam_tmp_get_available_sensors(sdev, &sensors);
  727. @@ -135,6 +201,19 @@ static int ssam_temp_probe(struct ssam_device *sdev)
  728. ssam_temp->sdev = sdev;
  729. ssam_temp->sensors = sensors;
  730. + /* Retrieve the name for each available sensor. */
  731. + for (channel = 0; channel < SSAM_TMP_SENSOR_MAX_COUNT; channel++)
  732. + {
  733. + if (!(sensors & BIT(channel)))
  734. + continue;
  735. +
  736. + status = ssam_tmp_get_name(sdev, channel + 1,
  737. + ssam_temp->names[channel],
  738. + SSAM_TMP_SENSOR_NAME_LENGTH);
  739. + if (status)
  740. + return status;
  741. + }
  742. +
  743. hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev,
  744. "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info,
  745. NULL);
  746. --
  747. 2.43.0
  748. From 37894568dd6a0bfb6422ce7c18df757fcb449512 Mon Sep 17 00:00:00 2001
  749. From: Maximilian Luz <luzmaximilian@gmail.com>
  750. Date: Sat, 30 Dec 2023 18:21:12 +0100
  751. Subject: [PATCH] platform/surface: aggregator_registry: Add support for
  752. thermal sensors on the Surface Pro 9
  753. The Surface Pro 9 has thermal sensors connected via the Surface
  754. Aggregator Module. Add a device node to support those.
  755. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  756. Patchset: surface-sam
  757. ---
  758. drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++
  759. 1 file changed, 7 insertions(+)
  760. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  761. index b0db25886c996..797802d16f319 100644
  762. --- a/drivers/platform/surface/surface_aggregator_registry.c
  763. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  764. @@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = {
  765. .parent = &ssam_node_root,
  766. };
  767. +/* Thermal sensors. */
  768. +static const struct software_node ssam_node_tmp_sensors = {
  769. + .name = "ssam:01:03:01:00:02",
  770. + .parent = &ssam_node_root,
  771. +};
  772. +
  773. /* Fan speed function. */
  774. static const struct software_node ssam_node_fan_speed = {
  775. .name = "ssam:01:05:01:01:01",
  776. @@ -325,6 +331,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
  777. &ssam_node_bat_ac,
  778. &ssam_node_bat_main,
  779. &ssam_node_tmp_pprof,
  780. + &ssam_node_tmp_sensors,
  781. &ssam_node_fan_speed,
  782. &ssam_node_pos_tablet_switch,
  783. &ssam_node_hid_kip_keyboard,
  784. --
  785. 2.43.0