Commit | Line | Data |
---|---|---|
37aa055c | 1 | // SPDX-License-Identifier: GPL-2.0 |
974e6f02 EBS |
2 | /* |
3 | * cros_ec_sensors_core - Common function for Chrome OS EC sensor driver. | |
4 | * | |
5 | * Copyright (C) 2016 Google, Inc | |
974e6f02 EBS |
6 | */ |
7 | ||
8 | #include <linux/delay.h> | |
9 | #include <linux/device.h> | |
10 | #include <linux/iio/buffer.h> | |
5a0b8cb4 | 11 | #include <linux/iio/common/cros_ec_sensors_core.h> |
974e6f02 EBS |
12 | #include <linux/iio/iio.h> |
13 | #include <linux/iio/kfifo_buf.h> | |
6562793b | 14 | #include <linux/iio/sysfs.h> |
80346b2b | 15 | #include <linux/iio/trigger.h> |
974e6f02 | 16 | #include <linux/iio/trigger_consumer.h> |
aa984f1b | 17 | #include <linux/iio/triggered_buffer.h> |
974e6f02 | 18 | #include <linux/kernel.h> |
974e6f02 EBS |
19 | #include <linux/module.h> |
20 | #include <linux/slab.h> | |
840d9f13 EBS |
21 | #include <linux/platform_data/cros_ec_commands.h> |
22 | #include <linux/platform_data/cros_ec_proto.h> | |
d60ac88a | 23 | #include <linux/platform_data/cros_ec_sensorhub.h> |
974e6f02 EBS |
24 | #include <linux/platform_device.h> |
25 | ||
cb875560 GG |
26 | /* |
27 | * Hard coded to the first device to support sensor fifo. The EC has a 2048 | |
28 | * byte fifo and will trigger an interrupt when fifo is 2/3 full. | |
29 | */ | |
30 | #define CROS_EC_FIFO_SIZE (2048 * 2 / 3) | |
31 | ||
3cf9df00 FL |
32 | static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev, |
33 | u16 cmd_offset, u16 cmd, u32 *mask) | |
34 | { | |
35 | int ret; | |
36 | struct { | |
37 | struct cros_ec_command msg; | |
38 | union { | |
39 | struct ec_params_get_cmd_versions params; | |
40 | struct ec_response_get_cmd_versions resp; | |
41 | }; | |
42 | } __packed buf = { | |
43 | .msg = { | |
44 | .command = EC_CMD_GET_CMD_VERSIONS + cmd_offset, | |
45 | .insize = sizeof(struct ec_response_get_cmd_versions), | |
46 | .outsize = sizeof(struct ec_params_get_cmd_versions) | |
47 | }, | |
48 | .params = {.cmd = cmd} | |
49 | }; | |
50 | ||
51 | ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg); | |
52 | if (ret >= 0) | |
53 | *mask = buf.resp.version_mask; | |
54 | return ret; | |
55 | } | |
56 | ||
ae7b02ad FL |
57 | static void get_default_min_max_freq(enum motionsensor_type type, |
58 | u32 *min_freq, | |
cb875560 GG |
59 | u32 *max_freq, |
60 | u32 *max_fifo_events) | |
ae7b02ad | 61 | { |
cb875560 GG |
62 | /* |
63 | * We don't know fifo size, set to size previously used by older | |
64 | * hardware. | |
65 | */ | |
66 | *max_fifo_events = CROS_EC_FIFO_SIZE; | |
67 | ||
ae7b02ad FL |
68 | switch (type) { |
69 | case MOTIONSENSE_TYPE_ACCEL: | |
ae7b02ad FL |
70 | *min_freq = 12500; |
71 | *max_freq = 100000; | |
72 | break; | |
33630679 GG |
73 | case MOTIONSENSE_TYPE_GYRO: |
74 | *min_freq = 25000; | |
75 | *max_freq = 100000; | |
76 | break; | |
ae7b02ad FL |
77 | case MOTIONSENSE_TYPE_MAG: |
78 | *min_freq = 5000; | |
79 | *max_freq = 25000; | |
80 | break; | |
81 | case MOTIONSENSE_TYPE_PROX: | |
82 | case MOTIONSENSE_TYPE_LIGHT: | |
83 | *min_freq = 100; | |
84 | *max_freq = 50000; | |
85 | break; | |
86 | case MOTIONSENSE_TYPE_BARO: | |
87 | *min_freq = 250; | |
88 | *max_freq = 20000; | |
89 | break; | |
90 | case MOTIONSENSE_TYPE_ACTIVITY: | |
91 | default: | |
92 | *min_freq = 0; | |
93 | *max_freq = 0; | |
94 | break; | |
95 | } | |
96 | } | |
97 | ||
6562793b GG |
98 | static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st, |
99 | int rate) | |
100 | { | |
101 | int ret; | |
102 | ||
103 | if (rate > U16_MAX) | |
104 | rate = U16_MAX; | |
105 | ||
106 | mutex_lock(&st->cmd_lock); | |
107 | st->param.cmd = MOTIONSENSE_CMD_EC_RATE; | |
108 | st->param.ec_rate.data = rate; | |
109 | ret = cros_ec_motion_send_host_cmd(st, 0); | |
110 | mutex_unlock(&st->cmd_lock); | |
111 | return ret; | |
112 | } | |
113 | ||
114 | static ssize_t cros_ec_sensor_set_report_latency(struct device *dev, | |
115 | struct device_attribute *attr, | |
116 | const char *buf, size_t len) | |
117 | { | |
118 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
119 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
120 | int integer, fract, ret; | |
121 | int latency; | |
122 | ||
123 | ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract); | |
124 | if (ret) | |
125 | return ret; | |
126 | ||
127 | /* EC rate is in ms. */ | |
128 | latency = integer * 1000 + fract / 1000; | |
129 | ret = cros_ec_sensor_set_ec_rate(st, latency); | |
130 | if (ret < 0) | |
131 | return ret; | |
132 | ||
133 | return len; | |
134 | } | |
135 | ||
136 | static ssize_t cros_ec_sensor_get_report_latency(struct device *dev, | |
137 | struct device_attribute *attr, | |
138 | char *buf) | |
139 | { | |
140 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
141 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
142 | int latency, ret; | |
143 | ||
144 | mutex_lock(&st->cmd_lock); | |
145 | st->param.cmd = MOTIONSENSE_CMD_EC_RATE; | |
146 | st->param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE; | |
147 | ||
148 | ret = cros_ec_motion_send_host_cmd(st, 0); | |
149 | latency = st->resp->ec_rate.ret; | |
150 | mutex_unlock(&st->cmd_lock); | |
151 | if (ret < 0) | |
152 | return ret; | |
153 | ||
154 | return sprintf(buf, "%d.%06u\n", | |
155 | latency / 1000, | |
156 | (latency % 1000) * 1000); | |
157 | } | |
158 | ||
159 | static IIO_DEVICE_ATTR(hwfifo_timeout, 0644, | |
160 | cros_ec_sensor_get_report_latency, | |
161 | cros_ec_sensor_set_report_latency, 0); | |
162 | ||
cb875560 GG |
163 | static ssize_t hwfifo_watermark_max_show(struct device *dev, |
164 | struct device_attribute *attr, | |
165 | char *buf) | |
166 | { | |
167 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
168 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
169 | ||
170 | return sprintf(buf, "%d\n", st->fifo_max_event_count); | |
171 | } | |
172 | ||
173 | static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0); | |
174 | ||
0a33755c MV |
175 | static const struct iio_dev_attr *cros_ec_sensor_fifo_attributes[] = { |
176 | &iio_dev_attr_hwfifo_timeout, | |
177 | &iio_dev_attr_hwfifo_watermark_max, | |
6562793b GG |
178 | NULL, |
179 | }; | |
6562793b | 180 | |
aa984f1b GG |
181 | int cros_ec_sensors_push_data(struct iio_dev *indio_dev, |
182 | s16 *data, | |
183 | s64 timestamp) | |
184 | { | |
185 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
186 | s16 *out; | |
187 | s64 delta; | |
188 | unsigned int i; | |
189 | ||
190 | /* | |
191 | * Ignore samples if the buffer is not set: it is needed if the ODR is | |
192 | * set but the buffer is not enabled yet. | |
7771c8c8 TBS |
193 | * |
194 | * Note: iio_device_claim_buffer_mode() returns -EBUSY if the buffer | |
195 | * is not enabled. | |
aa984f1b | 196 | */ |
7771c8c8 | 197 | if (iio_device_claim_buffer_mode(indio_dev) < 0) |
aa984f1b GG |
198 | return 0; |
199 | ||
200 | out = (s16 *)st->samples; | |
201 | for_each_set_bit(i, | |
202 | indio_dev->active_scan_mask, | |
203 | indio_dev->masklength) { | |
204 | *out = data[i]; | |
205 | out++; | |
206 | } | |
207 | ||
208 | if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME) | |
209 | delta = iio_get_time_ns(indio_dev) - cros_ec_get_time_ns(); | |
210 | else | |
211 | delta = 0; | |
212 | ||
213 | iio_push_to_buffers_with_timestamp(indio_dev, st->samples, | |
214 | timestamp + delta); | |
215 | ||
7771c8c8 | 216 | iio_device_release_buffer_mode(indio_dev); |
aa984f1b GG |
217 | return 0; |
218 | } | |
219 | EXPORT_SYMBOL_GPL(cros_ec_sensors_push_data); | |
220 | ||
221 | static void cros_ec_sensors_core_clean(void *arg) | |
222 | { | |
223 | struct platform_device *pdev = (struct platform_device *)arg; | |
224 | struct cros_ec_sensorhub *sensor_hub = | |
225 | dev_get_drvdata(pdev->dev.parent); | |
226 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | |
227 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
228 | u8 sensor_num = st->param.info.sensor_num; | |
229 | ||
230 | cros_ec_sensorhub_unregister_push_data(sensor_hub, sensor_num); | |
231 | } | |
232 | ||
d9452adc GG |
233 | /** |
234 | * cros_ec_sensors_core_init() - basic initialization of the core structure | |
0b4ae3f6 | 235 | * @pdev: platform device created for the sensor |
d9452adc GG |
236 | * @indio_dev: iio device structure of the device |
237 | * @physical_device: true if the device refers to a physical device | |
aa984f1b GG |
238 | * @trigger_capture: function pointer to call buffer is triggered, |
239 | * for backward compatibility. | |
d9452adc GG |
240 | * |
241 | * Return: 0 on success, -errno on failure. | |
242 | */ | |
974e6f02 EBS |
243 | int cros_ec_sensors_core_init(struct platform_device *pdev, |
244 | struct iio_dev *indio_dev, | |
aa984f1b | 245 | bool physical_device, |
0b4ae3f6 | 246 | cros_ec_sensors_capture_t trigger_capture) |
974e6f02 EBS |
247 | { |
248 | struct device *dev = &pdev->dev; | |
249 | struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); | |
d60ac88a GG |
250 | struct cros_ec_sensorhub *sensor_hub = dev_get_drvdata(dev->parent); |
251 | struct cros_ec_dev *ec = sensor_hub->ec; | |
974e6f02 | 252 | struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); |
56e4f2dd | 253 | u32 ver_mask, temp; |
317a0ebe | 254 | int frequencies[ARRAY_SIZE(state->frequencies) / 2] = { 0 }; |
22087c85 | 255 | int ret, i; |
974e6f02 EBS |
256 | |
257 | platform_set_drvdata(pdev, indio_dev); | |
258 | ||
259 | state->ec = ec->ec_dev; | |
8a462905 | 260 | state->msg = devm_kzalloc(&pdev->dev, sizeof(*state->msg) + |
974e6f02 EBS |
261 | max((u16)sizeof(struct ec_params_motion_sense), |
262 | state->ec->max_response), GFP_KERNEL); | |
263 | if (!state->msg) | |
264 | return -ENOMEM; | |
265 | ||
266 | state->resp = (struct ec_response_motion_sense *)state->msg->data; | |
267 | ||
268 | mutex_init(&state->cmd_lock); | |
269 | ||
3cf9df00 FL |
270 | ret = cros_ec_get_host_cmd_version_mask(state->ec, |
271 | ec->cmd_offset, | |
272 | EC_CMD_MOTION_SENSE_CMD, | |
273 | &ver_mask); | |
274 | if (ret < 0) | |
275 | return ret; | |
276 | ||
974e6f02 | 277 | /* Set up the host command structure. */ |
3cf9df00 | 278 | state->msg->version = fls(ver_mask) - 1; |
974e6f02 EBS |
279 | state->msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; |
280 | state->msg->outsize = sizeof(struct ec_params_motion_sense); | |
281 | ||
974e6f02 EBS |
282 | indio_dev->name = pdev->name; |
283 | ||
284 | if (physical_device) { | |
7cbb6681 GG |
285 | enum motionsensor_location loc; |
286 | ||
974e6f02 EBS |
287 | state->param.cmd = MOTIONSENSE_CMD_INFO; |
288 | state->param.info.sensor_num = sensor_platform->sensor_num; | |
f53199c0 GG |
289 | ret = cros_ec_motion_send_host_cmd(state, 0); |
290 | if (ret) { | |
974e6f02 | 291 | dev_warn(dev, "Can not access sensor info\n"); |
f53199c0 | 292 | return ret; |
974e6f02 EBS |
293 | } |
294 | state->type = state->resp->info.type; | |
7cbb6681 GG |
295 | loc = state->resp->info.location; |
296 | if (loc == MOTIONSENSE_LOC_BASE) | |
297 | indio_dev->label = "accel-base"; | |
298 | else if (loc == MOTIONSENSE_LOC_LID) | |
299 | indio_dev->label = "accel-display"; | |
300 | else if (loc == MOTIONSENSE_LOC_CAMERA) | |
301 | indio_dev->label = "accel-camera"; | |
12bf745c GG |
302 | |
303 | /* Set sign vector, only used for backward compatibility. */ | |
304 | memset(state->sign, 1, CROS_EC_SENSOR_MAX_AXIS); | |
ae7b02ad | 305 | |
22087c85 GG |
306 | for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) |
307 | state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE; | |
308 | ||
ae7b02ad | 309 | /* 0 is a correct value used to stop the device */ |
ae7b02ad FL |
310 | if (state->msg->version < 3) { |
311 | get_default_min_max_freq(state->resp->info.type, | |
317a0ebe GG |
312 | &frequencies[1], |
313 | &frequencies[2], | |
cb875560 | 314 | &state->fifo_max_event_count); |
ae7b02ad | 315 | } else { |
56e4f2dd GG |
316 | if (state->resp->info_3.max_frequency == 0) { |
317 | get_default_min_max_freq(state->resp->info.type, | |
318 | &frequencies[1], | |
319 | &frequencies[2], | |
320 | &temp); | |
321 | } else { | |
322 | frequencies[1] = state->resp->info_3.min_frequency; | |
323 | frequencies[2] = state->resp->info_3.max_frequency; | |
324 | } | |
325 | state->fifo_max_event_count = state->resp->info_3.fifo_max_event_count; | |
ae7b02ad | 326 | } |
317a0ebe GG |
327 | for (i = 0; i < ARRAY_SIZE(frequencies); i++) { |
328 | state->frequencies[2 * i] = frequencies[i] / 1000; | |
329 | state->frequencies[2 * i + 1] = | |
330 | (frequencies[i] % 1000) * 1000; | |
331 | } | |
aa984f1b GG |
332 | |
333 | if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { | |
334 | /* | |
335 | * Create a software buffer, feed by the EC FIFO. | |
336 | * We can not use trigger here, as events are generated | |
337 | * as soon as sample_frequency is set. | |
338 | */ | |
f67c6c73 | 339 | ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, NULL, |
80346b2b | 340 | cros_ec_sensor_fifo_attributes); |
17395ce2 AA |
341 | if (ret) |
342 | return ret; | |
aa984f1b | 343 | |
aa984f1b GG |
344 | /* Timestamp coming from FIFO are in ns since boot. */ |
345 | ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME); | |
346 | if (ret) | |
347 | return ret; | |
165aea80 | 348 | |
80346b2b | 349 | } else { |
aa984f1b GG |
350 | /* |
351 | * The only way to get samples in buffer is to set a | |
d18ffd83 | 352 | * software trigger (systrig, hrtimer). |
aa984f1b | 353 | */ |
80346b2b GG |
354 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, |
355 | NULL, trigger_capture, NULL); | |
aa984f1b GG |
356 | if (ret) |
357 | return ret; | |
358 | } | |
974e6f02 EBS |
359 | } |
360 | ||
361 | return 0; | |
362 | } | |
363 | EXPORT_SYMBOL_GPL(cros_ec_sensors_core_init); | |
364 | ||
0b4ae3f6 GG |
365 | /** |
366 | * cros_ec_sensors_core_register() - Register callback to FIFO and IIO when | |
367 | * sensor is ready. | |
368 | * It must be called at the end of the sensor probe routine. | |
369 | * @dev: device created for the sensor | |
370 | * @indio_dev: iio device structure of the device | |
371 | * @push_data: function to call when cros_ec_sensorhub receives | |
372 | * a sample for that sensor. | |
373 | * | |
374 | * Return: 0 on success, -errno on failure. | |
375 | */ | |
376 | int cros_ec_sensors_core_register(struct device *dev, | |
377 | struct iio_dev *indio_dev, | |
378 | cros_ec_sensorhub_push_data_cb_t push_data) | |
379 | { | |
380 | struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); | |
381 | struct cros_ec_sensorhub *sensor_hub = dev_get_drvdata(dev->parent); | |
382 | struct platform_device *pdev = to_platform_device(dev); | |
383 | struct cros_ec_dev *ec = sensor_hub->ec; | |
384 | int ret; | |
385 | ||
386 | ret = devm_iio_device_register(dev, indio_dev); | |
387 | if (ret) | |
388 | return ret; | |
389 | ||
390 | if (!push_data || | |
391 | !cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) | |
392 | return 0; | |
393 | ||
394 | ret = cros_ec_sensorhub_register_push_data( | |
395 | sensor_hub, sensor_platform->sensor_num, | |
396 | indio_dev, push_data); | |
397 | if (ret) | |
398 | return ret; | |
399 | ||
400 | return devm_add_action_or_reset( | |
401 | dev, cros_ec_sensors_core_clean, pdev); | |
402 | } | |
403 | EXPORT_SYMBOL_GPL(cros_ec_sensors_core_register); | |
404 | ||
d9452adc GG |
405 | /** |
406 | * cros_ec_motion_send_host_cmd() - send motion sense host command | |
407 | * @state: pointer to state information for device | |
408 | * @opt_length: optional length to reduce the response size, useful on the data | |
409 | * path. Otherwise, the maximal allowed response size is used | |
410 | * | |
411 | * When called, the sub-command is assumed to be set in param->cmd. | |
412 | * | |
413 | * Return: 0 on success, -errno on failure. | |
414 | */ | |
974e6f02 EBS |
415 | int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state, |
416 | u16 opt_length) | |
417 | { | |
418 | int ret; | |
419 | ||
420 | if (opt_length) | |
421 | state->msg->insize = min(opt_length, state->ec->max_response); | |
422 | else | |
423 | state->msg->insize = state->ec->max_response; | |
424 | ||
425 | memcpy(state->msg->data, &state->param, sizeof(state->param)); | |
426 | ||
427 | ret = cros_ec_cmd_xfer_status(state->ec, state->msg); | |
428 | if (ret < 0) | |
f53199c0 | 429 | return ret; |
974e6f02 EBS |
430 | |
431 | if (ret && | |
432 | state->resp != (struct ec_response_motion_sense *)state->msg->data) | |
433 | memcpy(state->resp, state->msg->data, ret); | |
434 | ||
435 | return 0; | |
436 | } | |
437 | EXPORT_SYMBOL_GPL(cros_ec_motion_send_host_cmd); | |
438 | ||
439 | static ssize_t cros_ec_sensors_calibrate(struct iio_dev *indio_dev, | |
440 | uintptr_t private, const struct iio_chan_spec *chan, | |
441 | const char *buf, size_t len) | |
442 | { | |
443 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
444 | int ret, i; | |
445 | bool calibrate; | |
446 | ||
74f582ec | 447 | ret = kstrtobool(buf, &calibrate); |
974e6f02 EBS |
448 | if (ret < 0) |
449 | return ret; | |
450 | if (!calibrate) | |
451 | return -EINVAL; | |
452 | ||
453 | mutex_lock(&st->cmd_lock); | |
454 | st->param.cmd = MOTIONSENSE_CMD_PERFORM_CALIB; | |
455 | ret = cros_ec_motion_send_host_cmd(st, 0); | |
456 | if (ret != 0) { | |
457 | dev_warn(&indio_dev->dev, "Unable to calibrate sensor\n"); | |
458 | } else { | |
459 | /* Save values */ | |
460 | for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) | |
ed1f2e85 | 461 | st->calib[i].offset = st->resp->perform_calib.offset[i]; |
974e6f02 EBS |
462 | } |
463 | mutex_unlock(&st->cmd_lock); | |
464 | ||
465 | return ret ? ret : len; | |
466 | } | |
467 | ||
8b7a6a35 GG |
468 | static ssize_t cros_ec_sensors_id(struct iio_dev *indio_dev, |
469 | uintptr_t private, | |
470 | const struct iio_chan_spec *chan, char *buf) | |
471 | { | |
472 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
473 | ||
474 | return snprintf(buf, PAGE_SIZE, "%d\n", st->param.info.sensor_num); | |
475 | } | |
476 | ||
974e6f02 EBS |
477 | const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = { |
478 | { | |
479 | .name = "calibrate", | |
480 | .shared = IIO_SHARED_BY_ALL, | |
481 | .write = cros_ec_sensors_calibrate | |
482 | }, | |
8b7a6a35 GG |
483 | { |
484 | .name = "id", | |
485 | .shared = IIO_SHARED_BY_ALL, | |
486 | .read = cros_ec_sensors_id | |
487 | }, | |
974e6f02 EBS |
488 | { }, |
489 | }; | |
490 | EXPORT_SYMBOL_GPL(cros_ec_sensors_ext_info); | |
491 | ||
492 | /** | |
493 | * cros_ec_sensors_idx_to_reg - convert index into offset in shared memory | |
494 | * @st: pointer to state information for device | |
495 | * @idx: sensor index (should be element of enum sensor_index) | |
496 | * | |
497 | * Return: address to read at | |
498 | */ | |
499 | static unsigned int cros_ec_sensors_idx_to_reg( | |
500 | struct cros_ec_sensors_core_state *st, | |
501 | unsigned int idx) | |
502 | { | |
503 | /* | |
504 | * When using LPC interface, only space for 2 Accel and one Gyro. | |
505 | * First halfword of MOTIONSENSE_TYPE_ACCEL is used by angle. | |
506 | */ | |
507 | if (st->type == MOTIONSENSE_TYPE_ACCEL) | |
508 | return EC_MEMMAP_ACC_DATA + sizeof(u16) * | |
509 | (1 + idx + st->param.info.sensor_num * | |
510 | CROS_EC_SENSOR_MAX_AXIS); | |
511 | ||
512 | return EC_MEMMAP_GYRO_DATA + sizeof(u16) * idx; | |
513 | } | |
514 | ||
515 | static int cros_ec_sensors_cmd_read_u8(struct cros_ec_device *ec, | |
516 | unsigned int offset, u8 *dest) | |
517 | { | |
518 | return ec->cmd_readmem(ec, offset, 1, dest); | |
519 | } | |
520 | ||
521 | static int cros_ec_sensors_cmd_read_u16(struct cros_ec_device *ec, | |
522 | unsigned int offset, u16 *dest) | |
523 | { | |
524 | __le16 tmp; | |
525 | int ret = ec->cmd_readmem(ec, offset, 2, &tmp); | |
526 | ||
527 | if (ret >= 0) | |
528 | *dest = le16_to_cpu(tmp); | |
529 | ||
530 | return ret; | |
531 | } | |
532 | ||
533 | /** | |
534 | * cros_ec_sensors_read_until_not_busy() - read until is not busy | |
535 | * | |
536 | * @st: pointer to state information for device | |
537 | * | |
538 | * Read from EC status byte until it reads not busy. | |
539 | * Return: 8-bit status if ok, -errno on failure. | |
540 | */ | |
541 | static int cros_ec_sensors_read_until_not_busy( | |
542 | struct cros_ec_sensors_core_state *st) | |
543 | { | |
544 | struct cros_ec_device *ec = st->ec; | |
545 | u8 status; | |
546 | int ret, attempts = 0; | |
547 | ||
548 | ret = cros_ec_sensors_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); | |
549 | if (ret < 0) | |
550 | return ret; | |
551 | ||
552 | while (status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) { | |
553 | /* Give up after enough attempts, return error. */ | |
554 | if (attempts++ >= 50) | |
555 | return -EIO; | |
556 | ||
557 | /* Small delay every so often. */ | |
558 | if (attempts % 5 == 0) | |
559 | msleep(25); | |
560 | ||
561 | ret = cros_ec_sensors_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, | |
562 | &status); | |
563 | if (ret < 0) | |
564 | return ret; | |
565 | } | |
566 | ||
567 | return status; | |
568 | } | |
569 | ||
570 | /** | |
85ece364 | 571 | * cros_ec_sensors_read_data_unsafe() - read acceleration data from EC shared memory |
974e6f02 EBS |
572 | * @indio_dev: pointer to IIO device |
573 | * @scan_mask: bitmap of the sensor indices to scan | |
574 | * @data: location to store data | |
575 | * | |
576 | * This is the unsafe function for reading the EC data. It does not guarantee | |
577 | * that the EC will not modify the data as it is being read in. | |
578 | * | |
579 | * Return: 0 on success, -errno on failure. | |
580 | */ | |
581 | static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev, | |
582 | unsigned long scan_mask, s16 *data) | |
583 | { | |
584 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
585 | struct cros_ec_device *ec = st->ec; | |
586 | unsigned int i; | |
587 | int ret; | |
588 | ||
589 | /* Read all sensors enabled in scan_mask. Each value is 2 bytes. */ | |
590 | for_each_set_bit(i, &scan_mask, indio_dev->masklength) { | |
591 | ret = cros_ec_sensors_cmd_read_u16(ec, | |
592 | cros_ec_sensors_idx_to_reg(st, i), | |
593 | data); | |
594 | if (ret < 0) | |
595 | return ret; | |
596 | ||
12bf745c | 597 | *data *= st->sign[i]; |
974e6f02 EBS |
598 | data++; |
599 | } | |
600 | ||
601 | return 0; | |
602 | } | |
603 | ||
ad9cc622 GG |
604 | /** |
605 | * cros_ec_sensors_read_lpc() - read acceleration data from EC shared memory. | |
606 | * @indio_dev: pointer to IIO device. | |
607 | * @scan_mask: bitmap of the sensor indices to scan. | |
608 | * @data: location to store data. | |
609 | * | |
610 | * Note: this is the safe function for reading the EC data. It guarantees | |
611 | * that the data sampled was not modified by the EC while being read. | |
612 | * | |
613 | * Return: 0 on success, -errno on failure. | |
614 | */ | |
974e6f02 EBS |
615 | int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, |
616 | unsigned long scan_mask, s16 *data) | |
617 | { | |
618 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
619 | struct cros_ec_device *ec = st->ec; | |
620 | u8 samp_id = 0xff, status = 0; | |
621 | int ret, attempts = 0; | |
622 | ||
623 | /* | |
624 | * Continually read all data from EC until the status byte after | |
625 | * all reads reflects that the EC is not busy and the sample id | |
626 | * matches the sample id from before all reads. This guarantees | |
627 | * that data read in was not modified by the EC while reading. | |
628 | */ | |
629 | while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT | | |
630 | EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) { | |
631 | /* If we have tried to read too many times, return error. */ | |
632 | if (attempts++ >= 5) | |
633 | return -EIO; | |
634 | ||
635 | /* Read status byte until EC is not busy. */ | |
6c02e33f CIK |
636 | ret = cros_ec_sensors_read_until_not_busy(st); |
637 | if (ret < 0) | |
638 | return ret; | |
974e6f02 EBS |
639 | |
640 | /* | |
641 | * Store the current sample id so that we can compare to the | |
642 | * sample id after reading the data. | |
643 | */ | |
6c02e33f | 644 | samp_id = ret & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; |
974e6f02 EBS |
645 | |
646 | /* Read all EC data, format it, and store it into data. */ | |
647 | ret = cros_ec_sensors_read_data_unsafe(indio_dev, scan_mask, | |
648 | data); | |
649 | if (ret < 0) | |
650 | return ret; | |
651 | ||
652 | /* Read status byte. */ | |
653 | ret = cros_ec_sensors_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, | |
654 | &status); | |
655 | if (ret < 0) | |
656 | return ret; | |
657 | } | |
658 | ||
659 | return 0; | |
660 | } | |
661 | EXPORT_SYMBOL_GPL(cros_ec_sensors_read_lpc); | |
662 | ||
d9452adc GG |
663 | /** |
664 | * cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol | |
665 | * @indio_dev: pointer to IIO device | |
666 | * @scan_mask: bitmap of the sensor indices to scan | |
667 | * @data: location to store data | |
668 | * | |
669 | * Return: 0 on success, -errno on failure. | |
670 | */ | |
974e6f02 EBS |
671 | int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, |
672 | unsigned long scan_mask, s16 *data) | |
673 | { | |
674 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
675 | int ret; | |
676 | unsigned int i; | |
677 | ||
678 | /* Read all sensor data through a command. */ | |
679 | st->param.cmd = MOTIONSENSE_CMD_DATA; | |
680 | ret = cros_ec_motion_send_host_cmd(st, sizeof(st->resp->data)); | |
681 | if (ret != 0) { | |
682 | dev_warn(&indio_dev->dev, "Unable to read sensor data\n"); | |
683 | return ret; | |
684 | } | |
685 | ||
686 | for_each_set_bit(i, &scan_mask, indio_dev->masklength) { | |
687 | *data = st->resp->data.data[i]; | |
688 | data++; | |
689 | } | |
690 | ||
691 | return 0; | |
692 | } | |
693 | EXPORT_SYMBOL_GPL(cros_ec_sensors_read_cmd); | |
694 | ||
d9452adc GG |
695 | /** |
696 | * cros_ec_sensors_capture() - the trigger handler function | |
697 | * @irq: the interrupt number. | |
698 | * @p: a pointer to the poll function. | |
699 | * | |
700 | * On a trigger event occurring, if the pollfunc is attached then this | |
701 | * handler is called as a threaded interrupt (and hence may sleep). It | |
702 | * is responsible for grabbing data from the device and pushing it into | |
703 | * the associated buffer. | |
704 | * | |
705 | * Return: IRQ_HANDLED | |
706 | */ | |
974e6f02 EBS |
707 | irqreturn_t cros_ec_sensors_capture(int irq, void *p) |
708 | { | |
709 | struct iio_poll_func *pf = p; | |
710 | struct iio_dev *indio_dev = pf->indio_dev; | |
711 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); | |
712 | int ret; | |
713 | ||
714 | mutex_lock(&st->cmd_lock); | |
715 | ||
716 | /* Clear capture data. */ | |
717 | memset(st->samples, 0, indio_dev->scan_bytes); | |
718 | ||
719 | /* Read data based on which channels are enabled in scan mask. */ | |
720 | ret = st->read_ec_sensors_data(indio_dev, | |
721 | *(indio_dev->active_scan_mask), | |
722 | (s16 *)st->samples); | |
723 | if (ret < 0) | |
724 | goto done; | |
725 | ||
726 | iio_push_to_buffers_with_timestamp(indio_dev, st->samples, | |
727 | iio_get_time_ns(indio_dev)); | |
728 | ||
729 | done: | |
730 | /* | |
731 | * Tell the core we are done with this trigger and ready for the | |
732 | * next one. | |
733 | */ | |
734 | iio_trigger_notify_done(indio_dev->trig); | |
735 | ||
736 | mutex_unlock(&st->cmd_lock); | |
737 | ||
738 | return IRQ_HANDLED; | |
739 | } | |
740 | EXPORT_SYMBOL_GPL(cros_ec_sensors_capture); | |
741 | ||
d9452adc GG |
742 | /** |
743 | * cros_ec_sensors_core_read() - function to request a value from the sensor | |
744 | * @st: pointer to state information for device | |
745 | * @chan: channel specification structure table | |
746 | * @val: will contain one element making up the returned value | |
747 | * @val2: will contain another element making up the returned value | |
748 | * @mask: specifies which values to be requested | |
749 | * | |
750 | * Return: the type of value returned by the device | |
751 | */ | |
974e6f02 EBS |
752 | int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, |
753 | struct iio_chan_spec const *chan, | |
754 | int *val, int *val2, long mask) | |
755 | { | |
317a0ebe | 756 | int ret, frequency; |
974e6f02 EBS |
757 | |
758 | switch (mask) { | |
759 | case IIO_CHAN_INFO_SAMP_FREQ: | |
974e6f02 EBS |
760 | st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; |
761 | st->param.sensor_odr.data = | |
762 | EC_MOTION_SENSE_NO_VALUE; | |
763 | ||
f53199c0 GG |
764 | ret = cros_ec_motion_send_host_cmd(st, 0); |
765 | if (ret) | |
766 | break; | |
767 | ||
317a0ebe GG |
768 | frequency = st->resp->sensor_odr.ret; |
769 | *val = frequency / 1000; | |
770 | *val2 = (frequency % 1000) * 1000; | |
771 | ret = IIO_VAL_INT_PLUS_MICRO; | |
974e6f02 EBS |
772 | break; |
773 | default: | |
f53199c0 | 774 | ret = -EINVAL; |
974e6f02 EBS |
775 | break; |
776 | } | |
777 | ||
778 | return ret; | |
779 | } | |
780 | EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read); | |
781 | ||
d9452adc GG |
782 | /** |
783 | * cros_ec_sensors_core_read_avail() - get available values | |
784 | * @indio_dev: pointer to state information for device | |
785 | * @chan: channel specification structure table | |
786 | * @vals: list of available values | |
787 | * @type: type of data returned | |
788 | * @length: number of data returned in the array | |
789 | * @mask: specifies which values to be requested | |
790 | * | |
791 | * Return: an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST | |
792 | */ | |
ae7b02ad FL |
793 | int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, |
794 | struct iio_chan_spec const *chan, | |
795 | const int **vals, | |
796 | int *type, | |
797 | int *length, | |
798 | long mask) | |
799 | { | |
800 | struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); | |
801 | ||
802 | switch (mask) { | |
803 | case IIO_CHAN_INFO_SAMP_FREQ: | |
804 | *length = ARRAY_SIZE(state->frequencies); | |
805 | *vals = (const int *)&state->frequencies; | |
317a0ebe | 806 | *type = IIO_VAL_INT_PLUS_MICRO; |
ae7b02ad FL |
807 | return IIO_AVAIL_LIST; |
808 | } | |
809 | ||
810 | return -EINVAL; | |
811 | } | |
812 | EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail); | |
813 | ||
d9452adc GG |
814 | /** |
815 | * cros_ec_sensors_core_write() - function to write a value to the sensor | |
816 | * @st: pointer to state information for device | |
817 | * @chan: channel specification structure table | |
818 | * @val: first part of value to write | |
819 | * @val2: second part of value to write | |
820 | * @mask: specifies which values to write | |
821 | * | |
822 | * Return: the type of value returned by the device | |
823 | */ | |
974e6f02 EBS |
824 | int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, |
825 | struct iio_chan_spec const *chan, | |
826 | int val, int val2, long mask) | |
827 | { | |
317a0ebe | 828 | int ret, frequency; |
974e6f02 EBS |
829 | |
830 | switch (mask) { | |
6562793b | 831 | case IIO_CHAN_INFO_SAMP_FREQ: |
317a0ebe | 832 | frequency = val * 1000 + val2 / 1000; |
974e6f02 | 833 | st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; |
317a0ebe | 834 | st->param.sensor_odr.data = frequency; |
974e6f02 EBS |
835 | |
836 | /* Always roundup, so caller gets at least what it asks for. */ | |
837 | st->param.sensor_odr.roundup = 1; | |
838 | ||
f53199c0 | 839 | ret = cros_ec_motion_send_host_cmd(st, 0); |
974e6f02 | 840 | break; |
974e6f02 EBS |
841 | default: |
842 | ret = -EINVAL; | |
843 | break; | |
844 | } | |
845 | return ret; | |
846 | } | |
847 | EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write); | |
848 | ||
e7e3b9d2 GG |
849 | static int __maybe_unused cros_ec_sensors_resume(struct device *dev) |
850 | { | |
f636fb04 | 851 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
e7e3b9d2 GG |
852 | struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); |
853 | int ret = 0; | |
854 | ||
855 | if (st->range_updated) { | |
856 | mutex_lock(&st->cmd_lock); | |
857 | st->param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; | |
858 | st->param.sensor_range.data = st->curr_range; | |
859 | st->param.sensor_range.roundup = 1; | |
860 | ret = cros_ec_motion_send_host_cmd(st, 0); | |
861 | mutex_unlock(&st->cmd_lock); | |
862 | } | |
863 | return ret; | |
864 | } | |
865 | ||
866 | SIMPLE_DEV_PM_OPS(cros_ec_sensors_pm_ops, NULL, cros_ec_sensors_resume); | |
867 | EXPORT_SYMBOL_GPL(cros_ec_sensors_pm_ops); | |
868 | ||
974e6f02 EBS |
869 | MODULE_DESCRIPTION("ChromeOS EC sensor hub core functions"); |
870 | MODULE_LICENSE("GPL v2"); |