77
88#include <linux/device.h>
99#include <linux/hwmon.h>
10+ #include <linux/math.h>
1011#include <linux/mod_devicetable.h>
1112#include <linux/module.h>
1213#include <linux/platform_device.h>
1718
1819#define DRV_NAME "cros-ec-hwmon"
1920
21+ #define CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION 0
22+ #define CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION 1
23+ #define CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION 2
24+
2025struct cros_ec_hwmon_priv {
2126 struct cros_ec_device * cros_ec ;
2227 const char * temp_sensor_names [EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES ];
2328 u8 usable_fans ;
29+ bool fan_control_supported ;
30+ u8 manual_fans ; /* bits to indicate whether the fan is set to manual */
31+ u8 manual_fan_pwm [EC_FAN_SPEED_ENTRIES ];
2432};
2533
2634static int cros_ec_hwmon_read_fan_speed (struct cros_ec_device * cros_ec , u8 index , u16 * speed )
@@ -36,6 +44,42 @@ static int cros_ec_hwmon_read_fan_speed(struct cros_ec_device *cros_ec, u8 index
3644 return 0 ;
3745}
3846
47+ static int cros_ec_hwmon_read_pwm_value (struct cros_ec_device * cros_ec , u8 index , u8 * pwm_value )
48+ {
49+ struct ec_params_pwm_get_fan_duty req = {
50+ .fan_idx = index ,
51+ };
52+ struct ec_response_pwm_get_fan_duty resp ;
53+ int ret ;
54+
55+ ret = cros_ec_cmd (cros_ec , CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION ,
56+ EC_CMD_PWM_GET_FAN_DUTY , & req , sizeof (req ), & resp , sizeof (resp ));
57+ if (ret < 0 )
58+ return ret ;
59+
60+ * pwm_value = (u8 )DIV_ROUND_CLOSEST (le32_to_cpu (resp .percent ) * 255 , 100 );
61+ return 0 ;
62+ }
63+
64+ static int cros_ec_hwmon_read_pwm_enable (struct cros_ec_device * cros_ec , u8 index ,
65+ u8 * control_method )
66+ {
67+ struct ec_params_auto_fan_ctrl_v2 req = {
68+ .cmd = EC_AUTO_FAN_CONTROL_CMD_GET ,
69+ .fan_idx = index ,
70+ };
71+ struct ec_response_auto_fan_control resp ;
72+ int ret ;
73+
74+ ret = cros_ec_cmd (cros_ec , CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION ,
75+ EC_CMD_THERMAL_AUTO_FAN_CTRL , & req , sizeof (req ), & resp , sizeof (resp ));
76+ if (ret < 0 )
77+ return ret ;
78+
79+ * control_method = resp .is_auto ? 2 : 1 ;
80+ return 0 ;
81+ }
82+
3983static int cros_ec_hwmon_read_temp (struct cros_ec_device * cros_ec , u8 index , u8 * temp )
4084{
4185 unsigned int offset ;
@@ -75,6 +119,8 @@ static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
75119{
76120 struct cros_ec_hwmon_priv * priv = dev_get_drvdata (dev );
77121 int ret = - EOPNOTSUPP ;
122+ u8 control_method ;
123+ u8 pwm_value ;
78124 u16 speed ;
79125 u8 temp ;
80126
@@ -92,6 +138,17 @@ static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
92138 if (ret == 0 )
93139 * val = cros_ec_hwmon_is_error_fan (speed );
94140 }
141+ } else if (type == hwmon_pwm ) {
142+ if (attr == hwmon_pwm_enable ) {
143+ ret = cros_ec_hwmon_read_pwm_enable (priv -> cros_ec , channel ,
144+ & control_method );
145+ if (ret == 0 )
146+ * val = control_method ;
147+ } else if (attr == hwmon_pwm_input ) {
148+ ret = cros_ec_hwmon_read_pwm_value (priv -> cros_ec , channel , & pwm_value );
149+ if (ret == 0 )
150+ * val = pwm_value ;
151+ }
95152 } else if (type == hwmon_temp ) {
96153 if (attr == hwmon_temp_input ) {
97154 ret = cros_ec_hwmon_read_temp (priv -> cros_ec , channel , & temp );
@@ -124,6 +181,74 @@ static int cros_ec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types
124181 return - EOPNOTSUPP ;
125182}
126183
184+ static int cros_ec_hwmon_set_fan_pwm_val (struct cros_ec_device * cros_ec , u8 index , u8 val )
185+ {
186+ struct ec_params_pwm_set_fan_duty_v1 req = {
187+ .fan_idx = index ,
188+ .percent = DIV_ROUND_CLOSEST ((uint32_t )val * 100 , 255 ),
189+ };
190+ int ret ;
191+
192+ ret = cros_ec_cmd (cros_ec , CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION ,
193+ EC_CMD_PWM_SET_FAN_DUTY , & req , sizeof (req ), NULL , 0 );
194+ if (ret < 0 )
195+ return ret ;
196+ return 0 ;
197+ }
198+
199+ static int cros_ec_hwmon_write_pwm_input (struct cros_ec_device * cros_ec , u8 index , u8 val )
200+ {
201+ u8 control_method ;
202+ int ret ;
203+
204+ ret = cros_ec_hwmon_read_pwm_enable (cros_ec , index , & control_method );
205+ if (ret )
206+ return ret ;
207+ if (control_method != 1 )
208+ return - EOPNOTSUPP ;
209+
210+ return cros_ec_hwmon_set_fan_pwm_val (cros_ec , index , val );
211+ }
212+
213+ static int cros_ec_hwmon_write_pwm_enable (struct cros_ec_device * cros_ec , u8 index , u8 val )
214+ {
215+ struct ec_params_auto_fan_ctrl_v2 req = {
216+ .fan_idx = index ,
217+ .cmd = EC_AUTO_FAN_CONTROL_CMD_SET ,
218+ };
219+ int ret ;
220+
221+ /* No CrOS EC supports no fan speed control */
222+ if (val == 0 )
223+ return - EOPNOTSUPP ;
224+
225+ req .set_auto = (val != 1 ) ? true : false;
226+ ret = cros_ec_cmd (cros_ec , CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION ,
227+ EC_CMD_THERMAL_AUTO_FAN_CTRL , & req , sizeof (req ), NULL , 0 );
228+ if (ret < 0 )
229+ return ret ;
230+ return 0 ;
231+ }
232+
233+ static int cros_ec_hwmon_write (struct device * dev , enum hwmon_sensor_types type , u32 attr ,
234+ int channel , long val )
235+ {
236+ struct cros_ec_hwmon_priv * priv = dev_get_drvdata (dev );
237+
238+ if (type == hwmon_pwm ) {
239+ switch (attr ) {
240+ case hwmon_pwm_input :
241+ return cros_ec_hwmon_write_pwm_input (priv -> cros_ec , channel , val );
242+ case hwmon_pwm_enable :
243+ return cros_ec_hwmon_write_pwm_enable (priv -> cros_ec , channel , val );
244+ default :
245+ return - EOPNOTSUPP ;
246+ }
247+ }
248+
249+ return - EOPNOTSUPP ;
250+ }
251+
127252static umode_t cros_ec_hwmon_is_visible (const void * data , enum hwmon_sensor_types type ,
128253 u32 attr , int channel )
129254{
@@ -132,6 +257,9 @@ static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_type
132257 if (type == hwmon_fan ) {
133258 if (priv -> usable_fans & BIT (channel ))
134259 return 0444 ;
260+ } else if (type == hwmon_pwm ) {
261+ if (priv -> fan_control_supported && priv -> usable_fans & BIT (channel ))
262+ return 0644 ;
135263 } else if (type == hwmon_temp ) {
136264 if (priv -> temp_sensor_names [channel ])
137265 return 0444 ;
@@ -147,6 +275,11 @@ static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = {
147275 HWMON_F_INPUT | HWMON_F_FAULT ,
148276 HWMON_F_INPUT | HWMON_F_FAULT ,
149277 HWMON_F_INPUT | HWMON_F_FAULT ),
278+ HWMON_CHANNEL_INFO (pwm ,
279+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE ,
280+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE ,
281+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE ,
282+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE ),
150283 HWMON_CHANNEL_INFO (temp ,
151284 HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL ,
152285 HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL ,
@@ -178,6 +311,7 @@ static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = {
178311static const struct hwmon_ops cros_ec_hwmon_ops = {
179312 .read = cros_ec_hwmon_read ,
180313 .read_string = cros_ec_hwmon_read_string ,
314+ .write = cros_ec_hwmon_write ,
181315 .is_visible = cros_ec_hwmon_is_visible ,
182316};
183317
@@ -233,6 +367,25 @@ static void cros_ec_hwmon_probe_fans(struct cros_ec_hwmon_priv *priv)
233367 }
234368}
235369
370+ static inline bool is_cros_ec_cmd_available (struct cros_ec_device * cros_ec ,
371+ u16 cmd , u8 version )
372+ {
373+ int ret ;
374+
375+ ret = cros_ec_get_cmd_versions (cros_ec , cmd );
376+ return ret >= 0 && (ret & EC_VER_MASK (version ));
377+ }
378+
379+ static bool cros_ec_hwmon_probe_fan_control_supported (struct cros_ec_device * cros_ec )
380+ {
381+ return is_cros_ec_cmd_available (cros_ec , EC_CMD_PWM_GET_FAN_DUTY ,
382+ CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION ) &&
383+ is_cros_ec_cmd_available (cros_ec , EC_CMD_PWM_SET_FAN_DUTY ,
384+ CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION ) &&
385+ is_cros_ec_cmd_available (cros_ec , EC_CMD_THERMAL_AUTO_FAN_CTRL ,
386+ CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION );
387+ }
388+
236389static int cros_ec_hwmon_probe (struct platform_device * pdev )
237390{
238391 struct device * dev = & pdev -> dev ;
@@ -259,13 +412,88 @@ static int cros_ec_hwmon_probe(struct platform_device *pdev)
259412
260413 cros_ec_hwmon_probe_temp_sensors (dev , priv , thermal_version );
261414 cros_ec_hwmon_probe_fans (priv );
415+ priv -> fan_control_supported = cros_ec_hwmon_probe_fan_control_supported (priv -> cros_ec );
262416
263417 hwmon_dev = devm_hwmon_device_register_with_info (dev , "cros_ec" , priv ,
264418 & cros_ec_hwmon_chip_info , NULL );
419+ platform_set_drvdata (pdev , priv );
265420
266421 return PTR_ERR_OR_ZERO (hwmon_dev );
267422}
268423
424+ static int cros_ec_hwmon_suspend (struct platform_device * pdev , pm_message_t state )
425+ {
426+ struct cros_ec_hwmon_priv * priv = platform_get_drvdata (pdev );
427+ u8 control_method ;
428+ size_t i ;
429+ int ret ;
430+
431+ if (!priv -> fan_control_supported )
432+ return 0 ;
433+
434+ /* EC sets fan control to auto after suspended, store settings before suspending. */
435+ for (i = 0 ; i < EC_FAN_SPEED_ENTRIES ; i ++ ) {
436+ if (!(priv -> usable_fans & BIT (i )))
437+ continue ;
438+
439+ ret = cros_ec_hwmon_read_pwm_enable (priv -> cros_ec , i , & control_method );
440+ if (ret ) {
441+ dev_warn (& pdev -> dev , "failed to get mode setting for fan %zu: %d\n" , i ,
442+ ret );
443+ continue ;
444+ }
445+
446+ if (control_method != 1 ) {
447+ priv -> manual_fans &= ~BIT (i );
448+ continue ;
449+ } else {
450+ priv -> manual_fans |= BIT (i );
451+ }
452+
453+ ret = cros_ec_hwmon_read_pwm_value (priv -> cros_ec , i , & priv -> manual_fan_pwm [i ]);
454+ /*
455+ * If storing the value failed, invalidate the stored mode value by setting it
456+ * to auto control. EC will automatically switch to auto mode for that fan after
457+ * suspended.
458+ */
459+ if (ret ) {
460+ dev_warn (& pdev -> dev , "failed to get PWM setting for fan %zu: %pe\n" , i ,
461+ ERR_PTR (ret ));
462+ priv -> manual_fans &= ~BIT (i );
463+ continue ;
464+ }
465+ }
466+
467+ return 0 ;
468+ }
469+
470+ static int cros_ec_hwmon_resume (struct platform_device * pdev )
471+ {
472+ const struct cros_ec_hwmon_priv * priv = platform_get_drvdata (pdev );
473+ size_t i ;
474+ int ret ;
475+
476+ if (!priv -> fan_control_supported )
477+ return 0 ;
478+
479+ /* EC sets fan control to auto after suspend, restore to settings before suspend. */
480+ for (i = 0 ; i < EC_FAN_SPEED_ENTRIES ; i ++ ) {
481+ if (!(priv -> manual_fans & BIT (i )))
482+ continue ;
483+
484+ /*
485+ * Setting fan PWM value to EC will change the mode to manual for that fan in EC as
486+ * well, so we do not need to issue a separate fan mode to manual call.
487+ */
488+ ret = cros_ec_hwmon_set_fan_pwm_val (priv -> cros_ec , i , priv -> manual_fan_pwm [i ]);
489+ if (ret )
490+ dev_warn (& pdev -> dev , "failed to restore settings for fan %zu: %pe\n" , i ,
491+ ERR_PTR (ret ));
492+ }
493+
494+ return 0 ;
495+ }
496+
269497static const struct platform_device_id cros_ec_hwmon_id [] = {
270498 { DRV_NAME , 0 },
271499 {}
@@ -274,6 +502,8 @@ static const struct platform_device_id cros_ec_hwmon_id[] = {
274502static struct platform_driver cros_ec_hwmon_driver = {
275503 .driver .name = DRV_NAME ,
276504 .probe = cros_ec_hwmon_probe ,
505+ .suspend = pm_ptr (cros_ec_hwmon_suspend ),
506+ .resume = pm_ptr (cros_ec_hwmon_resume ),
277507 .id_table = cros_ec_hwmon_id ,
278508};
279509module_platform_driver (cros_ec_hwmon_driver );
0 commit comments