7
7
#include <acpi/battery.h>
8
8
#include <linux/container_of.h>
9
9
#include <linux/dmi.h>
10
+ #include <linux/lockdep.h>
10
11
#include <linux/mod_devicetable.h>
11
12
#include <linux/module.h>
13
+ #include <linux/mutex.h>
12
14
#include <linux/platform_data/cros_ec_commands.h>
13
15
#include <linux/platform_data/cros_ec_proto.h>
14
16
#include <linux/platform_device.h>
@@ -49,6 +51,7 @@ struct cros_chctl_priv {
49
51
struct attribute * attributes [_CROS_CHCTL_ATTR_COUNT ];
50
52
struct attribute_group group ;
51
53
54
+ struct mutex lock ; /* protects fields below and cros_ec */
52
55
enum power_supply_charge_behaviour current_behaviour ;
53
56
u8 current_start_threshold , current_end_threshold ;
54
57
};
@@ -85,6 +88,8 @@ static int cros_chctl_configure_ec(struct cros_chctl_priv *priv)
85
88
{
86
89
struct ec_params_charge_control req = {};
87
90
91
+ lockdep_assert_held (& priv -> lock );
92
+
88
93
req .cmd = EC_CHARGE_CONTROL_CMD_SET ;
89
94
90
95
switch (priv -> current_behaviour ) {
@@ -134,11 +139,15 @@ static ssize_t cros_chctl_store_threshold(struct device *dev, struct cros_chctl_
134
139
return - EINVAL ;
135
140
136
141
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 )
138
147
return - EINVAL ;
139
148
priv -> current_end_threshold = val ;
140
149
} else {
141
- if (val >= priv -> current_end_threshold )
150
+ if (val > priv -> current_end_threshold )
142
151
return - EINVAL ;
143
152
priv -> current_start_threshold = val ;
144
153
}
@@ -159,6 +168,7 @@ static ssize_t charge_control_start_threshold_show(struct device *dev,
159
168
struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
160
169
CROS_CHCTL_ATTR_START_THRESHOLD );
161
170
171
+ guard (mutex )(& priv -> lock );
162
172
return sysfs_emit (buf , "%u\n" , (unsigned int )priv -> current_start_threshold );
163
173
}
164
174
@@ -169,6 +179,7 @@ static ssize_t charge_control_start_threshold_store(struct device *dev,
169
179
struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
170
180
CROS_CHCTL_ATTR_START_THRESHOLD );
171
181
182
+ guard (mutex )(& priv -> lock );
172
183
return cros_chctl_store_threshold (dev , priv , 0 , buf , count );
173
184
}
174
185
@@ -178,6 +189,7 @@ static ssize_t charge_control_end_threshold_show(struct device *dev, struct devi
178
189
struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
179
190
CROS_CHCTL_ATTR_END_THRESHOLD );
180
191
192
+ guard (mutex )(& priv -> lock );
181
193
return sysfs_emit (buf , "%u\n" , (unsigned int )priv -> current_end_threshold );
182
194
}
183
195
@@ -187,6 +199,7 @@ static ssize_t charge_control_end_threshold_store(struct device *dev, struct dev
187
199
struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
188
200
CROS_CHCTL_ATTR_END_THRESHOLD );
189
201
202
+ guard (mutex )(& priv -> lock );
190
203
return cros_chctl_store_threshold (dev , priv , 1 , buf , count );
191
204
}
192
205
@@ -195,6 +208,7 @@ static ssize_t charge_behaviour_show(struct device *dev, struct device_attribute
195
208
struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (& attr -> attr ,
196
209
CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR );
197
210
211
+ guard (mutex )(& priv -> lock );
198
212
return power_supply_charge_behaviour_show (dev , EC_CHARGE_CONTROL_BEHAVIOURS ,
199
213
priv -> current_behaviour , buf );
200
214
}
@@ -210,6 +224,7 @@ static ssize_t charge_behaviour_store(struct device *dev, struct device_attribut
210
224
if (ret < 0 )
211
225
return ret ;
212
226
227
+ guard (mutex )(& priv -> lock );
213
228
priv -> current_behaviour = ret ;
214
229
215
230
ret = cros_chctl_configure_ec (priv );
@@ -223,12 +238,10 @@ static umode_t cros_chtl_attr_is_visible(struct kobject *kobj, struct attribute
223
238
{
224
239
struct cros_chctl_priv * priv = cros_chctl_attr_to_priv (attr , n );
225
240
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 ;
232
245
233
246
return attr -> mode ;
234
247
}
@@ -290,6 +303,10 @@ static int cros_chctl_probe(struct platform_device *pdev)
290
303
if (!priv )
291
304
return - ENOMEM ;
292
305
306
+ ret = devm_mutex_init (dev , & priv -> lock );
307
+ if (ret )
308
+ return ret ;
309
+
293
310
ret = cros_ec_get_cmd_versions (cros_ec , EC_CMD_CHARGE_CONTROL );
294
311
if (ret < 0 )
295
312
return ret ;
@@ -327,7 +344,8 @@ static int cros_chctl_probe(struct platform_device *pdev)
327
344
priv -> current_end_threshold = 100 ;
328
345
329
346
/* 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 );
331
349
if (ret < 0 )
332
350
return ret ;
333
351
0 commit comments