altos: Record all failed sensors and report status at power up
[fw/altos] / src / drivers / ao_mpu9250.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_mpu9250.h>
21 #include <ao_exti.h>
22
23 #if HAS_MPU9250
24
25 #define MPU9250_TEST    0
26
27 static uint8_t  ao_mpu9250_configured;
28
29 #ifndef AO_MPU9250_I2C_INDEX
30 #define AO_MPU9250_SPI  1
31 #else
32 #define AO_MPU9250_SPI  0
33 #endif
34
35 #if AO_MPU9250_SPI
36
37 #define ao_mpu9250_spi_get()    ao_spi_get(AO_MPU9250_SPI_BUS, AO_SPI_SPEED_1MHz)
38 #define ao_mpu9250_spi_put()    ao_spi_put(AO_MPU9250_SPI_BUS)
39
40 #define ao_mpu9250_spi_start()  ao_spi_set_cs(AO_MPU9250_SPI_CS_PORT,   \
41                                               (1 << AO_MPU9250_SPI_CS_PIN))
42
43 #define ao_mpu9250_spi_end()    ao_spi_clr_cs(AO_MPU9250_SPI_CS_PORT,   \
44                                               (1 << AO_MPU9250_SPI_CS_PIN))
45
46 #else
47
48 #define ao_mpu9250_spi_get()
49 #define ao_mpu9250_spi_put()
50
51 #endif
52
53 static void
54 _ao_mpu9250_reg_write(uint8_t addr, uint8_t value)
55 {
56         uint8_t d[2] = { addr, value };
57 #if AO_MPU9250_SPI
58         ao_mpu9250_spi_start();
59         ao_spi_send(d, 2, AO_MPU9250_SPI_BUS);
60         ao_mpu9250_spi_end();
61 #else
62         ao_i2c_get(AO_MPU9250_I2C_INDEX);
63         ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_WRITE);
64         ao_i2c_send(d, 2, AO_MPU9250_I2C_INDEX, true);
65         ao_i2c_put(AO_MPU9250_I2C_INDEX);
66 #endif
67 }
68
69 static void
70 _ao_mpu9250_read(uint8_t addr, void *data, uint8_t len)
71 {
72 #if AO_MPU9250_SPI
73         addr |= 0x80;
74         ao_mpu9250_spi_start();
75         ao_spi_send(&addr, 1, AO_MPU9250_SPI_BUS);
76         ao_spi_recv(data, len, AO_MPU9250_SPI_BUS);
77         ao_mpu9250_spi_end();
78 #else
79         ao_i2c_get(AO_MPU9250_I2C_INDEX);
80         ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_WRITE);
81         ao_i2c_send(&addr, 1, AO_MPU9250_I2C_INDEX, false);
82         ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_READ);
83         ao_i2c_recv(data, len, AO_MPU9250_I2C_INDEX, true);
84         ao_i2c_put(AO_MPU9250_I2C_INDEX);
85 #endif
86 }
87
88 static uint8_t
89 _ao_mpu9250_reg_read(uint8_t addr)
90 {
91         uint8_t value;
92 #if AO_MPU9250_SPI
93         addr |= 0x80;
94         ao_mpu9250_spi_start();
95         ao_spi_send(&addr, 1, AO_MPU9250_SPI_BUS);
96         ao_spi_recv(&value, 1, AO_MPU9250_SPI_BUS);
97         ao_mpu9250_spi_end();
98 #else
99         ao_i2c_get(AO_MPU9250_I2C_INDEX);
100         ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_WRITE);
101         ao_i2c_send(&addr, 1, AO_MPU9250_I2C_INDEX, false);
102         ao_i2c_start(AO_MPU9250_I2C_INDEX, MPU9250_ADDR_READ);
103         ao_i2c_recv(&value, 1, AO_MPU9250_I2C_INDEX, true);
104         ao_i2c_put(AO_MPU9250_I2C_INDEX);
105 #endif
106         return value;
107 }
108
109 static void
110 _ao_mpu9250_slv4_setup(uint8_t addr, uint8_t reg)
111 {
112         /* Set i2c slave address */
113         _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_ADDR,
114                               addr);
115
116         /* Set i2c register address */
117         _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_REG,
118                               reg);
119 }
120
121 static void
122 _ao_mpu9250_slv4_run(void)
123 {
124         uint8_t ctrl;
125
126         /* Start the transfer */
127         _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_CTRL,
128                               (1 << MPU9250_I2C_SLV4_CTRL_I2C_SLV4_EN) |
129                               (0 << MPU9250_I2C_SLV4_CTRL_SLV4_DONE_INT_EN) |
130                               (0 << MPU9250_I2C_SLV4_CTRL_I2C_SLV4_REG_DIS) |
131                               (0 << MPU9250_I2C_SLV4_CTRL_I2C_MST_DLY));
132
133         /* Poll for completion */
134         for (;;) {
135                 ctrl = _ao_mpu9250_reg_read(MPU9250_I2C_SLV4_CTRL);
136                 if ((ctrl & (1 << MPU9250_I2C_SLV4_CTRL_I2C_SLV4_EN)) == 0)
137                         break;
138                 ao_delay(0);
139         }
140 }
141
142 static uint8_t
143 _ao_mpu9250_mag_reg_read(uint8_t reg)
144 {
145         _ao_mpu9250_slv4_setup((1 << 7) | MPU9250_MAG_ADDR, reg);
146
147         _ao_mpu9250_slv4_run();
148
149         return _ao_mpu9250_reg_read(MPU9250_I2C_SLV4_DI);
150 }
151
152 static void
153 _ao_mpu9250_mag_reg_write(uint8_t reg, uint8_t value)
154 {
155         _ao_mpu9250_slv4_setup((0 << 7) | MPU9250_MAG_ADDR, reg);
156
157         /* Set the data */
158         _ao_mpu9250_reg_write(MPU9250_I2C_SLV4_DO,
159                               value);
160
161         _ao_mpu9250_slv4_run();
162 }
163
164 static void
165 _ao_mpu9250_sample(struct ao_mpu9250_sample *sample)
166 {
167         uint16_t        *d = (uint16_t *) sample;
168         int             i = sizeof (*sample) / 2;
169
170         _ao_mpu9250_read(MPU9250_ACCEL_XOUT_H, sample, sizeof (*sample));
171 #if __BYTE_ORDER == __LITTLE_ENDIAN
172         /* byte swap */
173         while (i--) {
174                 uint16_t        t = *d;
175                 *d++ = (t >> 8) | (t << 8);
176         }
177 #endif
178 }
179
180 #define G       981     /* in cm/s² */
181
182 #if 0
183 static int16_t /* cm/s² */
184 ao_mpu9250_accel(int16_t v)
185 {
186         return (int16_t) ((v * (int32_t) (16.0 * 980.665 + 0.5)) / 32767);
187 }
188
189 static int16_t  /* deg*10/s */
190 ao_mpu9250_gyro(int16_t v)
191 {
192         return (int16_t) ((v * (int32_t) 20000) / 32767);
193 }
194 #endif
195
196 static uint8_t
197 ao_mpu9250_accel_check(int16_t normal, int16_t test)
198 {
199         int16_t diff = test - normal;
200
201         if (diff < MPU9250_ST_ACCEL(16) / 4) {
202                 return 1;
203         }
204         if (diff > MPU9250_ST_ACCEL(16) * 4) {
205                 return 1;
206         }
207         return 0;
208 }
209
210 static uint8_t
211 ao_mpu9250_gyro_check(int16_t normal, int16_t test)
212 {
213         int16_t diff = test - normal;
214
215         if (diff < 0)
216                 diff = -diff;
217         if (diff < MPU9250_ST_GYRO(2000) / 4) {
218                 return 1;
219         }
220         if (diff > MPU9250_ST_GYRO(2000) * 4) {
221                 return 1;
222         }
223         return 0;
224 }
225
226 static void
227 _ao_mpu9250_wait_alive(void)
228 {
229         uint8_t i;
230
231         /* Wait for the chip to wake up */
232         for (i = 0; i < 30; i++) {
233                 ao_delay(AO_MS_TO_TICKS(100));
234                 if (_ao_mpu9250_reg_read(MPU9250_WHO_AM_I) == MPU9250_I_AM_9250)
235                         break;
236         }
237         if (i == 30)
238                 ao_panic(AO_PANIC_SELF_TEST_MPU9250);
239 }
240
241 #define ST_TRIES        10
242 #define MAG_TRIES       10
243
244 static void
245 _ao_mpu9250_setup(void)
246 {
247         struct ao_mpu9250_sample        normal_mode, test_mode;
248         int                             errors;
249         int                             st_tries;
250         int                             mag_tries;
251
252         if (ao_mpu9250_configured)
253                 return;
254
255         _ao_mpu9250_wait_alive();
256
257         /* Reset the whole chip */
258
259         _ao_mpu9250_reg_write(MPU9250_PWR_MGMT_1,
260                               (1 << MPU9250_PWR_MGMT_1_DEVICE_RESET));
261
262         /* Wait for it to reset. If we talk too quickly, it appears to get confused */
263
264         _ao_mpu9250_wait_alive();
265
266         /* Reset signal conditioning, disabling I2C on SPI systems */
267         _ao_mpu9250_reg_write(MPU9250_USER_CTRL,
268                               (0 << MPU9250_USER_CTRL_FIFO_EN) |
269                               (1 << MPU9250_USER_CTRL_I2C_MST_EN) |
270                               (AO_MPU9250_SPI << MPU9250_USER_CTRL_I2C_IF_DIS) |
271                               (0 << MPU9250_USER_CTRL_FIFO_RESET) |
272                               (0 << MPU9250_USER_CTRL_I2C_MST_RESET) |
273                               (1 << MPU9250_USER_CTRL_SIG_COND_RESET));
274
275         while (_ao_mpu9250_reg_read(MPU9250_USER_CTRL) & (1 << MPU9250_USER_CTRL_SIG_COND_RESET))
276                 ao_delay(AO_MS_TO_TICKS(10));
277
278         /* Reset signal paths */
279         _ao_mpu9250_reg_write(MPU9250_SIGNAL_PATH_RESET,
280                               (1 << MPU9250_SIGNAL_PATH_RESET_GYRO_RESET) |
281                               (1 << MPU9250_SIGNAL_PATH_RESET_ACCEL_RESET) |
282                               (1 << MPU9250_SIGNAL_PATH_RESET_TEMP_RESET));
283
284         _ao_mpu9250_reg_write(MPU9250_SIGNAL_PATH_RESET,
285                               (0 << MPU9250_SIGNAL_PATH_RESET_GYRO_RESET) |
286                               (0 << MPU9250_SIGNAL_PATH_RESET_ACCEL_RESET) |
287                               (0 << MPU9250_SIGNAL_PATH_RESET_TEMP_RESET));
288
289         /* Select clocks, disable sleep */
290         _ao_mpu9250_reg_write(MPU9250_PWR_MGMT_1,
291                               (0 << MPU9250_PWR_MGMT_1_DEVICE_RESET) |
292                               (0 << MPU9250_PWR_MGMT_1_SLEEP) |
293                               (0 << MPU9250_PWR_MGMT_1_CYCLE) |
294                               (0 << MPU9250_PWR_MGMT_1_TEMP_DIS) |
295                               (MPU9250_PWR_MGMT_1_CLKSEL_PLL_X_AXIS << MPU9250_PWR_MGMT_1_CLKSEL));
296
297         /* Set I2C clock and options */
298         _ao_mpu9250_reg_write(MPU9250_MST_CTRL,
299                               (0 << MPU9250_MST_CTRL_MULT_MST_EN) |
300                               (0 << MPU9250_MST_CTRL_WAIT_FOR_ES) |
301                               (0 << MPU9250_MST_CTRL_SLV_3_FIFO_EN) |
302                               (0 << MPU9250_MST_CTRL_I2C_MST_P_NSR) |
303                               (MPU9250_MST_CTRL_I2C_MST_CLK_400 << MPU9250_MST_CTRL_I2C_MST_CLK));
304
305         /* Set sample rate divider to sample at full speed */
306         _ao_mpu9250_reg_write(MPU9250_SMPRT_DIV, 0);
307
308         /* Disable filtering */
309         _ao_mpu9250_reg_write(MPU9250_CONFIG,
310                               (MPU9250_CONFIG_EXT_SYNC_SET_DISABLED << MPU9250_CONFIG_EXT_SYNC_SET) |
311                               (MPU9250_CONFIG_DLPF_CFG_250 << MPU9250_CONFIG_DLPF_CFG));
312
313         for (st_tries = 0; st_tries < ST_TRIES; st_tries++) {
314                 errors = 0;
315
316                 /* Configure accelerometer to +/-16G in self-test mode */
317                 _ao_mpu9250_reg_write(MPU9250_ACCEL_CONFIG,
318                                       (1 << MPU9250_ACCEL_CONFIG_XA_ST) |
319                                       (1 << MPU9250_ACCEL_CONFIG_YA_ST) |
320                                       (1 << MPU9250_ACCEL_CONFIG_ZA_ST) |
321                                       (MPU9250_ACCEL_CONFIG_AFS_SEL_16G << MPU9250_ACCEL_CONFIG_AFS_SEL));
322
323                 /* Configure gyro to +/- 2000°/s in self-test mode */
324                 _ao_mpu9250_reg_write(MPU9250_GYRO_CONFIG,
325                                       (1 << MPU9250_GYRO_CONFIG_XG_ST) |
326                                       (1 << MPU9250_GYRO_CONFIG_YG_ST) |
327                                       (1 << MPU9250_GYRO_CONFIG_ZG_ST) |
328                                       (MPU9250_GYRO_CONFIG_FS_SEL_2000 << MPU9250_GYRO_CONFIG_FS_SEL));
329
330                 ao_delay(AO_MS_TO_TICKS(200));
331                 _ao_mpu9250_sample(&test_mode);
332
333                 /* Configure accelerometer to +/-16G */
334                 _ao_mpu9250_reg_write(MPU9250_ACCEL_CONFIG,
335                                       (0 << MPU9250_ACCEL_CONFIG_XA_ST) |
336                                       (0 << MPU9250_ACCEL_CONFIG_YA_ST) |
337                                       (0 << MPU9250_ACCEL_CONFIG_ZA_ST) |
338                                       (MPU9250_ACCEL_CONFIG_AFS_SEL_16G << MPU9250_ACCEL_CONFIG_AFS_SEL));
339
340                 /* Configure gyro to +/- 2000°/s */
341                 _ao_mpu9250_reg_write(MPU9250_GYRO_CONFIG,
342                                       (0 << MPU9250_GYRO_CONFIG_XG_ST) |
343                                       (0 << MPU9250_GYRO_CONFIG_YG_ST) |
344                                       (0 << MPU9250_GYRO_CONFIG_ZG_ST) |
345                                       (MPU9250_GYRO_CONFIG_FS_SEL_2000 << MPU9250_GYRO_CONFIG_FS_SEL));
346
347                 ao_delay(AO_MS_TO_TICKS(200));
348                 _ao_mpu9250_sample(&normal_mode);
349
350                 errors += ao_mpu9250_accel_check(normal_mode.accel_x, test_mode.accel_x);
351                 errors += ao_mpu9250_accel_check(normal_mode.accel_y, test_mode.accel_y);
352                 errors += ao_mpu9250_accel_check(normal_mode.accel_z, test_mode.accel_z);
353
354                 errors += ao_mpu9250_gyro_check(normal_mode.gyro_x, test_mode.gyro_x);
355                 errors += ao_mpu9250_gyro_check(normal_mode.gyro_y, test_mode.gyro_y);
356                 errors += ao_mpu9250_gyro_check(normal_mode.gyro_z, test_mode.gyro_z);
357                 if (!errors)
358                         break;
359         }
360
361         if (st_tries == ST_TRIES)
362                 AO_SENSOR_ERROR(AO_DATA_MPU9250);
363
364         /* Set up the mag sensor */
365
366         /* make sure it's alive */
367         for (mag_tries = 0; mag_tries < MAG_TRIES; mag_tries++) {
368                 if (_ao_mpu9250_mag_reg_read(MPU9250_MAG_WIA) == MPU9250_MAG_WIA_VALUE)
369                         break;
370         }
371
372         if (mag_tries == MAG_TRIES)
373                 AO_SENSOR_ERROR(AO_DATA_MPU9250);
374
375         /* Select continuous mode 2 (100Hz), 16 bit samples */
376
377         _ao_mpu9250_mag_reg_write(MPU9250_MAG_CNTL1,
378                                   (MPU9250_MAG_CNTL1_BIT_16 << MPU9250_MAG_CNTL1_BIT) |
379                                   (MPU9250_MAG_CNTL1_MODE_CONT_2 << MPU9250_MAG_CNTL1_MODE));
380
381         /* Set i2c master to delay shadowing data until read is
382          * complete (avoids tearing the data) */
383
384         _ao_mpu9250_reg_write(MPU9250_I2C_MST_DELAY_CTRL,
385                               (1 << MPU9250_I2C_MST_DELAY_CTRL_DELAY_ES_SHADOW) |
386                               (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN) |
387                               (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV3_DLY_EN) |
388                               (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV2_DLY_EN) |
389                               (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV1_DLY_EN) |
390                               (0 << MPU9250_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN));
391
392         /* Set up i2c slave 0 to read the mag registers starting at HXL (3) */
393
394         _ao_mpu9250_reg_write(MPU9250_I2C_SLV0_ADDR,
395                               (1 << 7) | MPU9250_MAG_ADDR);
396
397         _ao_mpu9250_reg_write(MPU9250_I2C_SLV0_REG,
398                               MPU9250_MAG_HXL);
399
400         /* Byte swap so the mag values match the gyro/accel. Read 7 bytes
401          * to include the status register
402          */
403
404         _ao_mpu9250_reg_write(MPU9250_I2C_SLV0_CTRL,
405                               (1 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_EN) |
406                               (1 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_BYTE_SW) |
407                               (0 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_REG_DIS) |
408                               (1 << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_GRP) |
409                               (MPU9250_MAG_ST2 - MPU9250_MAG_HXL + 1) << MPU9250_I2C_SLV0_CTRL_I2C_SLV0_LENG);
410
411         /* Filter to about 100Hz, which also sets the gyro rate to 1000Hz */
412         _ao_mpu9250_reg_write(MPU9250_CONFIG,
413                               (MPU9250_CONFIG_FIFO_MODE_REPLACE << MPU9250_CONFIG_FIFO_MODE) |
414                               (MPU9250_CONFIG_EXT_SYNC_SET_DISABLED << MPU9250_CONFIG_EXT_SYNC_SET) |
415                               (MPU9250_CONFIG_DLPF_CFG_92 << MPU9250_CONFIG_DLPF_CFG));
416
417         /* Set sample rate divider to sample at 200Hz (v = gyro/rate - 1) */
418         _ao_mpu9250_reg_write(MPU9250_SMPRT_DIV,
419                               1000 / 200 - 1);
420
421         ao_delay(AO_MS_TO_TICKS(100));
422         ao_mpu9250_configured = 1;
423 }
424
425 struct ao_mpu9250_sample        ao_mpu9250_current;
426
427 static void
428 ao_mpu9250(void)
429 {
430         struct ao_mpu9250_sample        sample;
431
432         /* ao_mpu9250_init already grabbed the SPI bus and mutex */
433         _ao_mpu9250_setup();
434         ao_mpu9250_spi_put();
435         for (;;)
436         {
437                 ao_mpu9250_spi_get();
438                 _ao_mpu9250_sample(&sample);
439                 ao_mpu9250_spi_put();
440                 ao_arch_block_interrupts();
441                 ao_mpu9250_current = sample;
442                 AO_DATA_PRESENT(AO_DATA_MPU9250);
443                 AO_DATA_WAIT();
444                 ao_arch_release_interrupts();
445         }
446 }
447
448 static struct ao_task ao_mpu9250_task;
449
450 static void
451 ao_mpu9250_show(void)
452 {
453         printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d Mag: %7d %7d %7d\n",
454                 ao_mpu9250_current.accel_x,
455                 ao_mpu9250_current.accel_y,
456                 ao_mpu9250_current.accel_z,
457                 ao_mpu9250_current.gyro_x,
458                 ao_mpu9250_current.gyro_y,
459                 ao_mpu9250_current.gyro_z,
460                 ao_mpu9250_current.mag_x,
461                 ao_mpu9250_current.mag_y,
462                 ao_mpu9250_current.mag_z);
463 }
464
465 #if MPU9250_TEST
466
467 static void
468 ao_mpu9250_read(void)
469 {
470         uint8_t addr;
471         uint8_t val;
472
473         addr = ao_cmd_hex();
474         if (ao_cmd_status != ao_cmd_success)
475                 return;
476         ao_mpu9250_spi_get();
477         val = _ao_mpu9250_reg_read(addr);
478         ao_mpu9250_spi_put();
479         printf("Addr %02x val %02x\n", addr, val);
480 }
481
482 static void
483 ao_mpu9250_write(void)
484 {
485         uint8_t addr;
486         uint8_t val;
487
488         addr = ao_cmd_hex();
489         if (ao_cmd_status != ao_cmd_success)
490                 return;
491         val = ao_cmd_hex();
492         if (ao_cmd_status != ao_cmd_success)
493                 return;
494         printf("Addr %02x val %02x\n", addr, val);
495         ao_mpu9250_spi_get();
496         _ao_mpu9250_reg_write(addr, val);
497         ao_mpu9250_spi_put();
498 }
499
500 static void
501 ao_mpu9250_mag_read(void)
502 {
503         uint8_t addr;
504         uint8_t val;
505
506         addr = ao_cmd_hex();
507         if (ao_cmd_status != ao_cmd_success)
508                 return;
509         ao_mpu9250_spi_get();
510         val = _ao_mpu9250_mag_reg_read(addr);
511         ao_mpu9250_spi_put();
512         printf("Addr %02x val %02x\n", addr, val);
513 }
514
515 static void
516 ao_mpu9250_mag_write(void)
517 {
518         uint8_t addr;
519         uint8_t val;
520
521         addr = ao_cmd_hex();
522         if (ao_cmd_status != ao_cmd_success)
523                 return;
524         val = ao_cmd_hex();
525         if (ao_cmd_status != ao_cmd_success)
526                 return;
527         printf("Addr %02x val %02x\n", addr, val);
528         ao_mpu9250_spi_get();
529         _ao_mpu9250_mag_reg_write(addr, val);
530         ao_mpu9250_spi_put();
531 }
532
533 #endif /* MPU9250_TEST */
534
535 static const struct ao_cmds ao_mpu9250_cmds[] = {
536         { ao_mpu9250_show,      "I\0Show MPU9250 status" },
537 #if MPU9250_TEST
538         { ao_mpu9250_read,      "R <addr>\0Read MPU9250 register" },
539         { ao_mpu9250_write,     "W <addr> <val>\0Write MPU9250 register" },
540         { ao_mpu9250_mag_read,  "G <addr>\0Read MPU9250 Mag register" },
541         { ao_mpu9250_mag_write, "P <addr> <val>\0Write MPU9250 Mag register" },
542 #endif
543         { 0, NULL }
544 };
545
546 void
547 ao_mpu9250_init(void)
548 {
549         ao_mpu9250_configured = 0;
550
551         ao_add_task(&ao_mpu9250_task, ao_mpu9250, "mpu9250");
552
553 #if AO_MPU9250_SPI
554         ao_spi_init_cs(AO_MPU9250_SPI_CS_PORT, (1 << AO_MPU9250_SPI_CS_PIN));
555
556         /* Pretend to be the mpu9250 task. Grab the SPI bus right away and
557          * hold it for the task so that nothing else uses the SPI bus before
558          * we get the I2C mode disabled in the chip
559          */
560
561         ao_cur_task = &ao_mpu9250_task;
562         ao_spi_get(AO_MPU9250_SPI_BUS, AO_SPI_SPEED_1MHz);
563         ao_cur_task = NULL;
564 #endif
565         ao_cmd_register(&ao_mpu9250_cmds[0]);
566 }
567 #endif