1 // SPDX-License-Identifier: GPL-2.0+
3 * Surface Platform Profile / Performance Mode driver for Surface System
4 * Aggregator Module (thermal subsystem).
6 * Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com>
9 #include <asm/unaligned.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_profile.h>
13 #include <linux/types.h>
15 #include <linux/surface_aggregator/device.h>
17 enum ssam_tmp_profile
{
18 SSAM_TMP_PROFILE_NORMAL
= 1,
19 SSAM_TMP_PROFILE_BATTERY_SAVER
= 2,
20 SSAM_TMP_PROFILE_BETTER_PERFORMANCE
= 3,
21 SSAM_TMP_PROFILE_BEST_PERFORMANCE
= 4,
24 struct ssam_tmp_profile_info
{
30 struct ssam_tmp_profile_device
{
31 struct ssam_device
*sdev
;
32 struct platform_profile_handler handler
;
35 SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get
, struct ssam_tmp_profile_info
, {
36 .target_category
= SSAM_SSH_TC_TMP
,
40 SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set
, __le32
, {
41 .target_category
= SSAM_SSH_TC_TMP
,
45 static int ssam_tmp_profile_get(struct ssam_device
*sdev
, enum ssam_tmp_profile
*p
)
47 struct ssam_tmp_profile_info info
;
50 status
= ssam_retry(__ssam_tmp_profile_get
, sdev
, &info
);
54 *p
= le32_to_cpu(info
.profile
);
58 static int ssam_tmp_profile_set(struct ssam_device
*sdev
, enum ssam_tmp_profile p
)
60 __le32 profile_le
= cpu_to_le32(p
);
62 return ssam_retry(__ssam_tmp_profile_set
, sdev
, &profile_le
);
65 static int convert_ssam_to_profile(struct ssam_device
*sdev
, enum ssam_tmp_profile p
)
68 case SSAM_TMP_PROFILE_NORMAL
:
69 return PLATFORM_PROFILE_BALANCED
;
71 case SSAM_TMP_PROFILE_BATTERY_SAVER
:
72 return PLATFORM_PROFILE_LOW_POWER
;
74 case SSAM_TMP_PROFILE_BETTER_PERFORMANCE
:
75 return PLATFORM_PROFILE_BALANCED_PERFORMANCE
;
77 case SSAM_TMP_PROFILE_BEST_PERFORMANCE
:
78 return PLATFORM_PROFILE_PERFORMANCE
;
81 dev_err(&sdev
->dev
, "invalid performance profile: %d", p
);
86 static int convert_profile_to_ssam(struct ssam_device
*sdev
, enum platform_profile_option p
)
89 case PLATFORM_PROFILE_LOW_POWER
:
90 return SSAM_TMP_PROFILE_BATTERY_SAVER
;
92 case PLATFORM_PROFILE_BALANCED
:
93 return SSAM_TMP_PROFILE_NORMAL
;
95 case PLATFORM_PROFILE_BALANCED_PERFORMANCE
:
96 return SSAM_TMP_PROFILE_BETTER_PERFORMANCE
;
98 case PLATFORM_PROFILE_PERFORMANCE
:
99 return SSAM_TMP_PROFILE_BEST_PERFORMANCE
;
102 /* This should have already been caught by platform_profile_store(). */
103 WARN(true, "unsupported platform profile");
108 static int ssam_platform_profile_get(struct platform_profile_handler
*pprof
,
109 enum platform_profile_option
*profile
)
111 struct ssam_tmp_profile_device
*tpd
;
112 enum ssam_tmp_profile tp
;
115 tpd
= container_of(pprof
, struct ssam_tmp_profile_device
, handler
);
117 status
= ssam_tmp_profile_get(tpd
->sdev
, &tp
);
121 status
= convert_ssam_to_profile(tpd
->sdev
, tp
);
129 static int ssam_platform_profile_set(struct platform_profile_handler
*pprof
,
130 enum platform_profile_option profile
)
132 struct ssam_tmp_profile_device
*tpd
;
135 tpd
= container_of(pprof
, struct ssam_tmp_profile_device
, handler
);
137 tp
= convert_profile_to_ssam(tpd
->sdev
, profile
);
141 return ssam_tmp_profile_set(tpd
->sdev
, tp
);
144 static int surface_platform_profile_probe(struct ssam_device
*sdev
)
146 struct ssam_tmp_profile_device
*tpd
;
148 tpd
= devm_kzalloc(&sdev
->dev
, sizeof(*tpd
), GFP_KERNEL
);
154 tpd
->handler
.profile_get
= ssam_platform_profile_get
;
155 tpd
->handler
.profile_set
= ssam_platform_profile_set
;
157 set_bit(PLATFORM_PROFILE_LOW_POWER
, tpd
->handler
.choices
);
158 set_bit(PLATFORM_PROFILE_BALANCED
, tpd
->handler
.choices
);
159 set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE
, tpd
->handler
.choices
);
160 set_bit(PLATFORM_PROFILE_PERFORMANCE
, tpd
->handler
.choices
);
162 platform_profile_register(&tpd
->handler
);
166 static void surface_platform_profile_remove(struct ssam_device
*sdev
)
168 platform_profile_remove();
171 static const struct ssam_device_id ssam_platform_profile_match
[] = {
172 { SSAM_SDEV(TMP
, SAM
, 0x00, 0x01) },
175 MODULE_DEVICE_TABLE(ssam
, ssam_platform_profile_match
);
177 static struct ssam_device_driver surface_platform_profile
= {
178 .probe
= surface_platform_profile_probe
,
179 .remove
= surface_platform_profile_remove
,
180 .match_table
= ssam_platform_profile_match
,
182 .name
= "surface_platform_profile",
183 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
186 module_ssam_device_driver(surface_platform_profile
);
188 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
189 MODULE_DESCRIPTION("Platform Profile Support for Surface System Aggregator Module");
190 MODULE_LICENSE("GPL");