0006-surface-sam.patch 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364
  1. From 973bf943acca4abdd932b5fdff032de0af07f96e 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 aeb3feae40ff..2bc4977037fc 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.44.0
  28. From 7dedc84364f9c1fb73d271c859dce19b4a9644d6 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 2bc4977037fc..26cb6229ad16 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.44.0
  90. From 96a7b3dd527f3e1b97e2d089a727c16cd5045aa5 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 26cb6229ad16..f02a933160ff 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.44.0
  130. From b4eb65349df9859f65aa9990c24c5036d35382da 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 c7ed1f73ac06..58be92e94a8d 100644
  152. --- a/Documentation/hwmon/index.rst
  153. +++ b/Documentation/hwmon/index.rst
  154. @@ -208,6 +208,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 000000000000..07942574c4f0
  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 1aabf1c15bb3..b6416cf3f022 100644
  195. --- a/MAINTAINERS
  196. +++ b/MAINTAINERS
  197. @@ -14576,6 +14576,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 a608264da87d..e762f6138970 100644
  213. --- a/drivers/hwmon/Kconfig
  214. +++ b/drivers/hwmon/Kconfig
  215. @@ -1994,6 +1994,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 47be39af5c03..30cc90f40844 100644
  236. --- a/drivers/hwmon/Makefile
  237. +++ b/drivers/hwmon/Makefile
  238. @@ -201,6 +201,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 000000000000..7c2e3ae3eb40
  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.44.0
  347. From 5c18bed9c7ad073b61e3c3686dc4bc1858f958dc 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 e762f6138970..41261b49f8be 100644
  367. --- a/drivers/hwmon/Kconfig
  368. +++ b/drivers/hwmon/Kconfig
  369. @@ -2007,6 +2007,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 30cc90f40844..6644fd4598a4 100644
  386. --- a/drivers/hwmon/Makefile
  387. +++ b/drivers/hwmon/Makefile
  388. @@ -202,6 +202,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 000000000000..48c3e826713f
  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.44.0
  569. From 8b1e37ad9423a6fdf8a8b3bfb1e15aadefe136de 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 48c3e826713f..4c08926139db 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.44.0
  748. From 9b490a17f59518e59cf3c77c103bf5ddc52041a3 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 f02a933160ff..67686042e009 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.44.0
  786. From ec0b680c0ce36ef6bffd682e10589cf5d8d467ae Mon Sep 17 00:00:00 2001
  787. From: Ivor Wanders <ivor@iwanders.net>
  788. Date: Sat, 16 Dec 2023 15:56:39 -0500
  789. Subject: [PATCH] platform/surface: platform_profile: add fan profile switching
  790. Change naming from tmp to platform profile to clarify the module may
  791. interact with both the TMP and FAN subystems. Add functionality that
  792. switches the fan profile when the platform profile is changed.
  793. Signed-off-by: Ivor Wanders <ivor@iwanders.net>
  794. Patchset: surface-sam
  795. ---
  796. .../surface/surface_aggregator_registry.c | 38 +++++---
  797. .../surface/surface_platform_profile.c | 86 ++++++++++++++++---
  798. 2 files changed, 100 insertions(+), 24 deletions(-)
  799. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  800. index 67686042e009..058b6654a91a 100644
  801. --- a/drivers/platform/surface/surface_aggregator_registry.c
  802. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  803. @@ -68,8 +68,8 @@ static const struct software_node ssam_node_bat_sb3base = {
  804. .parent = &ssam_node_hub_base,
  805. };
  806. -/* Platform profile / performance-mode device. */
  807. -static const struct software_node ssam_node_tmp_pprof = {
  808. +/* Platform profile / performance-mode device without a fan. */
  809. +static const struct software_node ssam_node_tmp_perf_profile = {
  810. .name = "ssam:01:03:01:00:01",
  811. .parent = &ssam_node_root,
  812. };
  813. @@ -86,6 +86,20 @@ static const struct software_node ssam_node_fan_speed = {
  814. .parent = &ssam_node_root,
  815. };
  816. +/* Platform profile / performance-mode device with a fan, such that
  817. + * the fan controller profile can also be switched.
  818. + */
  819. +static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = {
  820. + PROPERTY_ENTRY_BOOL("has_fan"),
  821. + { }
  822. +};
  823. +
  824. +static const struct software_node ssam_node_tmp_perf_profile_with_fan = {
  825. + .name = "ssam:01:03:01:00:01",
  826. + .parent = &ssam_node_root,
  827. + .properties = ssam_node_tmp_perf_profile_has_fan,
  828. +};
  829. +
  830. /* Tablet-mode switch via KIP subsystem. */
  831. static const struct software_node ssam_node_kip_tablet_switch = {
  832. .name = "ssam:01:0e:01:00:01",
  833. @@ -214,7 +228,7 @@ static const struct software_node ssam_node_pos_tablet_switch = {
  834. */
  835. static const struct software_node *ssam_node_group_gen5[] = {
  836. &ssam_node_root,
  837. - &ssam_node_tmp_pprof,
  838. + &ssam_node_tmp_perf_profile,
  839. NULL,
  840. };
  841. @@ -225,7 +239,7 @@ static const struct software_node *ssam_node_group_sb3[] = {
  842. &ssam_node_bat_ac,
  843. &ssam_node_bat_main,
  844. &ssam_node_bat_sb3base,
  845. - &ssam_node_tmp_pprof,
  846. + &ssam_node_tmp_perf_profile,
  847. &ssam_node_bas_dtx,
  848. &ssam_node_hid_base_keyboard,
  849. &ssam_node_hid_base_touchpad,
  850. @@ -239,7 +253,7 @@ static const struct software_node *ssam_node_group_sl3[] = {
  851. &ssam_node_root,
  852. &ssam_node_bat_ac,
  853. &ssam_node_bat_main,
  854. - &ssam_node_tmp_pprof,
  855. + &ssam_node_tmp_perf_profile,
  856. &ssam_node_hid_main_keyboard,
  857. &ssam_node_hid_main_touchpad,
  858. &ssam_node_hid_main_iid5,
  859. @@ -251,7 +265,7 @@ static const struct software_node *ssam_node_group_sl5[] = {
  860. &ssam_node_root,
  861. &ssam_node_bat_ac,
  862. &ssam_node_bat_main,
  863. - &ssam_node_tmp_pprof,
  864. + &ssam_node_tmp_perf_profile,
  865. &ssam_node_hid_main_keyboard,
  866. &ssam_node_hid_main_touchpad,
  867. &ssam_node_hid_main_iid5,
  868. @@ -264,7 +278,7 @@ static const struct software_node *ssam_node_group_sls1[] = {
  869. &ssam_node_root,
  870. &ssam_node_bat_ac,
  871. &ssam_node_bat_main,
  872. - &ssam_node_tmp_pprof,
  873. + &ssam_node_tmp_perf_profile,
  874. &ssam_node_pos_tablet_switch,
  875. &ssam_node_hid_sam_keyboard,
  876. &ssam_node_hid_sam_penstash,
  877. @@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls2[] = {
  878. &ssam_node_root,
  879. &ssam_node_bat_ac,
  880. &ssam_node_bat_main,
  881. - &ssam_node_tmp_pprof,
  882. + &ssam_node_tmp_perf_profile,
  883. &ssam_node_pos_tablet_switch,
  884. &ssam_node_hid_sam_keyboard,
  885. &ssam_node_hid_sam_penstash,
  886. @@ -294,7 +308,7 @@ static const struct software_node *ssam_node_group_slg1[] = {
  887. &ssam_node_root,
  888. &ssam_node_bat_ac,
  889. &ssam_node_bat_main,
  890. - &ssam_node_tmp_pprof,
  891. + &ssam_node_tmp_perf_profile,
  892. NULL,
  893. };
  894. @@ -303,7 +317,7 @@ static const struct software_node *ssam_node_group_sp7[] = {
  895. &ssam_node_root,
  896. &ssam_node_bat_ac,
  897. &ssam_node_bat_main,
  898. - &ssam_node_tmp_pprof,
  899. + &ssam_node_tmp_perf_profile,
  900. NULL,
  901. };
  902. @@ -313,7 +327,7 @@ static const struct software_node *ssam_node_group_sp8[] = {
  903. &ssam_node_hub_kip,
  904. &ssam_node_bat_ac,
  905. &ssam_node_bat_main,
  906. - &ssam_node_tmp_pprof,
  907. + &ssam_node_tmp_perf_profile,
  908. &ssam_node_kip_tablet_switch,
  909. &ssam_node_hid_kip_keyboard,
  910. &ssam_node_hid_kip_penstash,
  911. @@ -330,7 +344,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
  912. &ssam_node_hub_kip,
  913. &ssam_node_bat_ac,
  914. &ssam_node_bat_main,
  915. - &ssam_node_tmp_pprof,
  916. + &ssam_node_tmp_perf_profile_with_fan,
  917. &ssam_node_tmp_sensors,
  918. &ssam_node_fan_speed,
  919. &ssam_node_pos_tablet_switch,
  920. diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c
  921. index a5a3941b3f43..e54d0a8f7daa 100644
  922. --- a/drivers/platform/surface/surface_platform_profile.c
  923. +++ b/drivers/platform/surface/surface_platform_profile.c
  924. @@ -1,7 +1,7 @@
  925. // SPDX-License-Identifier: GPL-2.0+
  926. /*
  927. * Surface Platform Profile / Performance Mode driver for Surface System
  928. - * Aggregator Module (thermal subsystem).
  929. + * Aggregator Module (thermal and fan subsystem).
  930. *
  931. * Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com>
  932. */
  933. @@ -14,6 +14,7 @@
  934. #include <linux/surface_aggregator/device.h>
  935. +// Enum for the platform performance profile sent to the TMP module.
  936. enum ssam_tmp_profile {
  937. SSAM_TMP_PROFILE_NORMAL = 1,
  938. SSAM_TMP_PROFILE_BATTERY_SAVER = 2,
  939. @@ -21,15 +22,26 @@ enum ssam_tmp_profile {
  940. SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4,
  941. };
  942. +// Enum for the fan profile sent to the FAN module. This fan profile is
  943. +// only sent to the EC if the 'has_fan' property is set. The integers are
  944. +// not a typo, they differ from the performance profile indices.
  945. +enum ssam_fan_profile {
  946. + SSAM_FAN_PROFILE_NORMAL = 2,
  947. + SSAM_FAN_PROFILE_BATTERY_SAVER = 1,
  948. + SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3,
  949. + SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4,
  950. +};
  951. +
  952. struct ssam_tmp_profile_info {
  953. __le32 profile;
  954. __le16 unknown1;
  955. __le16 unknown2;
  956. } __packed;
  957. -struct ssam_tmp_profile_device {
  958. +struct ssam_platform_profile_device {
  959. struct ssam_device *sdev;
  960. struct platform_profile_handler handler;
  961. + bool has_fan;
  962. };
  963. SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, {
  964. @@ -42,6 +54,13 @@ SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, {
  965. .command_id = 0x03,
  966. });
  967. +SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, char, {
  968. + .target_category = SSAM_SSH_TC_FAN,
  969. + .target_id = SSAM_SSH_TID_SAM,
  970. + .command_id = 0x0e,
  971. + .instance_id = 0x01,
  972. +});
  973. +
  974. static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p)
  975. {
  976. struct ssam_tmp_profile_info info;
  977. @@ -62,7 +81,14 @@ static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile
  978. return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le);
  979. }
  980. -static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
  981. +static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p)
  982. +{
  983. + char profile = p;
  984. +
  985. + return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile);
  986. +}
  987. +
  988. +static int convert_ssam_tmp_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
  989. {
  990. switch (p) {
  991. case SSAM_TMP_PROFILE_NORMAL:
  992. @@ -83,7 +109,8 @@ static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profi
  993. }
  994. }
  995. -static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p)
  996. +
  997. +static int convert_profile_to_ssam_tmp(struct ssam_device *sdev, enum platform_profile_option p)
  998. {
  999. switch (p) {
  1000. case PLATFORM_PROFILE_LOW_POWER:
  1001. @@ -105,20 +132,42 @@ static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profi
  1002. }
  1003. }
  1004. +static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p)
  1005. +{
  1006. + switch (p) {
  1007. + case PLATFORM_PROFILE_LOW_POWER:
  1008. + return SSAM_FAN_PROFILE_BATTERY_SAVER;
  1009. +
  1010. + case PLATFORM_PROFILE_BALANCED:
  1011. + return SSAM_FAN_PROFILE_NORMAL;
  1012. +
  1013. + case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
  1014. + return SSAM_FAN_PROFILE_BETTER_PERFORMANCE;
  1015. +
  1016. + case PLATFORM_PROFILE_PERFORMANCE:
  1017. + return SSAM_FAN_PROFILE_BEST_PERFORMANCE;
  1018. +
  1019. + default:
  1020. + /* This should have already been caught by platform_profile_store(). */
  1021. + WARN(true, "unsupported platform profile");
  1022. + return -EOPNOTSUPP;
  1023. + }
  1024. +}
  1025. +
  1026. static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
  1027. enum platform_profile_option *profile)
  1028. {
  1029. - struct ssam_tmp_profile_device *tpd;
  1030. + struct ssam_platform_profile_device *tpd;
  1031. enum ssam_tmp_profile tp;
  1032. int status;
  1033. - tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
  1034. + tpd = container_of(pprof, struct ssam_platform_profile_device, handler);
  1035. status = ssam_tmp_profile_get(tpd->sdev, &tp);
  1036. if (status)
  1037. return status;
  1038. - status = convert_ssam_to_profile(tpd->sdev, tp);
  1039. + status = convert_ssam_tmp_to_profile(tpd->sdev, tp);
  1040. if (status < 0)
  1041. return status;
  1042. @@ -129,21 +178,32 @@ static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
  1043. static int ssam_platform_profile_set(struct platform_profile_handler *pprof,
  1044. enum platform_profile_option profile)
  1045. {
  1046. - struct ssam_tmp_profile_device *tpd;
  1047. + struct ssam_platform_profile_device *tpd;
  1048. int tp;
  1049. - tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
  1050. + tpd = container_of(pprof, struct ssam_platform_profile_device, handler);
  1051. +
  1052. + tp = convert_profile_to_ssam_tmp(tpd->sdev, profile);
  1053. + if (tp < 0)
  1054. + return tp;
  1055. - tp = convert_profile_to_ssam(tpd->sdev, profile);
  1056. + tp = ssam_tmp_profile_set(tpd->sdev, tp);
  1057. if (tp < 0)
  1058. return tp;
  1059. - return ssam_tmp_profile_set(tpd->sdev, tp);
  1060. + if (tpd->has_fan) {
  1061. + tp = convert_profile_to_ssam_fan(tpd->sdev, profile);
  1062. + if (tp < 0)
  1063. + return tp;
  1064. + tp = ssam_fan_profile_set(tpd->sdev, tp);
  1065. + }
  1066. +
  1067. + return tp;
  1068. }
  1069. static int surface_platform_profile_probe(struct ssam_device *sdev)
  1070. {
  1071. - struct ssam_tmp_profile_device *tpd;
  1072. + struct ssam_platform_profile_device *tpd;
  1073. tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL);
  1074. if (!tpd)
  1075. @@ -154,6 +214,8 @@ static int surface_platform_profile_probe(struct ssam_device *sdev)
  1076. tpd->handler.profile_get = ssam_platform_profile_get;
  1077. tpd->handler.profile_set = ssam_platform_profile_set;
  1078. + tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan");
  1079. +
  1080. set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices);
  1081. set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices);
  1082. set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices);
  1083. --
  1084. 2.44.0
  1085. From 63781a056a0f06d5cc38d7755e0753c7ec08c51c Mon Sep 17 00:00:00 2001
  1086. From: Maximilian Luz <luzmaximilian@gmail.com>
  1087. Date: Fri, 19 Apr 2024 20:41:47 +0200
  1088. Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is
  1089. destroyed in probe
  1090. There is a small window in ssam_serial_hub_probe() where the controller
  1091. is initialized but has not been started yet. Specifically, between
  1092. ssam_controller_init() and ssam_controller_start(). Any failure in this
  1093. window, for example caused by a failure of serdev_device_open(),
  1094. currently results in an incorrect warning being emitted.
  1095. In particular, any failure in this window results in the controller
  1096. being destroyed via ssam_controller_destroy(). This function checks the
  1097. state of the controller and, in an attempt to validate that the
  1098. controller has been cleanly shut down before we try and deallocate any
  1099. resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED.
  1100. However, since we have only just initialized the controller and have not
  1101. yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this
  1102. is the only point at which the controller has this state, as it will
  1103. change after we start the controller with ssam_controller_start() and
  1104. never revert back. Further, at this point no communication has taken
  1105. place and the sender and receiver threads have not been started yet (and
  1106. we may not even have an open serdev device either).
  1107. Therefore, it is perfectly safe to call ssam_controller_destroy() with a
  1108. state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the
  1109. warning currently being emitted is incorrect. Fix it by extending the
  1110. check.
  1111. Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem")
  1112. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  1113. ---
  1114. drivers/platform/surface/aggregator/controller.c | 3 ++-
  1115. 1 file changed, 2 insertions(+), 1 deletion(-)
  1116. diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
  1117. index 7fc602e01487..7e89f547999b 100644
  1118. --- a/drivers/platform/surface/aggregator/controller.c
  1119. +++ b/drivers/platform/surface/aggregator/controller.c
  1120. @@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl)
  1121. if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED)
  1122. return;
  1123. - WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED);
  1124. + WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED &&
  1125. + ctrl->state != SSAM_CONTROLLER_INITIALIZED);
  1126. /*
  1127. * Note: New events could still have been received after the previous
  1128. --
  1129. 2.44.0
  1130. From 9a219fa8d6c0beb0725a90bd32c7687aa5805fdc Mon Sep 17 00:00:00 2001
  1131. From: Weifeng Liu <weifeng.liu.z@gmail.com>
  1132. Date: Mon, 22 Apr 2024 20:45:34 +0800
  1133. Subject: [PATCH] platform/surface: aggregator: Defer probing when serdev is
  1134. not ready
  1135. This is an attempt to alleviate race conditions in the SAM driver where
  1136. essential resources like serial device and GPIO pins are not ready at
  1137. the time ssam_serial_hub_probe() is called. Instead of giving up
  1138. probing, a better way would be to defer the probing by returning
  1139. -EPROBE_DEFER, allowing the kernel try again later.
  1140. However, there is no way of identifying all such cases from other real
  1141. errors in a few days. So let's take a gradual approach identify and
  1142. address these cases as they arise. This commit marks the initial step
  1143. in this process.
  1144. Signed-off-by: Weifeng Liu <weifeng.liu.z@gmail.com>
  1145. Patchset: surface-sam
  1146. ---
  1147. drivers/platform/surface/aggregator/core.c | 13 ++++++++++++-
  1148. 1 file changed, 12 insertions(+), 1 deletion(-)
  1149. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  1150. index 9591a28bc38a9..72a521dd729c3 100644
  1151. --- a/drivers/platform/surface/aggregator/core.c
  1152. +++ b/drivers/platform/surface/aggregator/core.c
  1153. @@ -645,9 +645,20 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
  1154. /* Set up serdev device. */
  1155. serdev_device_set_drvdata(serdev, ctrl);
  1156. serdev_device_set_client_ops(serdev, &ssam_serdev_ops);
  1157. +
  1158. + /* The following step can fail when it's called too early before the
  1159. + * underlying uart device is ready (in this case -ENXIO is returned).
  1160. + * Instead of simply giving up and losing everything, we can defer
  1161. + * the probing by returning -EPROBE_DEFER so that the kernel would be
  1162. + * able to retry later. */
  1163. status = serdev_device_open(serdev);
  1164. - if (status)
  1165. + if (status == -ENXIO)
  1166. + status = -EPROBE_DEFER;
  1167. + if (status) {
  1168. + dev_err_probe(&serdev->dev, status,
  1169. + "failed to open serdev device\n");
  1170. goto err_devopen;
  1171. + }
  1172. astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
  1173. if (ACPI_FAILURE(astatus)) {
  1174. --
  1175. 2.44.0
  1176. From 25b5454ea67f3bf6214a1ee4ed5a409ccd8eb946 Mon Sep 17 00:00:00 2001
  1177. From: Weifeng Liu <weifeng.liu.z@gmail.com>
  1178. Date: Wed, 24 Apr 2024 22:24:08 +0800
  1179. Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM
  1180. probing
  1181. Emits messages upon errors during probing of SAM. Hopefully this could
  1182. provide useful context to user for the purpose of diagnosis when
  1183. something miserable happen.
  1184. Signed-off-by: Weifeng Liu <weifeng.liu.z@gmail.com>
  1185. Patchset: surface-sam
  1186. ---
  1187. drivers/platform/surface/aggregator/core.c | 26 +++++++++++++++++-----
  1188. 1 file changed, 20 insertions(+), 6 deletions(-)
  1189. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  1190. index 72a521dd729c3..4e2e70f4dcf51 100644
  1191. --- a/drivers/platform/surface/aggregator/core.c
  1192. +++ b/drivers/platform/surface/aggregator/core.c
  1193. @@ -623,8 +623,10 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
  1194. acpi_status astatus;
  1195. int status;
  1196. - if (gpiod_count(&serdev->dev, NULL) < 0)
  1197. + if (gpiod_count(&serdev->dev, NULL) < 0) {
  1198. + dev_err(&serdev->dev, "no GPIO found\n");
  1199. return -ENODEV;
  1200. + }
  1201. status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios);
  1202. if (status)
  1203. @@ -637,8 +639,11 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
  1204. /* Initialize controller. */
  1205. status = ssam_controller_init(ctrl, serdev);
  1206. - if (status)
  1207. + if (status) {
  1208. + dev_err_probe(&serdev->dev, status,
  1209. + "failed to initialize ssam controller\n");
  1210. goto err_ctrl_init;
  1211. + }
  1212. ssam_controller_lock(ctrl);
  1213. @@ -663,6 +668,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
  1214. astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
  1215. if (ACPI_FAILURE(astatus)) {
  1216. status = -ENXIO;
  1217. + dev_err(&serdev->dev, "failed to setup serdev\n");
  1218. goto err_devinit;
  1219. }
  1220. @@ -678,16 +684,22 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
  1221. * states.
  1222. */
  1223. status = ssam_log_firmware_version(ctrl);
  1224. - if (status)
  1225. + if (status) {
  1226. + dev_err(&serdev->dev, "failed to get firmware version\n");
  1227. goto err_initrq;
  1228. + }
  1229. status = ssam_ctrl_notif_d0_entry(ctrl);
  1230. - if (status)
  1231. + if (status) {
  1232. + dev_err(&serdev->dev, "failed to notify EC of entry of D0\n");
  1233. goto err_initrq;
  1234. + }
  1235. status = ssam_ctrl_notif_display_on(ctrl);
  1236. - if (status)
  1237. + if (status) {
  1238. + dev_err(&serdev->dev, "failed to notify EC of display on\n");
  1239. goto err_initrq;
  1240. + }
  1241. status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group);
  1242. if (status)
  1243. @@ -695,8 +707,10 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
  1244. /* Set up IRQ. */
  1245. status = ssam_irq_setup(ctrl);
  1246. - if (status)
  1247. + if (status) {
  1248. + dev_err_probe(&serdev->dev, status, "failed to setup IRQ\n");
  1249. goto err_irq;
  1250. + }
  1251. /* Finally, set main controller reference. */
  1252. status = ssam_try_set_controller(ctrl);
  1253. --
  1254. 2.44.0