2 * Copyright (C) 2014-2015 Intel Corporation.
8 #include <cutils/properties.h>
9 #include <hardware/sensors.h>
11 #include "enumeration.h"
12 #include "description.h"
14 #include "transform.h"
16 #define IIO_SENSOR_HAL_VERSION 1
18 #define MIN_ON_CHANGE_SAMPLING_PERIOD_US 200000 /* For on change sensors (temperature, proximity, ALS, etc.) report we support 5 Hz max (0.2 s min period) */
19 #define MAX_ON_CHANGE_SAMPLING_PERIOD_US 10000000 /* 0.1 Hz min (10 s max period)*/
20 #define ANDROID_MAX_FREQ 1000 /* 1000 Hz - This is how much Android requests for the fastest frequency */
25 * We acquire a number of parameters about sensors by reading properties.
26 * The idea here is that someone (either a script, or daemon, sets them
27 * depending on the set of sensors present on the machine.
29 * There are fallback paths in case the properties are not defined, but it is
30 * highly desirable to at least have the following for each sensor:
32 * ro.iio.anglvel.name = Gyroscope
33 * ro.iio.anglvel.vendor = Intel
34 * ro.iio.anglvel.max_range = 35
35 * ro.iio.anglvel.resolution = 0.002
36 * ro.iio.anglvel.power = 6.1
38 * Besides these, we have a couple of knobs initially used to cope with Intel
39 * Sensor Hub oddities, such as HID inspired units or firmware bugs:
41 * ro.iio.anglvel.transform = ISH
42 * ro.iio.anglvel.quirks = init-rate
44 * The "terse" quirk indicates that the underlying driver only sends events
45 * when the sensor reports a change. The HAL then periodically generates
46 * duplicate events so the sensor behaves as a continously firing one.
48 * The "noisy" quirk indicates that the underlying driver has a unusually high
49 * level of noise in its readings, and that the HAL has to accomodate it
50 * somehow, e.g. in the magnetometer calibration code path.
52 * This one is used specifically to pass a calibration scale to ALS drivers:
54 * ro.iio.illuminance.name = CPLM3218x Ambient Light Sensor
55 * ro.iio.illuminance.vendor = Capella Microsystems
56 * ro.iio.illuminance.max_range = 167000
57 * ro.iio.illuminance.resolution = 1
58 * ro.iio.illuminance.power = .001
59 * ro.iio.illuminance.illumincalib = 7400
61 * There's a 'opt_scale' specifier, documented as follows:
63 * This adds support for a scaling factor that can be expressed
64 * using properties, for all sensors, on a channel basis. That
65 * scaling factor is applied after all other transforms have been
66 * applied, and is intended as a way to compensate for problems
67 * such as an incorrect axis polarity for a given sensor.
69 * The syntax is <usual property prefix>.<channel>.opt_scale, e.g.
70 * ro.iio.accel.y.opt_scale = -1 to negate the sign of the y readings
71 * for the accelerometer.
73 * For sensors using a single channel - and only those - the channel
74 * name is implicitly void and a syntax such as ro.iio.illuminance.
75 * opt_scale = 3 has to be used.
77 * 'panel' and 'rotation' specifiers can be used to express ACPI PLD placement
78 * information ; if found they will be used in priority over the actual ACPI
79 * data. That is intended as a way to verify values during development.
81 * It's possible to use the contents of the iio device name as a way to
82 * discriminate between sensors. Several sensors of the same type can coexist:
83 * e.g. ro.iio.temp.bmg160.name = BMG160 Thermometer will be used in priority
84 * over ro.iio.temp.name = BMC150 Thermometer if the sensor for which we query
85 * properties values happen to have its iio device name set to bmg160.
88 int sensor_get_st_prop (int s, const char* sel, char val[MAX_NAME_SIZE])
90 char prop_name[PROP_NAME_MAX];
91 char prop_val[PROP_VALUE_MAX];
92 char extended_sel[PROP_VALUE_MAX];
94 int i = sensor[s].catalog_index;
95 const char *prefix = sensor_catalog[i].tag;
96 const char *shorthand = sensor_catalog[i].shorthand;
98 /* First try most specialized form, like ro.iio.anglvel.bmg160.name */
100 snprintf(extended_sel, PROP_NAME_MAX, "%s.%s",
101 sensor[s].internal_name, sel);
103 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, extended_sel);
105 if (property_get(prop_name, prop_val, "")) {
106 strncpy(val, prop_val, MAX_NAME_SIZE-1);
107 val[MAX_NAME_SIZE-1] = '\0';
111 if (shorthand[0] != '\0') {
112 /* Try with shorthand instead of prefix */
113 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, shorthand, extended_sel);
115 if (property_get(prop_name, prop_val, "")) {
116 strncpy(val, prop_val, MAX_NAME_SIZE-1);
117 val[MAX_NAME_SIZE-1] = '\0';
121 /* Fall back to simple form, like ro.iio.anglvel.name */
123 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, sel);
125 if (property_get(prop_name, prop_val, "")) {
126 strncpy(val, prop_val, MAX_NAME_SIZE-1);
127 val[MAX_NAME_SIZE-1] = '\0';
135 int sensor_get_prop (int s, const char* sel, int* val)
137 char buf[MAX_NAME_SIZE];
139 if (sensor_get_st_prop(s, sel, buf))
147 int sensor_get_fl_prop (int s, const char* sel, float* val)
149 char buf[MAX_NAME_SIZE];
151 if (sensor_get_st_prop(s, sel, buf))
154 *val = (float) strtod(buf, NULL);
159 char* sensor_get_name (int s)
161 char buf[MAX_NAME_SIZE];
163 if (sensor[s].is_virtual) {
164 switch (sensor[s].type) {
165 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
166 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
167 strcpy(buf, sensor[sensor[s].base[0]].friendly_name);
168 snprintf(sensor[s].friendly_name,
170 "%s %s", "Uncalibrated", buf);
171 return sensor[s].friendly_name;
178 if (sensor[s].friendly_name[0] != '\0' ||
179 !sensor_get_st_prop(s, "name", sensor[s].friendly_name))
180 return sensor[s].friendly_name;
182 /* If we got a iio device name from sysfs, use it */
183 if (sensor[s].internal_name[0]) {
184 snprintf(sensor[s].friendly_name, MAX_NAME_SIZE, "S%d-%s",
185 s, sensor[s].internal_name);
187 sprintf(sensor[s].friendly_name, "S%d", s);
190 return sensor[s].friendly_name;
194 char* sensor_get_vendor (int s)
196 if (sensor[s].is_virtual) {
197 switch (sensor[s].type) {
198 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
199 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
200 return sensor[sensor[s].base[0]].vendor_name;
209 if (sensor[s].vendor_name[0] ||
210 !sensor_get_st_prop(s, "vendor", sensor[s].vendor_name))
211 return sensor[s].vendor_name;
217 int sensor_get_version (__attribute__((unused)) int s)
219 return IIO_SENSOR_HAL_VERSION;
222 void sensor_update_max_range(int s)
224 if (sensor[s].max_range)
227 if (sensor[s].num_channels && sensor[s].channel[0].type_info.realbits) {
228 switch (sensor[s].type) {
229 case SENSOR_TYPE_MAGNETIC_FIELD:
230 sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) *
231 CONVERT_MICROTESLA_TO_GAUSS(sensor[s].resolution) +
232 (sensor[s].offset || sensor[s].channel[0].offset);
233 sensor[s].max_range = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].max_range);
235 case SENSOR_TYPE_PROXIMITY:
238 sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) *
239 sensor[s].resolution + (sensor[s].offset || sensor[s].channel[0].offset);
244 if (!sensor[s].max_range) {
245 /* Try returning a sensible value given the sensor type */
246 /* We should cap returned samples accordingly... */
247 switch (sensor[s].type) {
248 case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
249 sensor[s].max_range = 50;
251 case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
252 sensor[s].max_range = 500;
254 case SENSOR_TYPE_ORIENTATION: /* degrees */
255 sensor[s].max_range = 360;
257 case SENSOR_TYPE_GYROSCOPE: /* radians/s */
258 sensor[s].max_range = 10;
260 case SENSOR_TYPE_LIGHT: /* SI lux units */
261 sensor[s].max_range = 50000;
263 case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */
264 case SENSOR_TYPE_TEMPERATURE: /* °C */
265 case SENSOR_TYPE_PROXIMITY: /* centimeters */
266 case SENSOR_TYPE_PRESSURE: /* hecto-pascal */
267 case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */
268 sensor[s].max_range = 100;
273 if (sensor[s].max_range)
274 sensor_desc[s].maxRange = sensor[s].max_range;
277 float sensor_get_max_range (int s)
279 if (sensor[s].is_virtual) {
280 switch (sensor[s].type) {
281 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
282 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
283 return sensor[sensor[s].base[0]].max_range;
290 if (sensor[s].max_range != 0.0 ||
291 !sensor_get_fl_prop(s, "max_range", &sensor[s].max_range))
292 return sensor[s].max_range;
297 static float sensor_get_min_freq (int s)
300 * Check if a low cap has been specified for this sensor sampling rate.
301 * In some case, even when the driver supports lower rate, we still
302 * wish to receive a certain number of samples per seconds for various
303 * reasons (calibration, filtering, no change in power consumption...).
308 if (!sensor_get_fl_prop(s, "min_freq", &min_freq))
315 float sensor_get_max_freq (int s)
319 if (!sensor_get_fl_prop(s, "max_freq", &max_freq))
322 return ANDROID_MAX_FREQ;
325 int sensor_get_cal_steps (int s)
328 if (!sensor_get_prop(s, "cal_steps", &cal_steps))
334 float sensor_get_resolution (int s)
336 if (sensor[s].is_virtual) {
337 switch (sensor[s].type) {
338 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
339 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
340 return sensor[sensor[s].base[0]].resolution;
347 if (sensor[s].resolution != 0.0 ||
348 !sensor_get_fl_prop(s, "resolution", &sensor[s].resolution)) {
349 return sensor[s].resolution;
352 sensor[s].resolution = sensor[s].scale;
353 if (!sensor[s].resolution && sensor[s].num_channels)
354 sensor[s].resolution = sensor[s].channel[0].scale;
356 if (sensor[s].type == SENSOR_TYPE_MAGNETIC_FIELD)
357 sensor[s].resolution = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].resolution);
359 return sensor[s].resolution ? : 1;
363 float sensor_get_power (int s)
366 if (sensor[s].is_virtual) {
367 switch (sensor[s].type) {
368 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
369 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
370 return sensor[sensor[s].base[0]].power;
377 /* mA used while sensor is in use ; not sure about volts :) */
378 if (sensor[s].power != 0.0 ||
379 !sensor_get_fl_prop(s, "power", &sensor[s].power))
380 return sensor[s].power;
386 float sensor_get_illumincalib (int s)
388 /* calibrating the ALS Sensor*/
389 if (sensor[s].illumincalib != 0.0 ||
390 !sensor_get_fl_prop(s, "illumincalib", &sensor[s].illumincalib)) {
391 return sensor[s].illumincalib;
398 uint32_t sensor_get_quirks (int s)
400 char quirks_buf[MAX_NAME_SIZE];
402 /* Read and decode quirks property on first reference */
403 if (!(sensor[s].quirks & QUIRK_ALREADY_DECODED)) {
404 quirks_buf[0] = '\0';
405 sensor_get_st_prop(s, "quirks", quirks_buf);
407 if (strstr(quirks_buf, "init-rate"))
408 sensor[s].quirks |= QUIRK_INITIAL_RATE;
410 if (strstr(quirks_buf, "continuous"))
411 sensor[s].quirks |= QUIRK_FORCE_CONTINUOUS;
413 if (strstr(quirks_buf, "terse"))
414 sensor[s].quirks |= QUIRK_TERSE_DRIVER;
416 if (strstr(quirks_buf, "noisy"))
417 sensor[s].quirks |= QUIRK_NOISY;
419 if (strstr(quirks_buf, "biased"))
420 sensor[s].quirks |= QUIRK_BIASED;
422 if (strstr(quirks_buf, "spotty"))
423 sensor[s].quirks |= QUIRK_SPOTTY;
425 if (strstr(quirks_buf, "no-event"))
426 sensor[s].quirks |= QUIRK_NO_EVENT_MODE;
428 if (strstr(quirks_buf, "no-trig"))
429 sensor[s].quirks |= QUIRK_NO_TRIG_MODE;
431 if (strstr(quirks_buf, "no-poll"))
432 sensor[s].quirks |= QUIRK_NO_POLL_MODE;
434 if (strstr(quirks_buf, "hrtimer"))
435 sensor[s].quirks |= QUIRK_HRTIMER;
437 if (strstr(quirks_buf, "secondary"))
438 sensor[s].quirks |= QUIRK_SECONDARY;
440 sensor[s].quirks |= QUIRK_ALREADY_DECODED;
443 return sensor[s].quirks;
447 int sensor_get_order (int s, unsigned char map[MAX_CHANNELS])
449 char buf[MAX_NAME_SIZE];
451 int count = sensor_catalog[sensor[s].catalog_index].num_channels;
453 if (sensor_get_st_prop(s, "order", buf))
454 return 0; /* No order property */
456 /* Assume ASCII characters, in the '0'..'9' range */
458 for (i=0; i<count; i++)
459 if (buf[i] - '0' >= count) {
460 ALOGE("Order index out of range for sensor %d\n", s);
464 for (i=0; i<count; i++)
465 map[i] = buf[i] - '0';
467 return 1; /* OK to use modified ordering map */
470 int sensor_get_available_frequencies (int s)
472 int dev_num = sensor[s].dev_num, err, i;
473 char avail_sysfs_path[PATH_MAX], freqs_buf[100];
477 sensor[s].avail_freqs_count = 0;
478 sensor[s].avail_freqs = 0;
480 sprintf(avail_sysfs_path, DEVICE_AVAIL_FREQ_PATH, dev_num);
482 err = sysfs_read_str(avail_sysfs_path, freqs_buf, sizeof(freqs_buf));
486 for (p = freqs_buf, f = strtof(p, &end); p != end; p = end, f = strtof(p, &end))
487 sensor[s].avail_freqs_count++;
489 if (sensor[s].avail_freqs_count) {
490 sensor[s].avail_freqs = (float*) calloc(sensor[s].avail_freqs_count, sizeof(float));
492 for (p = freqs_buf, f = strtof(p, &end), i = 0; p != end; p = end, f = strtof(p, &end), i++)
493 sensor[s].avail_freqs[i] = f;
499 int sensor_get_mounting_matrix (int s, float mm[9])
501 int dev_num = sensor[s].dev_num, err, i;
502 char mm_path[PATH_MAX], mm_buf[100];
503 char *tmp1 = mm_buf, *tmp2;
505 switch (sensor[s].type) {
506 case SENSOR_TYPE_ACCELEROMETER:
507 case SENSOR_TYPE_MAGNETIC_FIELD:
508 case SENSOR_TYPE_GYROSCOPE:
509 case SENSOR_TYPE_PROXIMITY:
515 sprintf(mm_path, MOUNTING_MATRIX_PATH, dev_num);
517 err = sysfs_read_str(mm_path, mm_buf, sizeof(mm_buf));
521 for(i = 0; i < 9; i++) {
524 f = strtof(tmp1, &tmp2);
525 if (!f && tmp1 == tmp2)
532 * For proximity sensors, interpret a negative final z value as a hint that the sensor is back mounted. In that case, mark the sensor as secondary to
533 * ensure that it gets listed after other sensors of same type that would be front-mounted. Most applications will only ask for the default proximity
534 * sensor and it makes more sense to point to, say, the IR based proximity sensor rather than SAR based one if we have both, as on SoFIA LTE MRD boards.
536 if (sensor[s].type == SENSOR_TYPE_PROXIMITY) {
538 sensor[s].quirks |= QUIRK_SECONDARY;
543 ALOGI("%s: %f %f %f %f %f %f %f %f %f\n", __func__, mm[0], mm[1], mm[2], mm[3], mm[4], mm[5], mm[6], mm[7], mm[8]);
548 char* sensor_get_string_type (int s)
550 switch (sensor_desc[s].type) {
551 case SENSOR_TYPE_ACCELEROMETER:
552 return SENSOR_STRING_TYPE_ACCELEROMETER;
554 case SENSOR_TYPE_MAGNETIC_FIELD:
555 return SENSOR_STRING_TYPE_MAGNETIC_FIELD;
557 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
558 return SENSOR_STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
560 case SENSOR_TYPE_ORIENTATION:
561 return SENSOR_STRING_TYPE_ORIENTATION;
563 case SENSOR_TYPE_GYROSCOPE:
564 return SENSOR_STRING_TYPE_GYROSCOPE;
566 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
567 return SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
569 case SENSOR_TYPE_LIGHT:
570 return SENSOR_STRING_TYPE_LIGHT;
572 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
573 return SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
575 case SENSOR_TYPE_TEMPERATURE:
576 return SENSOR_STRING_TYPE_TEMPERATURE;
578 case SENSOR_TYPE_PROXIMITY:
579 return SENSOR_STRING_TYPE_PROXIMITY;
581 case SENSOR_TYPE_PRESSURE:
582 return SENSOR_STRING_TYPE_PRESSURE;
584 case SENSOR_TYPE_RELATIVE_HUMIDITY:
585 return SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
593 flag_t sensor_get_flags (int s)
597 switch (sensor_desc[s].type) {
598 case SENSOR_TYPE_LIGHT:
599 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
600 case SENSOR_TYPE_TEMPERATURE:
601 case SENSOR_TYPE_RELATIVE_HUMIDITY:
602 case SENSOR_TYPE_STEP_COUNTER:
603 flags |= SENSOR_FLAG_ON_CHANGE_MODE;
607 case SENSOR_TYPE_PROXIMITY:
608 flags |= SENSOR_FLAG_WAKE_UP;
609 flags |= SENSOR_FLAG_ON_CHANGE_MODE;
611 case SENSOR_TYPE_STEP_DETECTOR:
612 flags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
621 static int get_cdd_freq (int s, int must)
623 switch (sensor_desc[s].type) {
624 case SENSOR_TYPE_ACCELEROMETER:
625 return (must ? 100 : 200); /* must 100 Hz, should 200 Hz, CDD compliant */
627 case SENSOR_TYPE_GYROSCOPE:
628 return (must ? 200 : 200); /* must 200 Hz, should 200 Hz, CDD compliant */
630 case SENSOR_TYPE_MAGNETIC_FIELD:
631 return (must ? 10 : 50); /* must 10 Hz, should 50 Hz, CDD compliant */
633 case SENSOR_TYPE_LIGHT:
634 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
635 case SENSOR_TYPE_TEMPERATURE:
636 return (must ? 1 : 2); /* must 1 Hz, should 2Hz, not mentioned in CDD */
639 return 1; /* Use 1 Hz by default, e.g. for proximity */
644 * This value is defined only for continuous mode and on-change sensors. It is the delay between two sensor events corresponding to the lowest frequency that
645 * this sensor supports. When lower frequencies are requested through batch()/setDelay() the events will be generated at this frequency instead. It can be used
646 * by the framework or applications to estimate when the batch FIFO may be full. maxDelay should always fit within a 32 bit signed integer. It is declared as
647 * 64 bit on 64 bit architectures only for binary compatibility reasons. Availability: SENSORS_DEVICE_API_VERSION_1_3
649 max_delay_t sensor_get_max_delay (int s)
651 int dev_num = sensor[s].dev_num, i;
652 float min_supported_rate;
656 * continuous, on-change: maximum sampling period allowed in microseconds.
657 * one-shot, special : 0
659 switch (REPORTING_MODE(sensor_desc[s].flags)) {
660 case SENSOR_FLAG_ONE_SHOT_MODE:
661 case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
664 case SENSOR_FLAG_ON_CHANGE_MODE:
665 return MAX_ON_CHANGE_SAMPLING_PERIOD_US;
671 if (sensor[s].is_virtual) {
672 switch (sensor[s].type) {
673 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
674 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
675 return sensor_desc[sensor[s].base[0]].maxDelay;
681 switch (sensor[s].mode) {
683 /* For interrupt-based devices, obey the list of supported sampling rates */
684 if (!(sensor_get_quirks(s) & QUIRK_HRTIMER) &&
685 sensor[s].avail_freqs_count) {
686 min_supported_rate = 1000;
687 for (i = 0; i < sensor[s].avail_freqs_count; i++) {
688 if (sensor[s].avail_freqs[i] < min_supported_rate)
689 min_supported_rate = sensor[s].avail_freqs[i];
693 /* Fall through ... */
697 min_supported_rate = 1;
701 /* Check if a minimum rate was specified for this sensor */
702 rate_cap = sensor_get_min_freq(s);
704 if (min_supported_rate < rate_cap)
705 min_supported_rate = rate_cap;
707 /* return 0 for wrong values */
708 if (min_supported_rate < 0.1)
711 /* Return microseconds */
712 return (max_delay_t) (1000000.0 / min_supported_rate);
716 int32_t sensor_get_min_delay (int s)
718 int dev_num = sensor[s].dev_num, i;
719 float max_supported_rate = 0;
720 float max_from_prop = sensor_get_max_freq(s);
721 int hrtimer_quirk_enabled = sensor_get_quirks(s) & QUIRK_HRTIMER;
723 /* continuous, on change: minimum sampling period allowed in microseconds.
724 * special : 0, unless otherwise noted
727 switch (REPORTING_MODE(sensor_desc[s].flags)) {
728 case SENSOR_FLAG_ON_CHANGE_MODE:
729 return MIN_ON_CHANGE_SAMPLING_PERIOD_US;
731 case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
734 case SENSOR_FLAG_ONE_SHOT_MODE:
741 if (sensor[s].is_virtual) {
742 switch (sensor[s].type) {
743 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
744 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
745 return sensor_desc[sensor[s].base[0]].minDelay;
751 if (hrtimer_quirk_enabled || !sensor[s].avail_freqs_count) {
752 if (hrtimer_quirk_enabled || (sensor[s].mode == MODE_POLL)) {
753 /* If we have max specified via a property use it */
754 if (max_from_prop != ANDROID_MAX_FREQ)
755 max_supported_rate = max_from_prop;
757 /* The should rate */
758 max_supported_rate = get_cdd_freq(s, 0);
761 for (i = 0; i < sensor[s].avail_freqs_count; i++) {
762 if (sensor[s].avail_freqs[i] > max_supported_rate &&
763 sensor[s].avail_freqs[i] <= max_from_prop) {
764 max_supported_rate = sensor[s].avail_freqs[i];
769 /* return 0 for wrong values */
770 if (max_supported_rate < 0.1)
773 /* Return microseconds */
774 return (int32_t) (1000000.0 / max_supported_rate);