77#include <acpi/battery.h>
88#include <linux/container_of.h>
99#include <linux/dmi.h>
10+ #include <linux/lockdep.h>
1011#include <linux/mod_devicetable.h>
1112#include <linux/module.h>
13+ #include <linux/mutex.h>
1214#include <linux/platform_data/cros_ec_commands.h>
1315#include <linux/platform_data/cros_ec_proto.h>
1416#include <linux/platform_device.h>
@@ -49,6 +51,7 @@ struct cros_chctl_priv {
4951 struct attribute * attributes [_CROS_CHCTL_ATTR_COUNT ];
5052 struct attribute_group group ;
5153
54+ struct mutex lock ; /* protects fields below and cros_ec */
5255 enum power_supply_charge_behaviour current_behaviour ;
5356 u8 current_start_threshold , current_end_threshold ;
5457};
@@ -85,6 +88,8 @@ static int cros_chctl_configure_ec(struct cros_chctl_priv *priv)
8588{
8689 struct ec_params_charge_control req = {};
8790
91+ lockdep_assert_held (& priv -> lock );
92+
8893 req .cmd = EC_CHARGE_CONTROL_CMD_SET ;
8994
9095 switch (priv -> current_behaviour ) {
@@ -134,11 +139,15 @@ static ssize_t cros_chctl_store_threshold(struct device *dev, struct cros_chctl_
134139 return - EINVAL ;
135140
136141 if (is_end_threshold ) {
137- if (val <= priv -> current_start_threshold )
142+ /* Start threshold is not exposed, use fixed value */
143+ if (priv -> cmd_version == 2 )
144+ priv -> current_start_threshold = val == 100 ? 0 : val ;
145+
146+ if (val < priv -> current_start_threshold )
138147 return - EINVAL ;
139148 priv -> current_end_threshold = val ;
140149 } else {
141- if (val >= priv -> current_end_threshold )
150+ if (val > priv -> current_end_threshold )
142151 return - EINVAL ;
143152 priv -> current_start_threshold = val ;
144153 }
@@ -159,6 +168,7 @@ static ssize_t charge_control_start_threshold_show(struct device *dev,
159168 struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
160169 CROS_CHCTL_ATTR_START_THRESHOLD );
161170
171+ guard (mutex )(& priv -> lock );
162172 return sysfs_emit (buf , "%u\n" , (unsigned int )priv -> current_start_threshold );
163173}
164174
@@ -169,6 +179,7 @@ static ssize_t charge_control_start_threshold_store(struct device *dev,
169179 struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
170180 CROS_CHCTL_ATTR_START_THRESHOLD );
171181
182+ guard (mutex )(& priv -> lock );
172183 return cros_chctl_store_threshold (dev , priv , 0 , buf , count );
173184}
174185
@@ -178,6 +189,7 @@ static ssize_t charge_control_end_threshold_show(struct device *dev, struct devi
178189 struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
179190 CROS_CHCTL_ATTR_END_THRESHOLD );
180191
192+ guard (mutex )(& priv -> lock );
181193 return sysfs_emit (buf , "%u\n" , (unsigned int )priv -> current_end_threshold );
182194}
183195
@@ -187,6 +199,7 @@ static ssize_t charge_control_end_threshold_store(struct device *dev, struct dev
187199 struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
188200 CROS_CHCTL_ATTR_END_THRESHOLD );
189201
202+ guard (mutex )(& priv -> lock );
190203 return cros_chctl_store_threshold (dev , priv , 1 , buf , count );
191204}
192205
@@ -195,6 +208,7 @@ static ssize_t charge_behaviour_show(struct device *dev, struct device_attribute
195208 struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
196209 CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR );
197210
211+ guard (mutex )(& priv -> lock );
198212 return power_supply_charge_behaviour_show (dev , EC_CHARGE_CONTROL_BEHAVIOURS ,
199213 priv -> current_behaviour , buf );
200214}
@@ -210,6 +224,7 @@ static ssize_t charge_behaviour_store(struct device *dev, struct device_attribut
210224 if (ret < 0 )
211225 return ret ;
212226
227+ guard (mutex )(& priv -> lock );
213228 priv -> current_behaviour = ret ;
214229
215230 ret = cros_chctl_configure_ec (priv );
@@ -223,12 +238,10 @@ static umode_t cros_chtl_attr_is_visible(struct kobject *kobj, struct attribute
223238{
224239 struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (attr , n );
225240
226- if (priv -> cmd_version < 2 ) {
227- if (n == CROS_CHCTL_ATTR_START_THRESHOLD )
228- return 0 ;
229- if (n == CROS_CHCTL_ATTR_END_THRESHOLD )
230- return 0 ;
231- }
241+ if (n == CROS_CHCTL_ATTR_START_THRESHOLD && priv -> cmd_version < 3 )
242+ return 0 ;
243+ else if (n == CROS_CHCTL_ATTR_END_THRESHOLD && priv -> cmd_version < 2 )
244+ return 0 ;
232245
233246 return attr -> mode ;
234247}
@@ -290,6 +303,10 @@ static int cros_chctl_probe(struct platform_device *pdev)
290303 if (!priv )
291304 return - ENOMEM ;
292305
306+ ret = devm_mutex_init (dev , & priv -> lock );
307+ if (ret )
308+ return ret ;
309+
293310 ret = cros_ec_get_cmd_versions (cros_ec , EC_CMD_CHARGE_CONTROL );
294311 if (ret < 0 )
295312 return ret ;
@@ -327,7 +344,8 @@ static int cros_chctl_probe(struct platform_device *pdev)
327344 priv -> current_end_threshold = 100 ;
328345
329346 /* Bring EC into well-known state */
330- ret = cros_chctl_configure_ec (priv );
347+ scoped_guard (mutex , & priv -> lock )
348+ ret = cros_chctl_configure_ec (priv );
331349 if (ret < 0 )
332350 return ret ;
333351
0 commit comments