aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sensor/yas_mag_driver-yas532.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sensor/yas_mag_driver-yas532.c')
-rw-r--r--drivers/sensor/yas_mag_driver-yas532.c2909
1 files changed, 2909 insertions, 0 deletions
diff --git a/drivers/sensor/yas_mag_driver-yas532.c b/drivers/sensor/yas_mag_driver-yas532.c
new file mode 100644
index 0000000..14259b8
--- /dev/null
+++ b/drivers/sensor/yas_mag_driver-yas532.c
@@ -0,0 +1,2909 @@
+/*
+ * Copyright (c) 2010-2011 Yamaha Corporation
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include <linux/sensor/yas.h>
+
+struct utimeval {
+ int32_t tv_sec;
+ int32_t tv_msec;
+};
+
+struct utimer {
+ struct utimeval prev_time;
+ struct utimeval total_time;
+ struct utimeval delay_ms;
+};
+
+static int utimeval_init(struct utimeval *val);
+static int utimeval_is_initial(struct utimeval *val);
+static int utimeval_is_overflow(struct utimeval *val);
+static struct utimeval utimeval_plus(struct utimeval *first,
+ struct utimeval *second);
+static struct utimeval utimeval_minus(struct utimeval *first,
+ struct utimeval *second);
+static int utimeval_greater_than(struct utimeval *first,
+ struct utimeval *second);
+static int utimeval_greater_or_equal(struct utimeval *first,
+ struct utimeval *second);
+static int utimeval_greater_than_zero(struct utimeval *val);
+static int utimeval_less_than_zero(struct utimeval *val);
+static struct utimeval *msec_to_utimeval(struct utimeval *result,
+ uint32_t msec);
+static uint32_t utimeval_to_msec(struct utimeval *val);
+
+static struct utimeval utimer_calc_next_time(struct utimer *ut,
+ struct utimeval *cur);
+static struct utimeval utimer_current_time(void);
+static int utimer_is_timeout(struct utimer *ut);
+static int utimer_clear_timeout(struct utimer *ut);
+static uint32_t utimer_get_total_time(struct utimer *ut);
+static uint32_t utimer_get_delay(struct utimer *ut);
+static int utimer_set_delay(struct utimer *ut, uint32_t delay_ms);
+static int utimer_update(struct utimer *ut);
+static int utimer_update_with_curtime(struct utimer *ut, struct utimeval *cur);
+static uint32_t utimer_sleep_time(struct utimer *ut);
+static uint32_t utimer_sleep_time_with_curtime(struct utimer *ut,
+ struct utimeval *cur);
+static int utimer_init(struct utimer *ut, uint32_t delay_ms);
+static int utimer_clear(struct utimer *ut);
+static void utimer_lib_init(void (*func) (int *sec, int *msec));
+
+#define YAS_REGADDR_DEVICE_ID (0x80)
+#define YAS_REGADDR_ACTUATE_INIT_COIL (0x81)
+#define YAS_REGADDR_MEASURE_COMMAND (0x82)
+#define YAS_REGADDR_CONFIG (0x83)
+#define YAS_REGADDR_MEASURE_INTERVAL (0x84)
+#define YAS_REGADDR_OFFSET_X (0x85)
+#define YAS_REGADDR_OFFSET_Y1 (0x86)
+#define YAS_REGADDR_OFFSET_Y2 (0x87)
+#define YAS_REGADDR_TEST1 (0x88)
+#define YAS_REGADDR_TEST2 (0x89)
+#define YAS_REGADDR_CAL (0x90)
+#define YAS_REGADDR_MEASURE_DATA (0xb0)
+#define YAS_YAS530_DEVICE_ID (0x01) /* YAS530 (MS-3E) */
+#define YAS_YAS530_VERSION_A (0) /* YAS530 (MS-3E Aver) */
+#define YAS_YAS530_VERSION_B (1) /* YAS530B (MS-3E Bver) */
+#define YAS_YAS530_VERSION_A_COEF (380)
+#define YAS_YAS530_VERSION_B_COEF (550)
+#define YAS_YAS530_DATA_CENTER (2048)
+#define YAS_YAS530_DATA_OVERFLOW (4095)
+
+#define YAS_YAS532_DEVICE_ID (0x02) /* YAS532 (MS-3R) */
+#define YAS_YAS532_VERSION_AB (0) /* YAS532AB (MS-3R ABver) */
+#define YAS_YAS532_VERSION_AC (1) /* YAS532AC (MS-3R ACver) */
+#define YAS_YAS532_VERSION_AB_COEF (1800)
+#define YAS_YAS532_VERSION_AC_COEF (900)
+#define YAS_YAS532_DATA_CENTER (4096)
+#define YAS_YAS532_DATA_OVERFLOW (8190)
+
+#undef YAS_YAS530_CAL_SINGLE_READ
+
+struct yas_machdep_func {
+ int (*device_open) (void);
+ int (*device_close) (void);
+ int (*device_write) (uint8_t addr, const uint8_t *buf, int len);
+ int (*device_read) (uint8_t addr, uint8_t *buf, int len);
+ void (*msleep) (int msec);
+};
+
+static int yas_cdrv_actuate_initcoil(void);
+static int yas_cdrv_set_offset(const int8_t *offset);
+static int yas_cdrv_recalc_calib_offset(int32_t *prev_calib_offset,
+ int32_t *new_calib_offset,
+ int8_t *prev_offset,
+ int8_t *new_offset);
+static int yas_cdrv_set_transformatiom_matrix(const int8_t *transform);
+static int yas_cdrv_measure_and_set_offset(int8_t *offset);
+static int yas_cdrv_measure(int32_t *msens, int32_t *raw, int16_t *t);
+static int yas_cdrv_init(const int8_t *transform,
+ struct yas_machdep_func *func);
+static int yas_cdrv_term(void);
+
+static void (*current_time) (int *sec, int *msec) = {
+0};
+
+static int utimeval_init(struct utimeval *val)
+{
+ if (unlikely(!val))
+ return -1;
+ val->tv_sec = val->tv_msec = 0;
+ return 0;
+}
+
+static int utimeval_is_initial(struct utimeval *val)
+{
+ if (unlikely(!val))
+ return 0;
+ return val->tv_sec == 0 && val->tv_msec == 0;
+}
+
+static int utimeval_is_overflow(struct utimeval *val)
+{
+ int32_t max;
+
+ if (unlikely(!val))
+ return 0;
+
+ max = (int32_t) (0xffffffff / 1000);
+ if (val->tv_sec > max) {
+ return 1; /* overflow */
+ } else if (val->tv_sec == max) {
+ if (val->tv_msec >
+ (int32_t) (0xffffffff % 1000)) {
+ return 1; /* overflow */
+ }
+ }
+
+ return 0;
+}
+
+static struct utimeval
+utimeval_plus(struct utimeval *first, struct utimeval *second)
+{
+ struct utimeval result = { 0, 0 };
+ int32_t tmp;
+
+ if (unlikely(!first || !second))
+ return result;
+
+ tmp = first->tv_sec + second->tv_sec;
+ if (first->tv_sec >= 0 && second->tv_sec >= 0 && tmp < 0)
+ goto overflow;
+ if (first->tv_sec < 0 && second->tv_sec < 0 && tmp >= 0)
+ goto underflow;
+
+ result.tv_sec = tmp;
+ result.tv_msec = first->tv_msec + second->tv_msec;
+ if (1000 <= result.tv_msec) {
+ tmp = result.tv_sec + result.tv_msec / 1000;
+ if (result.tv_sec >= 0 && result.tv_msec >= 0 && tmp < 0)
+ goto overflow;
+ result.tv_sec = tmp;
+ result.tv_msec = result.tv_msec % 1000;
+ }
+ if (result.tv_msec < 0) {
+ tmp = result.tv_sec + result.tv_msec / 1000 - 1;
+ if (result.tv_sec < 0 && result.tv_msec < 0 && tmp >= 0)
+ goto underflow;
+ result.tv_sec = tmp;
+ result.tv_msec = result.tv_msec % 1000 + 1000;
+ }
+
+ return result;
+
+overflow:
+ result.tv_sec = 0x7fffffff;
+ result.tv_msec = 999;
+ return result;
+
+underflow:
+ result.tv_sec = 0x80000000;
+ result.tv_msec = 0;
+ return result;
+}
+
+static struct utimeval
+utimeval_minus(struct utimeval *first, struct utimeval *second)
+{
+ struct utimeval result = { 0, 0 }, tmp;
+
+ if (first == NULL || second == NULL
+ || second->tv_sec == (int)0x80000000)
+ return result;
+
+ tmp.tv_sec = -second->tv_sec;
+ tmp.tv_msec = -second->tv_msec;
+ return utimeval_plus(first, &tmp);
+}
+
+static int utimeval_less_than(struct utimeval *first, struct utimeval *second)
+{
+ if (unlikely(!first || !second))
+ return 0;
+
+ if (first->tv_sec > second->tv_sec)
+ return 1;
+ else if (first->tv_sec < second->tv_sec)
+ return 0;
+ else
+ if (first->tv_msec > second->tv_msec)
+ return 1;
+ else
+ return 0;
+}
+
+static int
+utimeval_greater_than(struct utimeval *first, struct utimeval *second)
+{
+ if (unlikely(!first || !second))
+ return 0;
+
+ if (first->tv_sec < second->tv_sec)
+ return 1;
+ else if (first->tv_sec > second->tv_sec)
+ return 0;
+ else
+ if (first->tv_msec < second->tv_msec)
+ return 1;
+ else
+ return 0;
+}
+
+static int
+utimeval_greater_or_equal(struct utimeval *first, struct utimeval *second)
+{
+ return !utimeval_less_than(first, second);
+}
+
+static int utimeval_greater_than_zero(struct utimeval *val)
+{
+ struct utimeval zero = { 0, 0 };
+ return utimeval_greater_than(&zero, val);
+}
+
+static int utimeval_less_than_zero(struct utimeval *val)
+{
+ struct utimeval zero = { 0, 0 };
+ return utimeval_less_than(&zero, val);
+}
+
+static struct utimeval *msec_to_utimeval(struct utimeval *result, uint32_t msec)
+{
+ if (unlikely(!result))
+ return result;
+ result->tv_sec = msec / 1000;
+ result->tv_msec = msec % 1000;
+
+ return result;
+}
+
+static uint32_t utimeval_to_msec(struct utimeval *val)
+{
+ if (unlikely(!val))
+ return 0;
+ if (utimeval_less_than_zero(val))
+ return 0;
+
+ if (utimeval_is_overflow(val))
+ return 0xffffffff;
+
+ return val->tv_sec * 1000 + val->tv_msec;
+}
+
+static struct utimeval
+utimer_calc_next_time(struct utimer *ut, struct utimeval *cur)
+{
+ struct utimeval result = { 0, 0 }, delay;
+
+ if (ut == NULL || cur == NULL)
+ return result;
+ utimer_update_with_curtime(ut, cur);
+ if (utimer_is_timeout(ut)) {
+ result = *cur;
+ } else {
+ delay = utimeval_minus(&ut->delay_ms, &ut->total_time);
+ result = utimeval_plus(cur, &delay);
+ }
+
+ return result;
+}
+
+static struct utimeval utimer_current_time(void)
+{
+ struct utimeval tv;
+ int sec, msec;
+
+ if (current_time != NULL)
+ current_time(&sec, &msec);
+ else
+ sec = 0, msec = 0;
+ tv.tv_sec = sec;
+ tv.tv_msec = msec;
+
+ return tv;
+}
+
+static int utimer_clear(struct utimer *ut)
+{
+ if (unlikely(!ut))
+ return -1;
+ utimeval_init(&ut->prev_time);
+ utimeval_init(&ut->total_time);
+
+ return 0;
+}
+
+static int utimer_update_with_curtime(struct utimer *ut, struct utimeval *cur)
+{
+ struct utimeval tmp;
+
+ if (unlikely(!ut || !cur))
+ return -1;
+ if (utimeval_is_initial(&ut->prev_time))
+ ut->prev_time = *cur;
+ if (utimeval_greater_than_zero(&ut->delay_ms)) {
+ tmp = utimeval_minus(cur, &ut->prev_time);
+ if (utimeval_less_than_zero(&tmp))
+ utimeval_init(&ut->total_time);
+ else {
+ ut->total_time = utimeval_plus(&tmp, &ut->total_time);
+ if (utimeval_is_overflow(&ut->total_time))
+ utimeval_init(&ut->total_time);
+ }
+ ut->prev_time = *cur;
+ }
+
+ return 0;
+}
+
+static int utimer_update(struct utimer *ut)
+{
+ struct utimeval cur;
+
+ if (unlikely(!ut))
+ return -1;
+
+ cur = utimer_current_time();
+ utimer_update_with_curtime(ut, &cur);
+ return 0;
+}
+
+static int utimer_is_timeout(struct utimer *ut)
+{
+ if (unlikely(!ut))
+ return 0;
+
+ if (utimeval_greater_than_zero(&ut->delay_ms))
+ return utimeval_greater_or_equal(&ut->delay_ms,
+ &ut->total_time);
+ else
+ return 1;
+}
+
+static int utimer_clear_timeout(struct utimer *ut)
+{
+ uint32_t delay, total;
+
+ if (unlikely(!ut))
+ return -1;
+
+ delay = utimeval_to_msec(&ut->delay_ms);
+ if (delay == 0 || utimeval_is_overflow(&ut->total_time))
+ total = 0;
+ else
+ if (utimeval_is_overflow(&ut->total_time))
+ total = 0;
+ else {
+ total = utimeval_to_msec(&ut->total_time);
+ total = total % delay;
+ }
+ msec_to_utimeval(&ut->total_time, total);
+
+ return 0;
+}
+
+static uint32_t
+utimer_sleep_time_with_curtime(struct utimer *ut, struct utimeval *cur)
+{
+ struct utimeval tv;
+
+ if (unlikely(!ut || !cur))
+ return 0;
+
+ tv = utimer_calc_next_time(ut, cur);
+ tv = utimeval_minus(&tv, cur);
+ if (utimeval_less_than_zero(&tv))
+ return 0;
+
+ return utimeval_to_msec(&tv);
+}
+
+static uint32_t utimer_sleep_time(struct utimer *ut)
+{
+ struct utimeval cur;
+
+ if (unlikely(!ut))
+ return 0;
+
+ cur = utimer_current_time();
+ return utimer_sleep_time_with_curtime(ut, &cur);
+}
+
+static int utimer_init(struct utimer *ut, uint32_t delay_ms)
+{
+ if (unlikely(!ut))
+ return -1;
+ utimer_clear(ut);
+ msec_to_utimeval(&ut->delay_ms, delay_ms);
+
+ return 0;
+}
+
+static uint32_t utimer_get_total_time(struct utimer *ut)
+{
+ return utimeval_to_msec(&ut->total_time);
+}
+
+static uint32_t utimer_get_delay(struct utimer *ut)
+{
+ if (unlikely(!ut))
+ return -1;
+ return utimeval_to_msec(&ut->delay_ms);
+}
+
+static int utimer_set_delay(struct utimer *ut, uint32_t delay_ms)
+{
+ return utimer_init(ut, delay_ms);
+}
+
+static void utimer_lib_init(void (*func) (int *sec, int *msec))
+{
+ current_time = func;
+}
+
+struct yas_cal_data {
+ uint8_t dx, dy1, dy2;
+ uint8_t d2, d3, d4, d5, d6, d7, d8, d9, d0;
+ uint8_t dck;
+ uint8_t ver;
+};
+struct yas_correction_data {
+ int32_t Cx, Cy1, Cy2;
+ int32_t a2, a3, a4, a5, a6, a7, a8, a9, k;
+};
+struct yas_cdriver {
+ struct yas_cal_data cal;
+ struct yas_correction_data correct;
+ struct yas_machdep_func func;
+ int8_t transform[9];
+ int16_t temperature;
+ uint8_t dev_id;
+ int32_t coef;
+ int16_t center;
+ int16_t overflow;
+};
+static struct yas_cdriver cdriver;
+
+static int device_open(void)
+{
+ if (cdriver.func.device_open == NULL)
+ return -1;
+ return cdriver.func.device_open();
+}
+
+static int device_close(void)
+{
+ if (cdriver.func.device_close == NULL)
+ return -1;
+ return cdriver.func.device_close();
+}
+
+static int device_write(uint8_t addr, const uint8_t *buf, int len)
+{
+ if (cdriver.func.device_write == NULL)
+ return -1;
+ return cdriver.func.device_write(addr, buf, len);
+}
+
+static int device_read(uint8_t addr, uint8_t *buf, int len)
+{
+ if (cdriver.func.device_read == NULL)
+ return -1;
+ return cdriver.func.device_read(addr, buf, len);
+}
+
+static void sleep(int millisec)
+{
+ if (cdriver.func.msleep == NULL)
+ return;
+ cdriver.func.msleep(millisec);
+}
+
+static int init_test_register(void)
+{
+ uint8_t data;
+
+ data = 0x00;
+ if (device_write(YAS_REGADDR_TEST1, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ data = 0x00;
+ if (device_write(YAS_REGADDR_TEST2, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ return YAS_NO_ERROR;
+}
+
+static int get_device_id(uint8_t *id)
+{
+ uint8_t data = 0;
+
+ if (device_read(YAS_REGADDR_DEVICE_ID, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ *id = data;
+
+ return YAS_NO_ERROR;
+}
+
+static int get_cal_data_yas530(struct yas_cal_data *cal)
+{
+ uint8_t data[16];
+#ifdef YAS_YAS530_CAL_SINGLE_READ
+ int i;
+
+ for (i = 0; i < 16; i++) { /* dummy read */
+ if (device_read(YAS_REGADDR_CAL + i, &data[i], 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+ for (i = 0; i < 16; i++) {
+ if (device_read(YAS_REGADDR_CAL + i, &data[i], 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+#else
+ if (device_read(YAS_REGADDR_CAL, data, 16) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (device_read(YAS_REGADDR_CAL, data, 16) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+#endif
+
+ cal->dx = data[0];
+ cal->dy1 = data[1];
+ cal->dy2 = data[2];
+ cal->d2 = (data[3] >> 2) & 0x03f;
+ cal->d3 = ((data[3] << 2) & 0x0c) | ((data[4] >> 6) & 0x03);
+ cal->d4 = data[4] & 0x3f;
+ cal->d5 = (data[5] >> 2) & 0x3f;
+ cal->d6 = ((data[5] << 4) & 0x30) | ((data[6] >> 4) & 0x0f);
+ cal->d7 = ((data[6] << 3) & 0x78) | ((data[7] >> 5) & 0x07);
+ cal->d8 = ((data[7] << 1) & 0x3e) | ((data[8] >> 7) & 0x01);
+ cal->d9 = ((data[8] << 1) & 0xfe) | ((data[9] >> 7) & 0x01);
+ cal->d0 = (data[9] >> 2) & 0x1f;
+ cal->dck = ((data[9] << 1) & 0x06) | ((data[10] >> 7) & 0x01);
+ cal->ver = (data[15]) & 0x03;
+
+ return YAS_NO_ERROR;
+}
+
+static void
+get_correction_value_yas530(struct yas_cal_data *cal,
+ struct yas_correction_data *correct)
+{
+ correct->Cx = cal->dx * 6 - 768;
+ correct->Cy1 = cal->dy1 * 6 - 768;
+ correct->Cy2 = cal->dy2 * 6 - 768;
+ correct->a2 = cal->d2 - 32;
+ correct->a3 = cal->d3 - 8;
+ correct->a4 = cal->d4 - 32;
+ correct->a5 = cal->d5 + 38;
+ correct->a6 = cal->d6 - 32;
+ correct->a7 = cal->d7 - 64;
+ correct->a8 = cal->d8 - 32;
+ correct->a9 = cal->d9;
+ correct->k = cal->d0 + 10;
+}
+
+static int get_cal_data_yas532(struct yas_cal_data *cal)
+{
+ uint8_t data[14];
+#ifdef YAS_YAS530_CAL_SINGLE_READ
+ int i;
+
+ for (i = 0; i < 14; i++) { /* dummy read */
+ if (device_read(YAS_REGADDR_CAL + i, &data[i], 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+ for (i = 0; i < 14; i++) {
+ if (device_read(YAS_REGADDR_CAL + i, &data[i], 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+#else
+ if (device_read(YAS_REGADDR_CAL, data, 14) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (device_read(YAS_REGADDR_CAL, data, 14) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+#endif
+
+ cal->dx = data[0];
+ cal->dy1 = data[1];
+ cal->dy2 = data[2];
+ cal->d2 = (data[3] >> 2) & 0x03f;
+ cal->d3 = ((data[3] << 2) & 0x0c) | ((data[4] >> 6) & 0x03);
+ cal->d4 = data[4] & 0x3f;
+ cal->d5 = (data[5] >> 2) & 0x3f;
+ cal->d6 = ((data[5] << 4) & 0x30) | ((data[6] >> 4) & 0x0f);
+ cal->d7 = ((data[6] << 3) & 0x78) | ((data[7] >> 5) & 0x07);
+ cal->d8 = ((data[7] << 1) & 0x3e) | ((data[8] >> 7) & 0x01);
+ cal->d9 = ((data[8] << 1) & 0xfe) | ((data[9] >> 7) & 0x01);
+ cal->d0 = (data[9] >> 2) & 0x1f;
+ cal->dck = ((data[9] << 1) & 0x06) | ((data[10] >> 7) & 0x01);
+ cal->ver = (data[13]) & 0x01;
+
+ return YAS_NO_ERROR;
+}
+
+static void
+get_correction_value_yas532(struct yas_cal_data *cal,
+ struct yas_correction_data *correct)
+{
+ correct->Cx = cal->dx * 10 - 1280;
+ correct->Cy1 = cal->dy1 * 10 - 1280;
+ correct->Cy2 = cal->dy2 * 10 - 1280;
+ correct->a2 = cal->d2 - 32;
+ correct->a3 = cal->d3 - 8;
+ correct->a4 = cal->d4 - 32;
+ correct->a5 = cal->d5 + 38;
+ correct->a6 = cal->d6 - 32;
+ correct->a7 = cal->d7 - 64;
+ correct->a8 = cal->d8 - 32;
+ correct->a9 = cal->d9;
+ correct->k = cal->d0;
+}
+
+static int set_configuration(int inton, int inthact, int cck)
+{
+ uint8_t data = 0;
+
+ data |= (!!inton) & 0x01;
+ data |= ((!!inthact) << 1) & 0x02;
+ data |= (cck << 2) & 0x1c;
+
+ if (device_write(YAS_REGADDR_CONFIG, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ return YAS_NO_ERROR;
+}
+
+static int get_measure_interval(int32_t *msec)
+{
+ uint8_t data;
+ int mult = 7;
+
+ if (device_read(YAS_REGADDR_MEASURE_INTERVAL, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ switch (cdriver.dev_id) {
+ case YAS_YAS532_DEVICE_ID:
+ mult = 4;
+ break;
+ case YAS_YAS530_DEVICE_ID:
+ default:
+ mult = 7;
+ break;
+ }
+
+ *msec = data * mult;
+
+ return YAS_NO_ERROR;
+}
+
+static int set_measure_interval(int32_t msec)
+{
+ uint8_t data = 0;
+ int mult = 7;
+
+ switch (cdriver.dev_id) {
+ case YAS_YAS532_DEVICE_ID:
+ mult = 4;
+ break;
+ case YAS_YAS530_DEVICE_ID:
+ default:
+ mult = 7;
+ break;
+ }
+
+ if (msec > mult*0xff)
+ data = 0xff;
+ else
+ if (msec % mult == 0)
+ data = (uint8_t)(msec / mult);
+ else
+ data = (uint8_t)(msec / mult + 1);
+ if (device_write(YAS_REGADDR_MEASURE_INTERVAL, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ return YAS_NO_ERROR;
+}
+
+static int set_measure_command(int ldtc, int fors, int dlymes)
+{
+ uint8_t data = 0;
+
+ data |= 0x01; /* bit 0 must be 1 */
+ data |= ((!(!ldtc)) << 1) & 0x02;
+ data |= ((!(!fors)) << 2) & 0x04;
+ data |= ((!(!dlymes)) << 4) & 0x10;
+
+ if (device_write(YAS_REGADDR_MEASURE_COMMAND, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ return YAS_NO_ERROR;
+}
+
+static int
+measure_normal_yas530(int *busy, int16_t *t, int16_t *x, int16_t *y1,
+ int16_t *y2)
+{
+ uint8_t data[8];
+
+ if (set_measure_command(0, 0, 0) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ sleep(2);
+
+ if (device_read(YAS_REGADDR_MEASURE_DATA, data, 8) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ *busy = (data[0] >> 7) & 0x01;
+ *t = (((int32_t) data[0] << 2) & 0x1fc) | ((data[1] >> 6) & 0x03);
+ *x = (((int32_t) data[2] << 5) & 0xfe0) | ((data[3] >> 3) & 0x1f);
+ *y1 = (((int32_t) data[4] << 5) & 0xfe0) | ((data[5] >> 3) & 0x1f);
+ *y2 = (((int32_t) data[6] << 5) & 0xfe0) | ((data[7] >> 3) & 0x1f);
+ /*YLOGD(("f[%d] t[%d] x[%d] y1[%d] y2[%d]\n",
+ *busy, *t, *x, *y1, *y2)); */
+
+ return YAS_NO_ERROR;
+}
+
+static int
+measure_normal_yas532(int *busy, int16_t *t, int16_t *x, int16_t *y1,
+ int16_t *y2)
+{
+ uint8_t data[8];
+
+ if (set_measure_command(0, 0, 0) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ sleep(2);
+
+ if (device_read(YAS_REGADDR_MEASURE_DATA, data, 8) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ *busy = (data[0] >> 7) & 0x01;
+ *t = (((int32_t) data[0] << 3) & 0x3f8) | ((data[1] >> 5) & 0x07);
+ *x = (((int32_t) data[2] << 6) & 0x1fc0) | ((data[3] >> 2) & 0x3f);
+ *y1 = (((int32_t) data[4] << 6) & 0x1fc0) | ((data[5] >> 2) & 0x3f);
+ *y2 = (((int32_t) data[6] << 6) & 0x1fc0) | ((data[7] >> 2) & 0x3f);
+ /*YLOGD(("f[%d] t[%d] x[%d] y1[%d] y2[%d]\n",
+ *busy, *t, *x, *y1, *y2)); */
+
+ return YAS_NO_ERROR;
+}
+
+static int
+measure_normal(int *busy, int16_t *t, int16_t *x, int16_t *y1, int16_t *y2)
+{
+ int result;
+
+ switch (cdriver.dev_id) {
+ case YAS_YAS532_DEVICE_ID:
+ result = measure_normal_yas532(busy, t, x, y1, y2);
+ break;
+ case YAS_YAS530_DEVICE_ID:
+ default:
+ result = measure_normal_yas530(busy, t, x, y1, y2);
+ break;
+ }
+
+ return result;
+}
+
+static int
+coordinate_conversion(int32_t x, int32_t y1, int32_t y2, int16_t t,
+ int32_t *xo, int32_t *yo, int32_t *zo,
+ struct yas_correction_data *c)
+{
+ int32_t sx, sy1, sy2, sy, sz;
+ int32_t hx, hy, hz;
+
+ sx = x - (c->Cx * t) / 100;
+ sy1 = y1 - (c->Cy1 * t) / 100;
+ sy2 = y2 - (c->Cy2 * t) / 100;
+
+ sy = sy1 - sy2;
+ sz = -sy1 - sy2;
+
+ hx = c->k * ((100 * sx + c->a2 * sy + c->a3 * sz) / 10);
+ hy = c->k * ((c->a4 * sx + c->a5 * sy + c->a6 * sz) / 10);
+ hz = c->k * ((c->a7 * sx + c->a8 * sy + c->a9 * sz) / 10);
+
+ *xo = cdriver.transform[0] * hx
+ + cdriver.transform[1] * hy + cdriver.transform[2] * hz;
+ *yo = cdriver.transform[3] * hx
+ + cdriver.transform[4] * hy + cdriver.transform[5] * hz;
+ *zo = cdriver.transform[6] * hx
+ + cdriver.transform[7] * hy + cdriver.transform[8] * hz;
+
+ return YAS_NO_ERROR;
+}
+
+static int
+set_hardware_offset(int8_t offset_x, int8_t offset_y1, int8_t offset_y2)
+{
+ uint8_t data;
+
+ data = offset_x & 0x3f;
+ if (device_write(YAS_REGADDR_OFFSET_X, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ data = offset_y1 & 0x3f;
+ if (device_write(YAS_REGADDR_OFFSET_Y1, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ data = offset_y2 & 0x3f;
+ if (device_write(YAS_REGADDR_OFFSET_Y2, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_cdrv_actuate_initcoil(void)
+{
+ uint8_t data = 0;
+
+ if (device_write(YAS_REGADDR_ACTUATE_INIT_COIL, &data, 1) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ return YAS_NO_ERROR;
+}
+
+static int
+check_offset(int8_t offset_x, int8_t offset_y1, int8_t offset_y2,
+ int *flag_x, int *flag_y1, int *flag_y2)
+{
+ int busy;
+ int16_t t, x, y1, y2;
+
+ if (set_hardware_offset(offset_x, offset_y1, offset_y2) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (measure_normal(&busy, &t, &x, &y1, &y2) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ *flag_x = *flag_y1 = *flag_y2 = 0;
+ if (x > cdriver.center)
+ *flag_x = 1;
+ if (y1 > cdriver.center)
+ *flag_y1 = 1;
+ if (y2 > cdriver.center)
+ *flag_y2 = 1;
+ if (x < cdriver.center)
+ *flag_x = -1;
+ if (y1 < cdriver.center)
+ *flag_y1 = -1;
+ if (y2 < cdriver.center)
+ *flag_y2 = -1;
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_cdrv_measure_and_set_offset(int8_t *offset)
+{
+ int i;
+ int8_t offset_x = 0, offset_y1 = 0, offset_y2 = 0;
+ int flag_x = 0, flag_y1 = 0, flag_y2 = 0;
+ static const int correct[5] = { 16, 8, 4, 2, 1 };
+
+ for (i = 0; i < 5; i++) {
+ if (check_offset(offset_x, offset_y1, offset_y2,
+ &flag_x, &flag_y1, &flag_y2) < 0) {
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+ YLOGD(("offset[%d][%d][%d] flag[%d][%d][%d]\n",
+ offset_x, offset_y1, offset_y2,
+ flag_x, flag_y1, flag_y2));
+ if (flag_x)
+ offset_x += flag_x * correct[i];
+ if (flag_y1)
+ offset_y1 += flag_y1 * correct[i];
+ if (flag_y2)
+ offset_y2 += flag_y2 * correct[i];
+ }
+ if (set_hardware_offset(offset_x, offset_y1, offset_y2) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ offset[0] = offset_x;
+ offset[1] = offset_y1;
+ offset[2] = offset_y2;
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_cdrv_set_offset(const int8_t *offset)
+{
+ if (set_hardware_offset(offset[0], offset[1], offset[2]) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_cdrv_measure(int32_t *data, int32_t *raw, int16_t *temperature)
+{
+ int busy;
+ int16_t x, y1, y2, t;
+ int32_t xx, yy1, yy2;
+ int result = 0;
+
+ if (measure_normal(&busy, &t, &x, &y1, &y2) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ if (x == 0)
+ result |= 0x01;
+ if (x == cdriver.overflow)
+ result |= 0x02;
+ if (y1 == 0)
+ result |= 0x04;
+ if (y1 == cdriver.overflow)
+ result |= 0x08;
+ if (y2 == 0)
+ result |= 0x10;
+ if (y2 == cdriver.overflow)
+ result |= 0x20;
+
+ xx = x;
+ yy1 = y1;
+ yy2 = y2;
+
+ if (coordinate_conversion(xx, yy1, yy2, t, &data[0], &data[1],
+ &data[2], &cdriver.correct) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ cdriver.temperature = t;
+
+ if (raw != NULL)
+ raw[0] = xx, raw[1] = yy1, raw[2] = yy2;
+ if (temperature != NULL)
+ *temperature = t;
+
+ return result;
+}
+
+static int
+yas_cdrv_recalc_calib_offset(int32_t *prev_calib_offset,
+ int32_t *new_calib_offset,
+ int8_t *prev_offset, int8_t *new_offset)
+{
+ int32_t tmp[3], resolution[9], base[3];
+ int32_t raw[3];
+ int32_t diff, i;
+
+ if (prev_calib_offset == NULL || new_calib_offset == NULL
+ || prev_offset == NULL || new_offset == NULL)
+ return YAS_ERROR_ARG;
+
+ raw[0] = raw[1] = raw[2] = 0;
+ if (coordinate_conversion(raw[0], raw[1], raw[2], cdriver.temperature,
+ &base[0], &base[1], &base[2],
+ &cdriver.correct) < 0)
+ return YAS_ERROR_ERROR;
+ for (i = 0; i < 3; i++) {
+ raw[0] = raw[1] = raw[2] = 0;
+ raw[i] = cdriver.coef;
+ if (coordinate_conversion(raw[0], raw[1], raw[2],
+ cdriver.temperature,
+ &resolution[i * 3 + 0],
+ &resolution[i * 3 + 1],
+ &resolution[i * 3 + 2],
+ &cdriver.correct) < 0)
+ return YAS_ERROR_ERROR;
+ resolution[i * 3 + 0] -= base[0];
+ resolution[i * 3 + 1] -= base[1];
+ resolution[i * 3 + 2] -= base[2];
+ }
+
+ for (i = 0; i < 3; i++)
+ tmp[i] = prev_calib_offset[i];
+
+ for (i = 0; i < 3; i++) {
+ diff = (int32_t) new_offset[i] - (int32_t) prev_offset[i];
+ while (diff > 0) {
+ tmp[0] -= resolution[i * 3 + 0];
+ tmp[1] -= resolution[i * 3 + 1];
+ tmp[2] -= resolution[i * 3 + 2];
+ diff--;
+ }
+ while (diff < 0) {
+ tmp[0] += resolution[i * 3 + 0];
+ tmp[1] += resolution[i * 3 + 1];
+ tmp[2] += resolution[i * 3 + 2];
+ diff++;
+ }
+ }
+ for (i = 0; i < 3; i++)
+ new_calib_offset[i] = tmp[i];
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_cdrv_set_transformatiom_matrix(const int8_t *transform)
+{
+ int i;
+
+ if (transform == NULL)
+ return YAS_ERROR_ARG;
+ for (i = 0; i < 9; i++)
+ cdriver.transform[i] = transform[i];
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_cdrv_init(const int8_t *transform, struct yas_machdep_func *func)
+{
+ int interval, i;
+ uint8_t id;
+
+ if (transform == NULL || func == NULL)
+ return YAS_ERROR_ARG;
+
+ for (i = 0; i < 9; i++)
+ cdriver.transform[i] = transform[i];
+
+ cdriver.func = *func;
+
+ if (device_open() < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ if (init_test_register() < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ if (get_device_id(&id) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ YLOGD(("device id:%02x\n", id));
+
+ switch (id) {
+ case YAS_YAS530_DEVICE_ID:
+ if (get_cal_data_yas530(&cdriver.cal) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+
+ get_correction_value_yas530(&cdriver.cal, &cdriver.correct);
+ cdriver.center = YAS_YAS530_DATA_CENTER;
+ cdriver.overflow = YAS_YAS530_DATA_OVERFLOW;
+ switch (cdriver.cal.ver) {
+ case YAS_YAS530_VERSION_B:
+ cdriver.coef = YAS_YAS530_VERSION_B_COEF;
+ break;
+ case YAS_YAS530_VERSION_A:
+ default:
+ cdriver.coef = YAS_YAS530_VERSION_A_COEF;
+ break;
+ }
+ break;
+
+ case YAS_YAS532_DEVICE_ID:
+ if (get_cal_data_yas532(&cdriver.cal) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ get_correction_value_yas532(&cdriver.cal, &cdriver.correct);
+ cdriver.center = YAS_YAS532_DATA_CENTER;
+ cdriver.overflow = YAS_YAS532_DATA_OVERFLOW;
+ switch (cdriver.cal.ver) {
+ case YAS_YAS532_VERSION_AC:
+ cdriver.coef = YAS_YAS532_VERSION_AC_COEF;
+ break;
+ case YAS_YAS532_VERSION_AB:
+ default:
+ cdriver.coef = YAS_YAS532_VERSION_AB_COEF;
+ break;
+ }
+ break;
+
+ default:
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+ cdriver.dev_id = id;
+
+ if (set_configuration(0, 0, cdriver.cal.dck) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (set_measure_interval(0) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (get_measure_interval(&interval) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ YLOGD(("interval[%d]\n", interval));
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_cdrv_term(void)
+{
+ device_close();
+ return YAS_NO_ERROR;
+}
+
+#define YAS_DEFAULT_CALIB_INTERVAL (50) /* 50 msecs */
+#define YAS_DEFAULT_DATA_INTERVAL (200) /* 200 msecs */
+#define YAS_INITCOIL_INTERVAL (200) /* 200 msec */
+#define YAS_INITCOIL_GIVEUP_INTERVAL (180000) /* 180 seconds */
+#define YAS_DETECT_OVERFLOW_INTERVAL (0) /* 0 second */
+
+#define YAS_MAG_ERROR_DELAY (200)
+#define YAS_MAG_STATE_NORMAL (0)
+#define YAS_MAG_STATE_INIT_COIL (1)
+#define YAS_MAG_STATE_MEASURE_OFFSET (2)
+
+static const int8_t YAS_TRANSFORMATION[][9] = {
+ {0, 1, 0, -1, 0, 0, 0, 0, 1},
+ {-1, 0, 0, 0, -1, 0, 0, 0, 1},
+ {0, -1, 0, 1, 0, 0, 0, 0, 1},
+ {1, 0, 0, 0, 1, 0, 0, 0, 1},
+ {0, -1, 0, -1, 0, 0, 0, 0, -1},
+ {1, 0, 0, 0, -1, 0, 0, 0, -1},
+ {0, 1, 0, 1, 0, 0, 0, 0, -1},
+ {-1, 0, 0, 0, 1, 0, 0, 0, -1},
+};
+
+static const int supported_data_interval[] = { 10, 20, 50, 60, 100, 200, 1000 };
+static const int supported_calib_interval[] = { 60, 60, 50, 60, 50, 50, 50 };
+static const int32_t INVALID_CALIB_OFFSET[] = { 0x7fffffff,
+ 0x7fffffff, 0x7fffffff };
+static const int8_t INVALID_OFFSET[] = { 0x7f, 0x7f, 0x7f };
+
+struct yas_adaptive_filter {
+ int num;
+ int index;
+ int filter_len;
+ int filter_noise;
+ int32_t sequence[YAS_MAG_MAX_FILTER_LEN];
+};
+
+struct yas_thresh_filter {
+ int32_t threshold;
+ int32_t last;
+};
+
+struct yas_driver {
+ int initialized;
+ struct yas_mag_driver_callback callback;
+ struct utimer data_timer;
+ struct utimer initcoil_timer;
+ struct utimer initcoil_giveup_timer;
+ struct utimer detect_overflow_timer;
+ int32_t prev_mag[3];
+ int32_t prev_xy1y2[3];
+ int32_t prev_mag_w_offset[3];
+ int16_t prev_temperature;
+ int measure_state;
+ int active;
+ int overflow;
+ int initcoil_gaveup;
+ int position;
+ int delay_timer_use_data;
+ int delay_timer_interval;
+ int delay_timer_counter;
+ int filter_enable;
+ int filter_len;
+ int filter_thresh;
+ int filter_noise[3];
+ struct yas_adaptive_filter adap_filter[3];
+ struct yas_thresh_filter thresh_filter[3];
+ struct yas_mag_offset offset;
+#ifdef YAS_MAG_MANUAL_OFFSET
+ struct yas_vector manual_offset;
+#endif
+ struct yas_matrix static_matrix;
+ struct yas_matrix dynamic_matrix;
+};
+
+static struct yas_driver this_driver;
+
+static int lock(void)
+{
+ if (this_driver.callback.lock != NULL) {
+ if (this_driver.callback.lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+ }
+ return 0;
+}
+
+static int unlock(void)
+{
+ if (this_driver.callback.unlock != NULL) {
+ if (this_driver.callback.unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+ }
+ return 0;
+}
+
+static int32_t square(int32_t data)
+{
+ return data * data;
+}
+
+static void
+adaptive_filter_init(struct yas_adaptive_filter *adap_filter, int len,
+ int noise)
+{
+ int i;
+
+ adap_filter->num = 0;
+ adap_filter->index = 0;
+ adap_filter->filter_noise = noise;
+ adap_filter->filter_len = len;
+
+ for (i = 0; i < adap_filter->filter_len; ++i)
+ adap_filter->sequence[i] = 0;
+}
+
+static int32_t
+adaptive_filter_filter(struct yas_adaptive_filter *adap_filter, int32_t in)
+{
+ int32_t avg, sum;
+ int i;
+
+ if (adap_filter->filter_len == 0)
+ return in;
+
+ if (adap_filter->num < adap_filter->filter_len) {
+ adap_filter->sequence[adap_filter->index++] = in / 100;
+ adap_filter->num++;
+ return in;
+ }
+ if (adap_filter->filter_len <= adap_filter->index)
+ adap_filter->index = 0;
+
+ adap_filter->sequence[adap_filter->index++] = in / 100;
+
+ avg = 0;
+ for (i = 0; i < adap_filter->filter_len; i++)
+ avg += adap_filter->sequence[i];
+
+ avg /= adap_filter->filter_len;
+
+ sum = 0;
+ for (i = 0; i < adap_filter->filter_len; i++)
+ sum += square(avg - adap_filter->sequence[i]);
+
+ sum /= adap_filter->filter_len;
+
+ if (sum <= adap_filter->filter_noise)
+ return avg * 100;
+
+ return ((in / 100 - avg) * (sum - adap_filter->filter_noise) / sum +
+ avg) * 100;
+}
+
+static void
+thresh_filter_init(struct yas_thresh_filter *thresh_filter, int threshold)
+{
+ thresh_filter->threshold = threshold;
+ thresh_filter->last = 0;
+}
+
+static int32_t
+thresh_filter_filter(struct yas_thresh_filter *thresh_filter, int32_t in)
+{
+ if (in < thresh_filter->last - thresh_filter->threshold
+ || thresh_filter->last + thresh_filter->threshold < in) {
+ thresh_filter->last = in;
+ return in;
+ } else
+ return thresh_filter->last;
+}
+
+static void filter_init(struct yas_driver *d)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ adaptive_filter_init(&d->adap_filter[i], d->filter_len,
+ d->filter_noise[i]);
+ thresh_filter_init(&d->thresh_filter[i], d->filter_thresh);
+ }
+}
+
+static void
+filter_filter(struct yas_driver *d, int32_t *orig, int32_t *filtered)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ filtered[i] =
+ adaptive_filter_filter(&d->adap_filter[i], orig[i]);
+ filtered[i] =
+ thresh_filter_filter(&d->thresh_filter[i], filtered[i]);
+ }
+}
+
+static int is_valid_offset(const int8_t *p)
+{
+ return (p != NULL && (p[0] <= 31) && (p[1] <= 31) && (p[2] <= 31)
+ && (-31 <= p[0]) && (-31 <= p[1]) && (-31 <= p[2]));
+}
+
+static int is_valid_calib_offset(const int32_t *p)
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (p[i] != INVALID_CALIB_OFFSET[i])
+ return 1;
+ }
+ return 0;
+}
+
+static int is_offset_differ(const int8_t *p0, const int8_t *p1)
+{
+ if (p0[0] != p1[0] || p0[1] != p1[1] || p0[2] != p1[2])
+ return 1;
+ else
+ return 0;
+}
+
+static int is_calib_offset_differ(const int32_t *p0, const int32_t *p1)
+{
+ if (p0[0] != p1[0] || p0[1] != p1[1] || p0[2] != p1[2])
+ return 1;
+ else
+ return 0;
+}
+
+static int get_overflow(struct yas_driver *d)
+{
+ return d->overflow;
+}
+
+static void set_overflow(struct yas_driver *d, const int overflow)
+{
+ if (d->overflow != overflow)
+ d->overflow = overflow;
+}
+
+static int get_initcoil_gaveup(struct yas_driver *d)
+{
+ return d->initcoil_gaveup;
+}
+
+static void set_initcoil_gaveup(struct yas_driver *d, const int initcoil_gaveup)
+{
+ d->initcoil_gaveup = initcoil_gaveup;
+}
+
+static int32_t *get_calib_offset(struct yas_driver *d)
+{
+ return d->offset.calib_offset.v;
+}
+
+static void set_calib_offset(struct yas_driver *d, const int32_t *offset)
+{
+ int i;
+
+ if (is_calib_offset_differ(d->offset.calib_offset.v, offset)) {
+ for (i = 0; i < 3; i++)
+ d->offset.calib_offset.v[i] = offset[i];
+ }
+}
+
+#ifdef YAS_MAG_MANUAL_OFFSET
+static int32_t *get_manual_offset(struct yas_driver *d)
+{
+ return d->manual_offset.v;
+}
+
+static void set_manual_offset(struct yas_driver *d, const int32_t *offset)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ d->manual_offset.v[i] = offset[i];
+}
+#endif
+
+static int32_t *get_static_matrix(struct yas_driver *d)
+{
+ return d->static_matrix.matrix;
+}
+
+static void set_static_matrix(struct yas_driver *d, const int32_t *matrix)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ d->static_matrix.matrix[i] = matrix[i];
+}
+
+static int32_t *get_dynamic_matrix(struct yas_driver *d)
+{
+ return d->dynamic_matrix.matrix;
+}
+
+static void set_dynamic_matrix(struct yas_driver *d, const int32_t *matrix)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ d->dynamic_matrix.matrix[i] = matrix[i];
+}
+
+static int8_t *get_offset(struct yas_driver *d)
+{
+ return d->offset.hard_offset;
+}
+
+static void set_offset(struct yas_driver *d, const int8_t *offset)
+{
+ int i;
+
+ if (is_offset_differ(d->offset.hard_offset, offset)) {
+ for (i = 0; i < 3; i++)
+ d->offset.hard_offset[i] = offset[i];
+ }
+}
+
+static int get_active(struct yas_driver *d)
+{
+ return d->active;
+}
+
+static void set_active(struct yas_driver *d, const int active)
+{
+ d->active = active;
+}
+
+static int get_position(struct yas_driver *d)
+{
+ return d->position;
+}
+
+static void set_position(struct yas_driver *d, const int position)
+{
+ d->position = position;
+}
+
+static int get_measure_state(struct yas_driver *d)
+{
+ return d->measure_state;
+}
+
+static void set_measure_state(struct yas_driver *d, const int state)
+{
+ d->measure_state = state;
+}
+
+static struct utimer *get_data_timer(struct yas_driver *d)
+{
+ return &d->data_timer;
+}
+
+static struct utimer *get_initcoil_timer(struct yas_driver *d)
+{
+ return &d->initcoil_timer;
+}
+
+static struct utimer *get_initcoil_giveup_timer(struct yas_driver *d)
+{
+ return &d->initcoil_giveup_timer;
+}
+
+static struct utimer *get_detect_overflow_timer(struct yas_driver *d)
+{
+ return &d->detect_overflow_timer;
+}
+
+static int get_delay_timer_use_data(struct yas_driver *d)
+{
+ return d->delay_timer_use_data;
+}
+
+static void set_delay_timer_use_data(struct yas_driver *d, int flag)
+{
+ d->delay_timer_use_data = !(!flag);
+}
+
+static int get_delay_timer_interval(struct yas_driver *d)
+{
+ return d->delay_timer_interval;
+}
+
+static void set_delay_timer_interval(struct yas_driver *d, int interval)
+{
+ d->delay_timer_interval = interval;
+}
+
+static int get_delay_timer_counter(struct yas_driver *d)
+{
+ return d->delay_timer_counter;
+}
+
+static void set_delay_timer_counter(struct yas_driver *d, int counter)
+{
+ d->delay_timer_counter = counter;
+}
+
+static int get_filter_enable(struct yas_driver *d)
+{
+ return d->filter_enable;
+}
+
+static void set_filter_enable(struct yas_driver *d, int enable)
+{
+ if (enable)
+ filter_init(d);
+
+ d->filter_enable = !(!enable);
+}
+
+static int get_filter_len(struct yas_driver *d)
+{
+ return d->filter_len;
+}
+
+static void set_filter_len(struct yas_driver *d, int len)
+{
+ if (len < 0)
+ return;
+
+ if (len > YAS_MAG_MAX_FILTER_LEN)
+ return;
+
+ d->filter_len = len;
+ filter_init(d);
+}
+
+static int get_filter_noise(struct yas_driver *d, int *noise)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ noise[i] = d->filter_noise[i];
+
+ return 0;
+}
+
+static void set_filter_noise(struct yas_driver *d, int *noise)
+{
+ int i;
+
+ if (noise == NULL)
+ return;
+
+ for (i = 0; i < 3; i++) {
+ if (noise[i] < 0)
+ noise[i] = 0;
+
+ d->filter_noise[i] = noise[i];
+ }
+ filter_init(d);
+}
+
+static int get_filter_thresh(struct yas_driver *d)
+{
+ return d->filter_thresh;
+}
+
+static void set_filter_thresh(struct yas_driver *d, int threshold)
+{
+ if (threshold < 0)
+ return;
+
+ d->filter_thresh = threshold;
+ filter_init(d);
+}
+
+static int32_t *get_previous_mag(struct yas_driver *d)
+{
+ return d->prev_mag;
+}
+
+static void set_previous_mag(struct yas_driver *d, int32_t *data)
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ d->prev_mag[i] = data[i];
+}
+
+static int32_t *get_previous_xy1y2(struct yas_driver *d)
+{
+ return d->prev_xy1y2;
+}
+
+static void set_previous_xy1y2(struct yas_driver *d, int32_t *data)
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ d->prev_xy1y2[i] = data[i];
+}
+
+static int32_t *get_previous_mag_w_offset(struct yas_driver *d)
+{
+ return d->prev_mag_w_offset;
+}
+
+static void set_previous_mag_w_offset(struct yas_driver *d, int32_t *data)
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ d->prev_mag_w_offset[i] = data[i];
+}
+
+static int16_t get_previous_temperature(struct yas_driver *d)
+{
+ return d->prev_temperature;
+}
+
+static void set_previous_temperature(struct yas_driver *d, int16_t temperature)
+{
+ d->prev_temperature = temperature;
+}
+
+static int init_coil(struct yas_driver *d)
+{
+ int rt;
+
+ YLOGD(("init_coil IN\n"));
+
+ utimer_update(get_initcoil_timer(d));
+ if (!get_initcoil_gaveup(d)) {
+ utimer_update(get_initcoil_giveup_timer(d));
+ if (utimer_is_timeout(get_initcoil_giveup_timer(d))) {
+ utimer_clear_timeout(get_initcoil_giveup_timer(d));
+ set_initcoil_gaveup(d, TRUE);
+ }
+ }
+ if (utimer_is_timeout(get_initcoil_timer(d)) &&
+ !get_initcoil_gaveup(d)) {
+ utimer_clear_timeout(get_initcoil_timer(d));
+ YLOGI(("init_coil!\n"));
+ rt = yas_cdrv_actuate_initcoil();
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_actuate_initcoil failed[%d]\n", rt));
+ return rt;
+ }
+ if (get_overflow(d) || !is_valid_offset(get_offset(d)))
+ set_measure_state(d, YAS_MAG_STATE_MEASURE_OFFSET);
+ else
+ set_measure_state(d, YAS_MAG_STATE_NORMAL);
+ }
+
+ YLOGD(("init_coil OUT\n"));
+
+ return 0;
+}
+
+static int measure_offset(struct yas_driver *d)
+{
+ int8_t offset[3];
+ int32_t moffset[3];
+ int rt, result = 0, i;
+
+ YLOGI(("measure_offset IN\n"));
+ rt = yas_cdrv_measure_and_set_offset(offset);
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_measure_offset failed[%d]\n", rt));
+ return rt;
+ }
+
+ YLOGI(("offset[%d][%d][%d]\n", offset[0], offset[1], offset[2]));
+
+ for (i = 0; i < 3; i++)
+ moffset[i] = get_calib_offset(d)[i];
+
+ if (is_offset_differ(get_offset(d), offset)) {
+ if (is_valid_offset(get_offset(d))
+ && is_valid_calib_offset(get_calib_offset(d))) {
+ yas_cdrv_recalc_calib_offset(get_calib_offset(d),
+ moffset,
+ get_offset(d), offset);
+ result |= YAS_REPORT_CALIB_OFFSET_CHANGED;
+ }
+ }
+ result |= YAS_REPORT_HARD_OFFSET_CHANGED;
+
+ set_offset(d, offset);
+ if (is_valid_calib_offset(moffset))
+ set_calib_offset(d, moffset);
+
+ set_measure_state(d, YAS_MAG_STATE_NORMAL);
+
+ YLOGI(("measure_offset OUT\n"));
+
+ return result;
+}
+
+static int
+measure_msensor_normal(struct yas_driver *d, int32_t *magnetic,
+ int32_t *mag_w_offset, int32_t * xy1y2,
+ int16_t *temperature)
+{
+ int rt = 0, result, i;
+ int32_t tmp[3];
+
+ YLOGD(("measure_msensor_normal IN\n"));
+
+ result = 0;
+ rt = yas_cdrv_measure(mag_w_offset, tmp, temperature);
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_measure failed[%d]\n", rt));
+ return rt;
+ }
+ for (i = 0; i < 3; i++)
+ xy1y2[i] = tmp[i];
+
+#ifdef YAS_MAG_MANUAL_OFFSET
+ for (i = 0; i < 3; i++)
+ mag_w_offset[i] -= get_manual_offset(d)[i];
+#endif
+ if (rt > 0) {
+ utimer_update(get_detect_overflow_timer(d));
+ set_overflow(d, TRUE);
+ if (utimer_is_timeout(get_detect_overflow_timer(d))) {
+ utimer_clear_timeout(get_detect_overflow_timer(d));
+ result |= YAS_REPORT_OVERFLOW_OCCURED;
+ }
+ if (get_measure_state(d) == YAS_MAG_STATE_NORMAL)
+ set_measure_state(d, YAS_MAG_STATE_INIT_COIL);
+
+ } else {
+ utimer_clear(get_detect_overflow_timer(d));
+ set_overflow(d, FALSE);
+ if (get_measure_state(d) == YAS_MAG_STATE_NORMAL) {
+ utimer_clear(get_initcoil_timer(d));
+ utimer_clear(get_initcoil_giveup_timer(d));
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ tmp[i]
+ = (get_static_matrix(d)[i * 3 + 0] / 10 *
+ (mag_w_offset[0] / 10)) / 100 +
+ (get_static_matrix(d)[i * 3 + 1] / 10 *
+ (mag_w_offset[1] / 10)) / 100 +
+ (get_static_matrix(d)[i * 3 + 2] / 10 *
+ (mag_w_offset[2] / 10)) / 100;
+ }
+ for (i = 0; i < 3; i++)
+ magnetic[i] = mag_w_offset[i] = tmp[i];
+ if (is_valid_calib_offset(get_calib_offset(d))) {
+ for (i = 0; i < 3; i++)
+ magnetic[i] -= get_calib_offset(d)[i];
+ }
+ for (i = 0; i < 3; i++) {
+ tmp[i]
+ = (get_dynamic_matrix(d)[i * 3 + 0] / 10 *
+ (magnetic[0] / 10)) / 100 +
+ (get_dynamic_matrix(d)[i * 3 + 1] / 10 *
+ (magnetic[1] / 10)) / 100 + (get_dynamic_matrix(d)[i * 3 +
+ 2] /
+ 10 * (magnetic[2] / 10)) /
+ 100;
+ }
+ for (i = 0; i < 3; i++)
+ magnetic[i] = tmp[i];
+
+ if (get_filter_enable(d))
+ filter_filter(d, magnetic, magnetic);
+
+ YLOGD(("measure_msensor_normal OUT\n"));
+
+ return result;
+}
+
+static int
+measure_msensor(struct yas_driver *d, int32_t *magnetic,
+ int32_t *mag_w_offset, int32_t *xy1y2, int16_t *temperature)
+{
+ int result, i;
+
+ YLOGD(("measure_msensor IN\n"));
+
+ for (i = 0; i < 3; i++) {
+ magnetic[i] = get_previous_mag(d)[i];
+ mag_w_offset[i] = get_previous_mag_w_offset(d)[i];
+ xy1y2[i] = get_previous_xy1y2(d)[i];
+ *temperature = get_previous_temperature(d);
+ }
+
+ result = 0;
+ switch (get_measure_state(d)) {
+ case YAS_MAG_STATE_INIT_COIL:
+ result = init_coil(d);
+ break;
+ case YAS_MAG_STATE_MEASURE_OFFSET:
+ result = measure_offset(d);
+ break;
+ case YAS_MAG_STATE_NORMAL:
+ result = 0;
+ break;
+ default:
+ result = -1;
+ break;
+ }
+
+ if (result < 0)
+ return result;
+
+ if (!(result & YAS_REPORT_OVERFLOW_OCCURED))
+ result |=
+ measure_msensor_normal(d, magnetic, mag_w_offset, xy1y2,
+ temperature);
+ set_previous_mag(d, magnetic);
+ set_previous_xy1y2(d, xy1y2);
+ set_previous_mag_w_offset(d, mag_w_offset);
+ set_previous_temperature(d, *temperature);
+
+ YLOGD(("measure_msensor OUT\n"));
+
+ return result;
+}
+
+static int
+measure(struct yas_driver *d, int32_t *magnetic, int32_t *mag_w_offset,
+ int32_t *xy1y2, int16_t *temperature, uint32_t *time_delay)
+{
+ int result;
+ int counter;
+ uint32_t total = 0;
+
+ YLOGD(("measure IN\n"));
+
+ utimer_update(get_data_timer(d));
+ result = measure_msensor(d, magnetic, mag_w_offset, xy1y2,
+ temperature);
+ if (result < 0)
+ return result;
+
+ counter = get_delay_timer_counter(d);
+ total = utimer_get_total_time(get_data_timer(d));
+ if (utimer_get_delay(get_data_timer(d)) > 0)
+ counter -= total / utimer_get_delay(get_data_timer(d));
+ else
+ counter = 0;
+
+ if (utimer_is_timeout(get_data_timer(d))) {
+ utimer_clear_timeout(get_data_timer(d));
+
+ if (get_delay_timer_use_data(d)) {
+ result |= YAS_REPORT_DATA;
+ if (counter <= 0)
+ result |= YAS_REPORT_CALIB;
+ } else {
+ result |= YAS_REPORT_CALIB;
+ if (counter <= 0)
+ result |= YAS_REPORT_DATA;
+ }
+ }
+
+ if (counter <= 0)
+ set_delay_timer_counter(d, get_delay_timer_interval(d));
+ else
+ set_delay_timer_counter(d, counter);
+
+ *time_delay = utimer_sleep_time(get_data_timer(d));
+
+ YLOGD(("measure OUT [%d]\n", result));
+
+ return result;
+}
+
+static int resume(struct yas_driver *d)
+{
+ int32_t zero[] = { 0, 0, 0 };
+ struct yas_machdep_func func;
+ int rt;
+
+ YLOGI(("resume IN\n"));
+
+ func.device_open = d->callback.device_open;
+ func.device_close = d->callback.device_close;
+ func.device_write = d->callback.device_write;
+ func.device_read = d->callback.device_read;
+ func.msleep = d->callback.msleep;
+
+ rt =
+ yas_cdrv_init(YAS_TRANSFORMATION[get_position(d)], &func);
+
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_init failed[%d]\n", rt));
+ return rt;
+ }
+
+ utimer_clear(get_data_timer(d));
+ utimer_clear(get_initcoil_giveup_timer(d));
+ utimer_clear(get_initcoil_timer(d));
+ utimer_clear(get_detect_overflow_timer(d));
+
+ set_previous_mag(d, zero);
+ set_previous_xy1y2(d, zero);
+ set_previous_mag_w_offset(d, zero);
+ set_previous_temperature(d, 0);
+ set_overflow(d, FALSE);
+ set_initcoil_gaveup(d, FALSE);
+
+ filter_init(d);
+
+ if (is_valid_offset(d->offset.hard_offset)) {
+ yas_cdrv_set_offset(d->offset.hard_offset);
+ rt = yas_cdrv_actuate_initcoil();
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_actuate_initcoil failed[%d]\n", rt));
+ set_measure_state(d, YAS_MAG_STATE_INIT_COIL);
+ } else
+ set_measure_state(d, YAS_MAG_STATE_NORMAL);
+ } else {
+ rt = yas_cdrv_actuate_initcoil();
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_actuate_initcoil failed[%d]\n", rt));
+ set_measure_state(d, YAS_MAG_STATE_INIT_COIL);
+ } else
+ set_measure_state(d, YAS_MAG_STATE_MEASURE_OFFSET);
+ }
+
+ YLOGI(("resume OUT\n"));
+ return 0;
+}
+
+static int suspend(struct yas_driver *d)
+{
+ YLOGI(("suspend IN\n"));
+
+ (void)d;
+ yas_cdrv_term();
+
+ YLOGI(("suspend OUT\n"));
+ return 0;
+}
+
+static int check_interval(int ms)
+{
+ int index = -1;
+
+ if (ms <= supported_data_interval[0])
+ ms = supported_data_interval[0];
+ for (index = 0; index < NELEMS(supported_data_interval); index++) {
+ if (ms == supported_data_interval[index])
+ goto done;
+ else if (ms < supported_data_interval[index]) {
+ if (index != 0)
+ index -= 1;
+ goto done;
+ }
+ }
+done:
+ return index;
+}
+
+static int yas_get_delay_nolock(struct yas_driver *d, int *ms)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ if (get_delay_timer_use_data(d))
+ *ms = utimer_get_delay(get_data_timer(d));
+ else {
+ *ms =
+ utimer_get_delay(get_data_timer(d)) *
+ get_delay_timer_interval(d);
+ }
+ return YAS_NO_ERROR;
+}
+
+static int yas_set_delay_nolock(struct yas_driver *d, int ms)
+{
+ int index;
+ uint32_t delay_data, delay_calib;
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ index = check_interval(ms);
+ if (index < 0)
+ return YAS_ERROR_ARG;
+ delay_data = supported_data_interval[index];
+ delay_calib = supported_calib_interval[index];
+ set_delay_timer_use_data(d, delay_data < delay_calib);
+ if (delay_data < delay_calib) {
+ set_delay_timer_interval(d, delay_calib / delay_data);
+ set_delay_timer_counter(d, delay_calib / delay_data);
+ utimer_set_delay(get_data_timer(d),
+ supported_data_interval[index]);
+ } else {
+ set_delay_timer_interval(d, delay_data / delay_calib);
+ set_delay_timer_counter(d, delay_data / delay_calib);
+ utimer_set_delay(get_data_timer(d),
+ supported_calib_interval[index]);
+ }
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_get_offset_nolock(struct yas_driver *d, struct yas_mag_offset *offset)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ *offset = d->offset;
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_set_offset_nolock(struct yas_driver *d, struct yas_mag_offset *offset)
+{
+ int32_t zero[] = { 0, 0, 0 };
+ int rt;
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ if (!get_active(d)) {
+ d->offset = *offset;
+ return YAS_NO_ERROR;
+ }
+
+ if (!is_valid_offset(offset->hard_offset)
+ || is_offset_differ(offset->hard_offset, d->offset.hard_offset)) {
+ filter_init(d);
+
+ utimer_clear(get_data_timer(d));
+ utimer_clear(get_initcoil_giveup_timer(d));
+ utimer_clear(get_initcoil_timer(d));
+ utimer_clear(get_detect_overflow_timer(d));
+
+ set_previous_mag(d, zero);
+ set_previous_xy1y2(d, zero);
+ set_previous_mag_w_offset(d, zero);
+ set_previous_temperature(d, 0);
+ set_overflow(d, FALSE);
+ set_initcoil_gaveup(d, FALSE);
+ }
+ d->offset = *offset;
+
+ if (is_valid_offset(d->offset.hard_offset))
+ yas_cdrv_set_offset(d->offset.hard_offset);
+ else {
+ rt = yas_cdrv_actuate_initcoil();
+ if (rt < 0) {
+ YLOGE(("yas_cdrv_actuate_initcoil failed[%d]\n", rt));
+ set_measure_state(d, YAS_MAG_STATE_INIT_COIL);
+ } else
+ set_measure_state(d, YAS_MAG_STATE_MEASURE_OFFSET);
+ }
+
+ return YAS_NO_ERROR;
+}
+
+#ifdef YAS_MAG_MANUAL_OFFSET
+
+static int
+yas_get_manual_offset_nolock(struct yas_driver *d, struct yas_vector *offset)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ *offset = d->manual_offset;
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_set_manual_offset_nolock(struct yas_driver *d, struct yas_vector *offset)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ set_manual_offset(d, offset->v);
+
+ return YAS_NO_ERROR;
+}
+
+#endif
+
+static int
+yas_get_static_matrix_nolock(struct yas_driver *d, struct yas_matrix *matrix)
+{
+ int i;
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ for (i = 0; i < 9; i++)
+ matrix->matrix[i] = get_static_matrix(d)[i];
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_set_static_matrix_nolock(struct yas_driver *d, struct yas_matrix *matrix)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ set_static_matrix(d, matrix->matrix);
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_get_dynamic_matrix_nolock(struct yas_driver *d, struct yas_matrix *matrix)
+{
+ int i;
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ for (i = 0; i < 9; i++)
+ matrix->matrix[i] = get_dynamic_matrix(d)[i];
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_set_dynamic_matrix_nolock(struct yas_driver *d, struct yas_matrix *matrix)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ set_dynamic_matrix(d, matrix->matrix);
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_get_enable_nolock(struct yas_driver *d)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ return get_active(d);
+}
+
+static int yas_set_enable_nolock(struct yas_driver *d, int active)
+{
+ int rt;
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ if (active) {
+ if (get_active(d))
+ return YAS_NO_ERROR;
+ rt = resume(d);
+ if (rt < 0)
+ return rt;
+ set_active(d, TRUE);
+ } else {
+ if (!get_active(d))
+ return YAS_NO_ERROR;
+ rt = suspend(d);
+ if (rt < 0)
+ return rt;
+ set_active(d, FALSE);
+ }
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_get_filter_nolock(struct yas_driver *d, struct yas_mag_filter *filter)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ filter->len = get_filter_len(d);
+ get_filter_noise(d, filter->noise);
+ filter->threshold = get_filter_thresh(d);
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_set_filter_nolock(struct yas_driver *d, struct yas_mag_filter *filter)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ set_filter_len(d, filter->len);
+ set_filter_noise(d, filter->noise);
+ set_filter_thresh(d, filter->threshold);
+ return YAS_NO_ERROR;
+}
+
+static int yas_get_filter_enable_nolock(struct yas_driver *d)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ return get_filter_enable(d);
+}
+
+static int yas_set_filter_enable_nolock(struct yas_driver *d, int enable)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ set_filter_enable(d, enable);
+ return YAS_NO_ERROR;
+}
+
+static int yas_get_position_nolock(struct yas_driver *d, int *position)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ *position = get_position(d);
+ return YAS_NO_ERROR;
+}
+
+static int yas_set_position_nolock(struct yas_driver *d, int position)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ if (get_active(d))
+ yas_cdrv_set_transformatiom_matrix(YAS_TRANSFORMATION
+ [position]);
+ set_position(d, position);
+ filter_init(d);
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_read_reg_nolock(struct yas_driver *d, uint8_t addr, uint8_t * buf, int len)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ if (!get_active(d)) {
+ if (d->callback.device_open() < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+ if (d->callback.device_read(addr, buf, len) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (!get_active(d)) {
+ if (d->callback.device_close() < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_write_reg_nolock(struct yas_driver *d, uint8_t addr, const uint8_t * buf,
+ int len)
+{
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ if (!get_active(d)) {
+ if (d->callback.device_open() < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+ if (d->callback.device_write(addr, buf, len) < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ if (!get_active(d)) {
+ if (d->callback.device_close() < 0)
+ return YAS_ERROR_DEVICE_COMMUNICATION;
+ }
+
+ return YAS_NO_ERROR;
+}
+
+static int
+yas_measure_nolock(struct yas_driver *d, struct yas_mag_data *data,
+ int *time_delay_ms)
+{
+ uint32_t time_delay = YAS_MAG_ERROR_DELAY;
+ int rt, i;
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+ *time_delay_ms = YAS_MAG_ERROR_DELAY;
+
+ if (!get_active(d)) {
+ for (i = 0; i < 3; i++) {
+ data->xyz.v[i] = get_previous_mag(d)[i];
+ data->raw.v[i] = get_previous_mag_w_offset(d)[i];
+ data->xy1y2.v[i] = get_previous_xy1y2(d)[i];
+ }
+ data->temperature = get_previous_temperature(d);
+ return YAS_NO_ERROR;
+ }
+
+ rt = measure(d, data->xyz.v, data->raw.v, data->xy1y2.v,
+ &data->temperature, &time_delay);
+ if (rt >= 0) {
+ *time_delay_ms = time_delay;
+ if (*time_delay_ms > 0)
+ *time_delay_ms += 1;
+ }
+
+ return rt;
+}
+
+static int yas_init_nolock(struct yas_driver *d)
+{
+#ifdef YAS_MAG_MANUAL_OFFSET
+ int32_t zero[] = { 0, 0, 0 };
+#endif
+ int32_t notransform[] = { 10000, 0, 0, 0, 10000, 0, 0, 0, 10000 };
+ int noise[] = {
+ YAS_MAG_DEFAULT_FILTER_NOISE_X,
+ YAS_MAG_DEFAULT_FILTER_NOISE_Y,
+ YAS_MAG_DEFAULT_FILTER_NOISE_Z
+ };
+
+ YLOGI(("yas_init_nolock IN\n"));
+
+ utimer_lib_init(this_driver.callback.current_time);
+ utimer_init(get_data_timer(d), 50);
+ utimer_init(get_initcoil_timer(d), YAS_INITCOIL_INTERVAL);
+ utimer_init(get_initcoil_giveup_timer(d), YAS_INITCOIL_GIVEUP_INTERVAL);
+ utimer_init(get_detect_overflow_timer(d), YAS_DETECT_OVERFLOW_INTERVAL);
+
+ set_delay_timer_use_data(d, 0);
+ set_delay_timer_interval(d,
+ YAS_DEFAULT_DATA_INTERVAL /
+ YAS_DEFAULT_CALIB_INTERVAL);
+ set_delay_timer_counter(d,
+ YAS_DEFAULT_DATA_INTERVAL /
+ YAS_DEFAULT_CALIB_INTERVAL);
+
+ set_filter_enable(d, FALSE);
+ set_filter_len(d, YAS_MAG_DEFAULT_FILTER_LEN);
+ set_filter_thresh(d, YAS_MAG_DEFAULT_FILTER_THRESH);
+ set_filter_noise(d, noise);
+ filter_init(d);
+ set_calib_offset(d, INVALID_CALIB_OFFSET);
+#ifdef YAS_MAG_MANUAL_OFFSET
+ set_manual_offset(d, zero);
+#endif
+ set_static_matrix(d, notransform);
+ set_dynamic_matrix(d, notransform);
+ set_offset(d, INVALID_OFFSET);
+ set_active(d, FALSE);
+ set_position(d, 0);
+
+ d->initialized = 1;
+
+ YLOGI(("yas_init_nolock OUT\n"));
+
+ return YAS_NO_ERROR;
+}
+
+static int yas_term_nolock(struct yas_driver *d)
+{
+ YLOGI(("yas_term_nolock\n"));
+
+ if (unlikely(!d->initialized))
+ return YAS_ERROR_NOT_INITIALIZED;
+
+ if (get_active(d))
+ suspend(d);
+ d->initialized = 0;
+
+ YLOGI(("yas_term_nolock out\n"));
+ return YAS_NO_ERROR;
+}
+
+static int yas_get_delay(void)
+{
+ int ms = 0, rt;
+
+ YLOGI(("yas_get_delay\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_delay_nolock(&this_driver, &ms);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_delay[%d] OUT\n", ms));
+
+ return (rt < 0 ? rt : ms);
+}
+
+static int yas_set_delay(int delay)
+{
+ int rt;
+
+ YLOGI(("yas_set_delay\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_delay_nolock(&this_driver, delay);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_delay OUT\n"));
+
+ return rt;
+}
+
+static int yas_get_offset(struct yas_mag_offset *offset)
+{
+ int rt;
+
+ YLOGI(("yas_get_offset\n"));
+
+ if (offset == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_offset_nolock(&this_driver, offset);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_offset[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_set_offset(struct yas_mag_offset *offset)
+{
+ int rt;
+
+ YLOGI(("yas_set_offset IN\n"));
+
+ if (offset == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_offset_nolock(&this_driver, offset);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_offset OUT\n"));
+
+ return rt;
+}
+
+#ifdef YAS_MAG_MANUAL_OFFSET
+
+static int yas_get_manual_offset(struct yas_vector *offset)
+{
+ int rt;
+
+ YLOGI(("yas_get_manual_offset\n"));
+
+ if (offset == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_manual_offset_nolock(&this_driver, offset);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_manual_offset[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_set_manual_offset(struct yas_vector *offset)
+{
+ int rt;
+
+ YLOGI(("yas_set_manual_offset IN\n"));
+
+ if (offset == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_manual_offset_nolock(&this_driver, offset);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_manual_offset OUT\n"));
+
+ return rt;
+}
+
+#endif
+
+static int yas_get_static_matrix(struct yas_matrix *matrix)
+{
+ int rt;
+
+ YLOGI(("yas_get_static_matrix\n"));
+
+ if (matrix == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_static_matrix_nolock(&this_driver, matrix);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_static_matrix[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_set_static_matrix(struct yas_matrix *matrix)
+{
+ int rt;
+
+ YLOGI(("yas_set_static_matrix IN\n"));
+
+ if (matrix == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_static_matrix_nolock(&this_driver, matrix);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_static_matrix OUT\n"));
+
+ return rt;
+}
+
+static int yas_get_dynamic_matrix(struct yas_matrix *matrix)
+{
+ int rt;
+
+ YLOGI(("yas_get_dynamic_matrix\n"));
+
+ if (matrix == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_dynamic_matrix_nolock(&this_driver, matrix);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_dynamic_matrix[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_set_dynamic_matrix(struct yas_matrix *matrix)
+{
+ int rt;
+
+ YLOGI(("yas_set_dynamic_matrix IN\n"));
+
+ if (matrix == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_dynamic_matrix_nolock(&this_driver, matrix);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_dynamic_matrix OUT\n"));
+
+ return rt;
+}
+
+static int yas_get_enable(void)
+{
+ int rt;
+
+ YLOGI(("yas_get_enable\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_enable_nolock(&this_driver);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_enable OUT[%d]\n", rt));
+
+ return rt;
+}
+
+static int yas_set_enable(int enable)
+{
+ int rt;
+
+ YLOGI(("yas_set_enable IN\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_enable_nolock(&this_driver, enable);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_enable OUT\n"));
+
+ return rt;
+}
+
+static int yas_get_filter(struct yas_mag_filter *filter)
+{
+ int rt;
+
+ YLOGI(("yas_get_filter\n"));
+
+ if (filter == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_filter_nolock(&this_driver, filter);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_filter[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_set_filter(struct yas_mag_filter *filter)
+{
+ int rt, i;
+
+ YLOGI(("yas_set_filter IN\n"));
+
+ if (filter == NULL
+ || filter->len < 0
+ || YAS_MAG_MAX_FILTER_LEN < filter->len || filter->threshold < 0) {
+ return YAS_ERROR_ARG;
+ }
+ for (i = 0; i < 3; i++) {
+ if (filter->noise[i] < 0)
+ return YAS_ERROR_ARG;
+ }
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_filter_nolock(&this_driver, filter);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_filter OUT\n"));
+
+ return rt;
+}
+
+static int yas_get_filter_enable(void)
+{
+ int rt;
+
+ YLOGI(("yas_get_filter_enable\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_filter_enable_nolock(&this_driver);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_filter_enable OUT[%d]\n", rt));
+
+ return rt;
+}
+
+static int yas_set_filter_enable(int enable)
+{
+ int rt;
+
+ YLOGI(("yas_set_filter_enable IN\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_filter_enable_nolock(&this_driver, enable);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_filter_enable OUT\n"));
+
+ return rt;
+}
+
+static int yas_get_position(void)
+{
+ int position = 0;
+ int rt;
+
+ YLOGI(("yas_get_position\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_get_position_nolock(&this_driver, &position);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_get_position[%d] OUT\n", position));
+
+ return (rt < 0 ? rt : position);
+}
+
+static int yas_set_position(int position)
+{
+ int rt;
+
+ YLOGI(("yas_set_position\n"));
+
+ if (position < 0 || 7 < position)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_set_position_nolock(&this_driver, position);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_set_position[%d] OUT\n", position));
+
+ return rt;
+}
+
+static int yas_read_reg(uint8_t addr, uint8_t *buf, int len)
+{
+ int rt;
+
+ YLOGI(("yas_read_reg\n"));
+
+ if (buf == NULL || len <= 0)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_read_reg_nolock(&this_driver, addr, buf, len);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_read_reg[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_write_reg(uint8_t addr, const uint8_t *buf, int len)
+{
+ int rt;
+
+ YLOGI(("yas_write_reg\n"));
+
+ if (buf == NULL || len <= 0)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_write_reg_nolock(&this_driver, addr, buf, len);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGI(("yas_write_reg[%d] OUT\n", rt));
+
+ return rt;
+}
+
+static int yas_measure(struct yas_mag_data *data, int *time_delay_ms)
+{
+ int rt;
+
+ YLOGD(("yas_measure IN\n"));
+
+ if (data == NULL || time_delay_ms == NULL)
+ return YAS_ERROR_ARG;
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_measure_nolock(&this_driver, data, time_delay_ms);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ YLOGD(("yas_measure OUT[%d]\n", rt));
+
+ return rt;
+}
+
+static int yas_init(void)
+{
+ int rt;
+
+ YLOGI(("yas_init\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_init_nolock(&this_driver);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ return rt;
+}
+
+static int yas_term(void)
+{
+ int rt;
+ YLOGI(("yas_term\n"));
+
+ if (lock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ rt = yas_term_nolock(&this_driver);
+
+ if (unlock() < 0)
+ return YAS_ERROR_RESTARTSYS;
+
+ return rt;
+}
+
+int yas_mag_driver_init(struct yas_mag_driver *f)
+{
+ if (f == NULL)
+ return YAS_ERROR_ARG;
+ if (f->callback.device_open == NULL
+ || f->callback.device_close == NULL
+ || f->callback.device_read == NULL
+ || f->callback.device_write == NULL
+ || f->callback.msleep == NULL || f->callback.current_time == NULL)
+ return YAS_ERROR_ARG;
+
+ f->init = yas_init;
+ f->term = yas_term;
+ f->get_delay = yas_get_delay;
+ f->set_delay = yas_set_delay;
+ f->get_offset = yas_get_offset;
+ f->set_offset = yas_set_offset;
+#ifdef YAS_MAG_MANUAL_OFFSET
+ f->get_manual_offset = yas_get_manual_offset;
+ f->set_manual_offset = yas_set_manual_offset;
+#endif
+ f->get_static_matrix = yas_get_static_matrix;
+ f->set_static_matrix = yas_set_static_matrix;
+ f->get_dynamic_matrix = yas_get_dynamic_matrix;
+ f->set_dynamic_matrix = yas_set_dynamic_matrix;
+ f->get_enable = yas_get_enable;
+ f->set_enable = yas_set_enable;
+ f->get_filter = yas_get_filter;
+ f->set_filter = yas_set_filter;
+ f->get_filter_enable = yas_get_filter_enable;
+ f->set_filter_enable = yas_set_filter_enable;
+ f->get_position = yas_get_position;
+ f->set_position = yas_set_position;
+ f->read_reg = yas_read_reg;
+ f->write_reg = yas_write_reg;
+ f->measure = yas_measure;
+
+ if ((f->callback.lock == NULL && f->callback.unlock != NULL)
+ || (f->callback.lock != NULL && f->callback.unlock == NULL)) {
+ this_driver.callback.lock = NULL;
+ this_driver.callback.unlock = NULL;
+ } else {
+ this_driver.callback.lock = f->callback.lock;
+ this_driver.callback.unlock = f->callback.unlock;
+ }
+ this_driver.callback.device_open = f->callback.device_open;
+ this_driver.callback.device_close = f->callback.device_close;
+ this_driver.callback.device_write = f->callback.device_write;
+ this_driver.callback.device_read = f->callback.device_read;
+ this_driver.callback.msleep = f->callback.msleep;
+ this_driver.callback.current_time = f->callback.current_time;
+ yas_term();
+
+ return YAS_NO_ERROR;
+}