2 // Copyright (c) 2015 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
19 #include <utils/Log.h>
20 #include <cutils/properties.h>
21 #include <hardware/sensors.h>
23 #include "enumeration.h"
24 #include "description.h"
26 #include "transform.h"
28 #define IIO_SENSOR_HAL_VERSION 1
30 #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) */
31 #define MAX_ON_CHANGE_SAMPLING_PERIOD_US 10000000 /* 0.1 Hz min (10 s max period)*/
32 #define ANDROID_MAX_FREQ 1000 /* 1000 Hz - This is how much Android requests for the fastest frequency */
37 * We acquire a number of parameters about sensors by reading properties.
38 * The idea here is that someone (either a script, or daemon, sets them
39 * depending on the set of sensors present on the machine.
41 * There are fallback paths in case the properties are not defined, but it is
42 * highly desirable to at least have the following for each sensor:
44 * ro.iio.anglvel.name = Gyroscope
45 * ro.iio.anglvel.vendor = Intel
46 * ro.iio.anglvel.max_range = 35
47 * ro.iio.anglvel.resolution = 0.002
48 * ro.iio.anglvel.power = 6.1
50 * Besides these, we have a couple of knobs initially used to cope with Intel
51 * Sensor Hub oddities, such as HID inspired units or firmware bugs:
53 * ro.iio.anglvel.transform = ISH
54 * ro.iio.anglvel.quirks = init-rate
56 * The "terse" quirk indicates that the underlying driver only sends events
57 * when the sensor reports a change. The HAL then periodically generates
58 * duplicate events so the sensor behaves as a continously firing one.
60 * The "noisy" quirk indicates that the underlying driver has a unusually high
61 * level of noise in its readings, and that the HAL has to accomodate it
62 * somehow, e.g. in the magnetometer calibration code path.
64 * This one is used specifically to pass a calibration scale to ALS drivers:
66 * ro.iio.illuminance.name = CPLM3218x Ambient Light Sensor
67 * ro.iio.illuminance.vendor = Capella Microsystems
68 * ro.iio.illuminance.max_range = 167000
69 * ro.iio.illuminance.resolution = 1
70 * ro.iio.illuminance.power = .001
71 * ro.iio.illuminance.illumincalib = 7400
73 * There's a 'opt_scale' specifier, documented as follows:
75 * This adds support for a scaling factor that can be expressed
76 * using properties, for all sensors, on a channel basis. That
77 * scaling factor is applied after all other transforms have been
78 * applied, and is intended as a way to compensate for problems
79 * such as an incorrect axis polarity for a given sensor.
81 * The syntax is <usual property prefix>.<channel>.opt_scale, e.g.
82 * ro.iio.accel.y.opt_scale = -1 to negate the sign of the y readings
83 * for the accelerometer.
85 * For sensors using a single channel - and only those - the channel
86 * name is implicitly void and a syntax such as ro.iio.illuminance.
87 * opt_scale = 3 has to be used.
89 * 'panel' and 'rotation' specifiers can be used to express ACPI PLD placement
90 * information ; if found they will be used in priority over the actual ACPI
91 * data. That is intended as a way to verify values during development.
93 * It's possible to use the contents of the iio device name as a way to
94 * discriminate between sensors. Several sensors of the same type can coexist:
95 * e.g. ro.iio.temp.bmg160.name = BMG160 Thermometer will be used in priority
96 * over ro.iio.temp.name = BMC150 Thermometer if the sensor for which we query
97 * properties values happen to have its iio device name set to bmg160.
100 int sensor_get_st_prop (int s, const char* sel, char val[MAX_NAME_SIZE])
102 char prop_name[PROP_NAME_MAX];
103 char prop_val[PROP_VALUE_MAX];
104 char extended_sel[PROP_VALUE_MAX];
106 int i = sensor[s].catalog_index;
107 const char *prefix = sensor_catalog[i].tag;
108 const char *shorthand = sensor_catalog[i].shorthand;
110 /* First try most specialized form, like ro.iio.anglvel.bmg160.name */
112 snprintf(extended_sel, PROP_NAME_MAX, "%s.%s",
113 sensor[s].internal_name, sel);
115 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, extended_sel);
117 if (property_get(prop_name, prop_val, "")) {
118 strncpy(val, prop_val, MAX_NAME_SIZE-1);
119 val[MAX_NAME_SIZE-1] = '\0';
123 if (shorthand[0] != '\0') {
124 /* Try with shorthand instead of prefix */
125 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, shorthand, extended_sel);
127 if (property_get(prop_name, prop_val, "")) {
128 strncpy(val, prop_val, MAX_NAME_SIZE-1);
129 val[MAX_NAME_SIZE-1] = '\0';
133 /* Fall back to simple form, like ro.iio.anglvel.name */
135 snprintf(prop_name, PROP_NAME_MAX, PROP_BASE, prefix, sel);
137 if (property_get(prop_name, prop_val, "")) {
138 strncpy(val, prop_val, MAX_NAME_SIZE-1);
139 val[MAX_NAME_SIZE-1] = '\0';
147 int sensor_get_prop (int s, const char* sel, int* val)
149 char buf[MAX_NAME_SIZE];
151 if (sensor_get_st_prop(s, sel, buf))
159 int sensor_get_fl_prop (int s, const char* sel, float* val)
161 char buf[MAX_NAME_SIZE];
163 if (sensor_get_st_prop(s, sel, buf))
166 *val = (float) strtod(buf, NULL);
171 char* sensor_get_name (int s)
173 char buf[MAX_NAME_SIZE];
175 if (sensor[s].is_virtual) {
176 switch (sensor[s].type) {
177 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
178 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
179 strcpy(buf, sensor[sensor[s].base[0]].friendly_name);
180 snprintf(sensor[s].friendly_name,
182 "%s %s", "Uncalibrated", buf);
183 return sensor[s].friendly_name;
190 if (sensor[s].friendly_name[0] != '\0' ||
191 !sensor_get_st_prop(s, "name", sensor[s].friendly_name))
192 return sensor[s].friendly_name;
194 /* If we got a iio device name from sysfs, use it */
195 if (sensor[s].internal_name[0]) {
196 snprintf(sensor[s].friendly_name, MAX_NAME_SIZE, "S%d-%s",
197 s, sensor[s].internal_name);
199 sprintf(sensor[s].friendly_name, "S%d", s);
202 return sensor[s].friendly_name;
206 char* sensor_get_vendor (int s)
208 if (sensor[s].is_virtual) {
209 switch (sensor[s].type) {
210 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
211 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
212 return sensor[sensor[s].base[0]].vendor_name;
221 if (sensor[s].vendor_name[0] ||
222 !sensor_get_st_prop(s, "vendor", sensor[s].vendor_name))
223 return sensor[s].vendor_name;
229 int sensor_get_version (__attribute__((unused)) int s)
231 return IIO_SENSOR_HAL_VERSION;
234 void sensor_update_max_range(int s)
236 if (sensor[s].max_range)
239 if (sensor[s].num_channels && sensor[s].channel[0].type_info.realbits) {
240 switch (sensor[s].type) {
241 case SENSOR_TYPE_MAGNETIC_FIELD:
242 sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) *
243 CONVERT_MICROTESLA_TO_GAUSS(sensor[s].resolution) +
244 (sensor[s].offset || sensor[s].channel[0].offset);
245 sensor[s].max_range = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].max_range);
247 case SENSOR_TYPE_PROXIMITY:
250 sensor[s].max_range = (1ULL << sensor[s].channel[0].type_info.realbits) *
251 sensor[s].resolution + (sensor[s].offset || sensor[s].channel[0].offset);
256 if (!sensor[s].max_range) {
257 /* Try returning a sensible value given the sensor type */
258 /* We should cap returned samples accordingly... */
259 switch (sensor[s].type) {
260 case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
261 sensor[s].max_range = 50;
263 case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
264 sensor[s].max_range = 500;
266 case SENSOR_TYPE_ORIENTATION: /* degrees */
267 sensor[s].max_range = 360;
269 case SENSOR_TYPE_GYROSCOPE: /* radians/s */
270 sensor[s].max_range = 10;
272 case SENSOR_TYPE_LIGHT: /* SI lux units */
273 sensor[s].max_range = 50000;
275 case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */
276 case SENSOR_TYPE_TEMPERATURE: /* °C */
277 case SENSOR_TYPE_PROXIMITY: /* centimeters */
278 case SENSOR_TYPE_PRESSURE: /* hecto-pascal */
279 case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */
280 sensor[s].max_range = 100;
285 if (sensor[s].max_range)
286 sensor_desc[s].maxRange = sensor[s].max_range;
289 float sensor_get_max_range (int s)
291 if (sensor[s].is_virtual) {
292 switch (sensor[s].type) {
293 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
294 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
295 return sensor[sensor[s].base[0]].max_range;
302 if (sensor[s].max_range != 0.0 ||
303 !sensor_get_fl_prop(s, "max_range", &sensor[s].max_range))
304 return sensor[s].max_range;
309 float sensor_get_min_freq (int s)
312 * Check if a low cap has been specified for this sensor sampling rate.
313 * In some case, even when the driver supports lower rate, we still
314 * wish to receive a certain number of samples per seconds for various
315 * reasons (calibration, filtering, no change in power consumption...).
320 if (!sensor_get_fl_prop(s, "min_freq", &min_freq))
327 float sensor_get_max_freq (int s)
331 if (!sensor_get_fl_prop(s, "max_freq", &max_freq))
334 return ANDROID_MAX_FREQ;
337 int sensor_get_cal_steps (int s)
340 if (!sensor_get_prop(s, "cal_steps", &cal_steps))
346 float sensor_get_resolution (int s)
348 if (sensor[s].is_virtual) {
349 switch (sensor[s].type) {
350 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
351 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
352 return sensor[sensor[s].base[0]].resolution;
359 if (sensor[s].resolution != 0.0 ||
360 !sensor_get_fl_prop(s, "resolution", &sensor[s].resolution)) {
361 return sensor[s].resolution;
364 sensor[s].resolution = sensor[s].scale;
365 if (!sensor[s].resolution && sensor[s].num_channels)
366 sensor[s].resolution = sensor[s].channel[0].scale;
368 if (sensor[s].type == SENSOR_TYPE_MAGNETIC_FIELD)
369 sensor[s].resolution = CONVERT_GAUSS_TO_MICROTESLA(sensor[s].resolution);
371 return sensor[s].resolution ? : 1;
375 float sensor_get_power (int s)
378 if (sensor[s].is_virtual) {
379 switch (sensor[s].type) {
380 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
381 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
382 return sensor[sensor[s].base[0]].power;
389 /* mA used while sensor is in use ; not sure about volts :) */
390 if (sensor[s].power != 0.0 ||
391 !sensor_get_fl_prop(s, "power", &sensor[s].power))
392 return sensor[s].power;
398 float sensor_get_illumincalib (int s)
400 /* calibrating the ALS Sensor*/
401 if (sensor[s].illumincalib != 0.0 ||
402 !sensor_get_fl_prop(s, "illumincalib", &sensor[s].illumincalib)) {
403 return sensor[s].illumincalib;
410 uint32_t sensor_get_quirks (int s)
412 char quirks_buf[MAX_NAME_SIZE];
414 /* Read and decode quirks property on first reference */
415 if (!(sensor[s].quirks & QUIRK_ALREADY_DECODED)) {
416 quirks_buf[0] = '\0';
417 sensor_get_st_prop(s, "quirks", quirks_buf);
419 if (strstr(quirks_buf, "init-rate"))
420 sensor[s].quirks |= QUIRK_INITIAL_RATE;
422 if (strstr(quirks_buf, "continuous"))
423 sensor[s].quirks |= QUIRK_FORCE_CONTINUOUS;
425 if (strstr(quirks_buf, "terse"))
426 sensor[s].quirks |= QUIRK_TERSE_DRIVER;
428 if (strstr(quirks_buf, "noisy"))
429 sensor[s].quirks |= QUIRK_NOISY;
431 if (strstr(quirks_buf, "biased"))
432 sensor[s].quirks |= QUIRK_BIASED;
434 if (strstr(quirks_buf, "spotty"))
435 sensor[s].quirks |= QUIRK_SPOTTY;
437 if (strstr(quirks_buf, "no-event"))
438 sensor[s].quirks |= QUIRK_NO_EVENT_MODE;
440 if (strstr(quirks_buf, "no-trig"))
441 sensor[s].quirks |= QUIRK_NO_TRIG_MODE;
443 if (strstr(quirks_buf, "no-poll"))
444 sensor[s].quirks |= QUIRK_NO_POLL_MODE;
446 if (strstr(quirks_buf, "hrtimer"))
447 sensor[s].quirks |= QUIRK_HRTIMER;
449 if (strstr(quirks_buf, "secondary"))
450 sensor[s].quirks |= QUIRK_SECONDARY;
452 sensor[s].quirks |= QUIRK_ALREADY_DECODED;
455 return sensor[s].quirks;
459 int sensor_get_order (int s, unsigned char map[MAX_CHANNELS])
461 char buf[MAX_NAME_SIZE];
463 int count = sensor_catalog[sensor[s].catalog_index].num_channels;
465 if (sensor_get_st_prop(s, "order", buf))
466 return 0; /* No order property */
468 /* Assume ASCII characters, in the '0'..'9' range */
470 for (i=0; i<count; i++)
471 if (buf[i] - '0' >= count) {
472 ALOGE("Order index out of range for sensor %d\n", s);
476 for (i=0; i<count; i++)
477 map[i] = buf[i] - '0';
479 return 1; /* OK to use modified ordering map */
482 int sensor_get_available_frequencies (int s)
484 int dev_num = sensor[s].dev_num, err, i;
485 char avail_sysfs_path[PATH_MAX], freqs_buf[100];
489 sensor[s].avail_freqs_count = 0;
490 sensor[s].avail_freqs = 0;
492 sprintf(avail_sysfs_path, DEVICE_AVAIL_FREQ_PATH, dev_num);
494 err = sysfs_read_str(avail_sysfs_path, freqs_buf, sizeof(freqs_buf));
498 for (p = freqs_buf, f = strtof(p, &end); p != end; p = end, f = strtof(p, &end))
499 sensor[s].avail_freqs_count++;
501 if (sensor[s].avail_freqs_count) {
502 sensor[s].avail_freqs = (float*) calloc(sensor[s].avail_freqs_count, sizeof(float));
504 for (p = freqs_buf, f = strtof(p, &end), i = 0; p != end; p = end, f = strtof(p, &end), i++)
505 sensor[s].avail_freqs[i] = f;
511 int sensor_get_mounting_matrix (int s, float mm[9])
513 int dev_num = sensor[s].dev_num, err, i;
514 char mm_path[PATH_MAX], mm_buf[100];
515 char *tmp1 = mm_buf, *tmp2;
517 switch (sensor[s].type) {
518 case SENSOR_TYPE_ACCELEROMETER:
519 case SENSOR_TYPE_MAGNETIC_FIELD:
520 case SENSOR_TYPE_GYROSCOPE:
521 case SENSOR_TYPE_PROXIMITY:
527 sprintf(mm_path, MOUNTING_MATRIX_PATH, dev_num);
529 err = sysfs_read_str(mm_path, mm_buf, sizeof(mm_buf));
533 for(i = 0; i < 9; i++) {
536 f = strtof(tmp1, &tmp2);
537 if (!f && tmp1 == tmp2)
544 * 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
545 * 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
546 * 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.
548 if (sensor[s].type == SENSOR_TYPE_PROXIMITY) {
550 sensor[s].quirks |= QUIRK_SECONDARY;
555 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]);
560 char* sensor_get_string_type (int s)
562 switch (sensor_desc[s].type) {
563 case SENSOR_TYPE_ACCELEROMETER:
564 return SENSOR_STRING_TYPE_ACCELEROMETER;
566 case SENSOR_TYPE_MAGNETIC_FIELD:
567 return SENSOR_STRING_TYPE_MAGNETIC_FIELD;
569 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
570 return SENSOR_STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
572 case SENSOR_TYPE_ORIENTATION:
573 return SENSOR_STRING_TYPE_ORIENTATION;
575 case SENSOR_TYPE_GYROSCOPE:
576 return SENSOR_STRING_TYPE_GYROSCOPE;
578 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
579 return SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
581 case SENSOR_TYPE_LIGHT:
582 return SENSOR_STRING_TYPE_LIGHT;
584 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
585 return SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
587 case SENSOR_TYPE_TEMPERATURE:
588 return SENSOR_STRING_TYPE_TEMPERATURE;
590 case SENSOR_TYPE_PROXIMITY:
591 return SENSOR_STRING_TYPE_PROXIMITY;
593 case SENSOR_TYPE_PRESSURE:
594 return SENSOR_STRING_TYPE_PRESSURE;
596 case SENSOR_TYPE_RELATIVE_HUMIDITY:
597 return SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
605 flag_t sensor_get_flags (int s)
609 switch (sensor_desc[s].type) {
610 case SENSOR_TYPE_LIGHT:
611 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
612 case SENSOR_TYPE_TEMPERATURE:
613 case SENSOR_TYPE_RELATIVE_HUMIDITY:
614 case SENSOR_TYPE_STEP_COUNTER:
615 flags |= SENSOR_FLAG_ON_CHANGE_MODE;
619 case SENSOR_TYPE_PROXIMITY:
620 flags |= SENSOR_FLAG_WAKE_UP;
621 flags |= SENSOR_FLAG_ON_CHANGE_MODE;
623 case SENSOR_TYPE_STEP_DETECTOR:
624 flags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
633 static int get_cdd_freq (int s, int must)
635 switch (sensor_desc[s].type) {
636 case SENSOR_TYPE_ACCELEROMETER:
637 return (must ? 100 : 200); /* must 100 Hz, should 200 Hz, CDD compliant */
639 case SENSOR_TYPE_GYROSCOPE:
640 return (must ? 200 : 200); /* must 200 Hz, should 200 Hz, CDD compliant */
642 case SENSOR_TYPE_MAGNETIC_FIELD:
643 return (must ? 10 : 50); /* must 10 Hz, should 50 Hz, CDD compliant */
645 case SENSOR_TYPE_LIGHT:
646 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
647 case SENSOR_TYPE_TEMPERATURE:
648 return (must ? 1 : 2); /* must 1 Hz, should 2Hz, not mentioned in CDD */
651 return 1; /* Use 1 Hz by default, e.g. for proximity */
656 * 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
657 * this sensor supports. When lower frequencies are requested through batch()/setDelay() the events will be generated at this frequency instead. It can be used
658 * 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
659 * 64 bit on 64 bit architectures only for binary compatibility reasons. Availability: SENSORS_DEVICE_API_VERSION_1_3
661 max_delay_t sensor_get_max_delay (int s)
664 float min_supported_rate;
668 * continuous, on-change: maximum sampling period allowed in microseconds.
669 * one-shot, special : 0
671 switch (REPORTING_MODE(sensor_desc[s].flags)) {
672 case SENSOR_FLAG_ONE_SHOT_MODE:
673 case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
676 case SENSOR_FLAG_ON_CHANGE_MODE:
677 return MAX_ON_CHANGE_SAMPLING_PERIOD_US;
683 if (sensor[s].is_virtual) {
684 switch (sensor[s].type) {
685 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
686 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
687 return sensor_desc[sensor[s].base[0]].maxDelay;
693 switch (sensor[s].mode) {
695 /* For interrupt-based devices, obey the list of supported sampling rates */
696 if (sensor[s].avail_freqs_count) {
697 min_supported_rate = 1000;
698 for (i = 0; i < sensor[s].avail_freqs_count; i++) {
699 if (sensor[s].avail_freqs[i] < min_supported_rate)
700 min_supported_rate = sensor[s].avail_freqs[i];
704 /* Fall through ... */
708 min_supported_rate = 1;
712 /* Check if a minimum rate was specified for this sensor */
713 rate_cap = sensor_get_min_freq(s);
715 if (min_supported_rate < rate_cap)
716 min_supported_rate = rate_cap;
718 /* return 0 for wrong values */
719 if (min_supported_rate < 0.1)
722 /* Return microseconds */
723 return (max_delay_t) (1000000.0 / min_supported_rate);
726 float sensor_get_max_static_freq(int s)
728 float max_from_prop = sensor_get_max_freq(s);
730 /* If we have max specified via a property use it */
731 if (max_from_prop != ANDROID_MAX_FREQ) {
732 return max_from_prop;
734 /* The should rate */
735 return get_cdd_freq(s, 0);
739 int32_t sensor_get_min_delay (int s)
742 float max_supported_rate = 0;
743 float max_from_prop = sensor_get_max_freq(s);
745 /* continuous, on change: minimum sampling period allowed in microseconds.
746 * special : 0, unless otherwise noted
749 switch (REPORTING_MODE(sensor_desc[s].flags)) {
750 case SENSOR_FLAG_ON_CHANGE_MODE:
751 return MIN_ON_CHANGE_SAMPLING_PERIOD_US;
753 case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
756 case SENSOR_FLAG_ONE_SHOT_MODE:
763 if (sensor[s].is_virtual) {
764 switch (sensor[s].type) {
765 case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
766 case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
767 return sensor_desc[sensor[s].base[0]].minDelay;
773 if (!sensor[s].avail_freqs_count) {
774 if (sensor[s].mode == MODE_POLL) {
775 /* If we have max specified via a property use it */
776 if (max_from_prop != ANDROID_MAX_FREQ)
777 max_supported_rate = max_from_prop;
779 /* The should rate */
780 max_supported_rate = get_cdd_freq(s, 0);
783 for (i = 0; i < sensor[s].avail_freqs_count; i++) {
784 if (sensor[s].avail_freqs[i] > max_supported_rate &&
785 sensor[s].avail_freqs[i] <= max_from_prop) {
786 max_supported_rate = sensor[s].avail_freqs[i];
791 /* return 0 for wrong values */
792 if (max_supported_rate < 0.1)
795 /* Return microseconds */
796 return (int32_t) (1000000.0 / max_supported_rate);