ARM: tegra12: loki: Fix regulator warnings
[linux-3.10.git] / drivers / misc / mpu3050 / accel / kxtf9.c
1 /*
2  $License:
3     Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   $
18  */
19
20 /**
21  *  @defgroup   ACCELDL (Motion Library - Accelerometer Driver Layer)
22  *  @brief      Provides the interface to setup and handle an accelerometers
23  *              connected to the secondary I2C interface of the gyroscope.
24  *
25  *  @{
26  *      @file   kxtf9.c
27  *      @brief  Accelerometer setup and handling methods.
28 */
29
30 /* ------------------ */
31 /* - Include Files. - */
32 /* ------------------ */
33
34 #undef MPL_LOG_NDEBUG
35 #define MPL_LOG_NDEBUG 1
36
37 #ifdef __KERNEL__
38 #include <linux/module.h>
39 #endif
40
41 #include "mpu.h"
42 #include "mlsl.h"
43 #include "mlos.h"
44
45 #include <log.h>
46 #undef MPL_LOG_TAG
47 #define MPL_LOG_TAG "MPL-acc"
48
49 #define KXTF9_XOUT_HPF_L                (0x00) /* 0000 0000 */
50 #define KXTF9_XOUT_HPF_H                (0x01) /* 0000 0001 */
51 #define KXTF9_YOUT_HPF_L                (0x02) /* 0000 0010 */
52 #define KXTF9_YOUT_HPF_H                (0x03) /* 0000 0011 */
53 #define KXTF9_ZOUT_HPF_L                (0x04) /* 0001 0100 */
54 #define KXTF9_ZOUT_HPF_H                (0x05) /* 0001 0101 */
55 #define KXTF9_XOUT_L                    (0x06) /* 0000 0110 */
56 #define KXTF9_XOUT_H                    (0x07) /* 0000 0111 */
57 #define KXTF9_YOUT_L                    (0x08) /* 0000 1000 */
58 #define KXTF9_YOUT_H                    (0x09) /* 0000 1001 */
59 #define KXTF9_ZOUT_L                    (0x0A) /* 0001 1010 */
60 #define KXTF9_ZOUT_H                    (0x0B) /* 0001 1011 */
61 #define KXTF9_ST_RESP                   (0x0C) /* 0000 1100 */
62 #define KXTF9_WHO_AM_I                  (0x0F) /* 0000 1111 */
63 #define KXTF9_TILT_POS_CUR              (0x10) /* 0001 0000 */
64 #define KXTF9_TILT_POS_PRE              (0x11) /* 0001 0001 */
65 #define KXTF9_INT_SRC_REG1              (0x15) /* 0001 0101 */
66 #define KXTF9_INT_SRC_REG2              (0x16) /* 0001 0110 */
67 #define KXTF9_STATUS_REG                (0x18) /* 0001 1000 */
68 #define KXTF9_INT_REL                   (0x1A) /* 0001 1010 */
69 #define KXTF9_CTRL_REG1                 (0x1B) /* 0001 1011 */
70 #define KXTF9_CTRL_REG2                 (0x1C) /* 0001 1100 */
71 #define KXTF9_CTRL_REG3                 (0x1D) /* 0001 1101 */
72 #define KXTF9_INT_CTRL_REG1             (0x1E) /* 0001 1110 */
73 #define KXTF9_INT_CTRL_REG2             (0x1F) /* 0001 1111 */
74 #define KXTF9_INT_CTRL_REG3             (0x20) /* 0010 0000 */
75 #define KXTF9_DATA_CTRL_REG             (0x21) /* 0010 0001 */
76 #define KXTF9_TILT_TIMER                (0x28) /* 0010 1000 */
77 #define KXTF9_WUF_TIMER                 (0x29) /* 0010 1001 */
78 #define KXTF9_TDT_TIMER                 (0x2B) /* 0010 1011 */
79 #define KXTF9_TDT_H_THRESH              (0x2C) /* 0010 1100 */
80 #define KXTF9_TDT_L_THRESH              (0x2D) /* 0010 1101 */
81 #define KXTF9_TDT_TAP_TIMER             (0x2E) /* 0010 1110 */
82 #define KXTF9_TDT_TOTAL_TIMER           (0x2F) /* 0010 1111 */
83 #define KXTF9_TDT_LATENCY_TIMER         (0x30) /* 0011 0000 */
84 #define KXTF9_TDT_WINDOW_TIMER          (0x31) /* 0011 0001 */
85 #define KXTF9_WUF_THRESH                (0x5A) /* 0101 1010 */
86 #define KXTF9_TILT_ANGLE                (0x5C) /* 0101 1100 */
87 #define KXTF9_HYST_SET                  (0x5F) /* 0101 1111 */
88
89 #define KXTF9_MAX_DUR (0xFF)
90 #define KXTF9_MAX_THS (0xFF)
91 #define KXTF9_THS_COUNTS_P_G (32)
92
93 /* --------------------- */
94 /* -    Variables.     - */
95 /* --------------------- */
96
97 struct kxtf9_config {
98         unsigned int odr; /* Output data rate mHz */
99         unsigned int fsr; /* full scale range mg */
100         unsigned int ths; /* Motion no-motion thseshold mg */
101         unsigned int dur; /* Motion no-motion duration ms */
102         unsigned int irq_type;
103         unsigned char reg_ths;
104         unsigned char reg_dur;
105         unsigned char reg_odr;
106         unsigned char reg_int_cfg1;
107         unsigned char reg_int_cfg2;
108         unsigned char ctrl_reg1;
109 };
110
111 struct kxtf9_private_data {
112         struct kxtf9_config suspend;
113         struct kxtf9_config resume;
114 };
115
116 /*****************************************
117     Accelerometer Initialization Functions
118 *****************************************/
119
120 static int kxtf9_set_ths(void *mlsl_handle,
121                         struct ext_slave_platform_data *pdata,
122                         struct kxtf9_config *config,
123                         int apply,
124                         long ths)
125 {
126         int result = ML_SUCCESS;
127         if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS)
128                 ths = (KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G;
129
130         if (ths < 0)
131                 ths = 0;
132
133         config->ths = ths;
134         config->reg_ths = (unsigned char)
135                 ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000);
136         MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
137         if (apply)
138                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
139                                         KXTF9_WUF_THRESH,
140                                         config->reg_ths);
141         return result;
142 }
143
144 static int kxtf9_set_dur(void *mlsl_handle,
145                         struct ext_slave_platform_data *pdata,
146                         struct kxtf9_config *config,
147                         int apply,
148                         long dur)
149 {
150         int result = ML_SUCCESS;
151         long reg_dur = (dur * config->odr) / 1000000;
152         config->dur = dur;
153
154         if (reg_dur > KXTF9_MAX_DUR)
155                 reg_dur = KXTF9_MAX_DUR;
156
157         config->reg_dur = (unsigned char) reg_dur;
158         MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
159         if (apply)
160                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
161                                         KXTF9_WUF_TIMER,
162                                         (unsigned char)reg_dur);
163         return result;
164 }
165
166 /**
167  * Sets the IRQ to fire when one of the IRQ events occur.  Threshold and
168  * duration will not be used uless the type is MOT or NMOT.
169  *
170  * @param config configuration to apply to, suspend or resume
171  * @param irq_type The type of IRQ.  Valid values are
172  * - MPU_SLAVE_IRQ_TYPE_NONE
173  * - MPU_SLAVE_IRQ_TYPE_MOTION
174  * - MPU_SLAVE_IRQ_TYPE_DATA_READY
175  */
176 static int kxtf9_set_irq(void *mlsl_handle,
177                         struct ext_slave_platform_data *pdata,
178                         struct kxtf9_config *config,
179                         int apply,
180                         long irq_type)
181 {
182         int result = ML_SUCCESS;
183         struct kxtf9_private_data *private_data = pdata->private_data;
184
185         config->irq_type = (unsigned char)irq_type;
186         config->ctrl_reg1 &= ~0x22;
187         if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
188                 config->ctrl_reg1 |= 0x20;
189                 config->reg_int_cfg1 = 0x38;
190                 config->reg_int_cfg2 = 0x00;
191         } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
192                 config->ctrl_reg1 |= 0x02;
193                 if ((unsigned long) config ==
194                         (unsigned long) &private_data->suspend)
195                         config->reg_int_cfg1 = 0x34;
196                 else
197                         config->reg_int_cfg1 = 0x24;
198                 config->reg_int_cfg2 = 0xE0;
199         } else {
200                 config->reg_int_cfg1 = 0x00;
201                 config->reg_int_cfg2 = 0x00;
202         }
203
204         if (apply) {
205                 /* Must clear bit 7 before writing new configuration */
206                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
207                                         KXTF9_CTRL_REG1, 0x40);
208                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
209                                         KXTF9_INT_CTRL_REG1,
210                                         config->reg_int_cfg1);
211                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
212                                         KXTF9_INT_CTRL_REG2,
213                                         config->reg_int_cfg2);
214                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
215                                         KXTF9_CTRL_REG1,
216                                         config->ctrl_reg1);
217         }
218         MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n",
219                 (unsigned long)config->ctrl_reg1,
220                 (unsigned long)config->reg_int_cfg1,
221                 (unsigned long)config->reg_int_cfg2);
222
223         return result;
224 }
225
226 /**
227  * Set the Output data rate for the particular configuration
228  *
229  * @param config Config to modify with new ODR
230  * @param odr Output data rate in units of 1/1000Hz
231  */
232 static int kxtf9_set_odr(void *mlsl_handle,
233                         struct ext_slave_platform_data *pdata,
234                         struct kxtf9_config *config,
235                         int apply,
236                         long odr)
237 {
238         unsigned char bits;
239         int result = ML_SUCCESS;
240
241         /* Data sheet says there is 12.5 hz, but that seems to produce a single
242          * correct data value, thus we remove it from the table */
243         if (odr > 400000) {
244                 config->odr = 800000;
245                 bits = 0x06;
246         } else if (odr > 200000) {
247                 config->odr = 400000;
248                 bits = 0x05;
249         } else if (odr > 100000) {
250                 config->odr = 200000;
251                 bits = 0x04;
252         } else if (odr > 50000) {
253                 config->odr = 100000;
254                 bits = 0x03;
255         } else if (odr > 25000) {
256                 config->odr = 50000;
257                 bits = 0x02;
258         } else if (odr != 0) {
259                 config->odr = 25000;
260                 bits = 0x01;
261         } else {
262                 config->odr = 0;
263                 bits = 0;
264         }
265
266         config->reg_odr = bits;
267         kxtf9_set_dur(mlsl_handle, pdata,
268                 config, apply, config->dur);
269         MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
270         if (apply) {
271                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
272                                         KXTF9_DATA_CTRL_REG,
273                                         config->reg_odr);
274                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
275                                         KXTF9_CTRL_REG1,
276                                         0x40);
277                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
278                                         KXTF9_CTRL_REG1,
279                                         config->ctrl_reg1);
280         }
281         return result;
282 }
283
284 /**
285  * Set the full scale range of the accels
286  *
287  * @param config pointer to configuration
288  * @param fsr requested full scale range
289  */
290 static int kxtf9_set_fsr(void *mlsl_handle,
291                         struct ext_slave_platform_data *pdata,
292                         struct kxtf9_config *config,
293                         int apply,
294                         long fsr)
295 {
296         int result = ML_SUCCESS;
297
298         config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7);
299         if (fsr <= 2000) {
300                 config->fsr = 2000;
301                 config->ctrl_reg1 |= 0x00;
302         } else if (fsr <= 4000) {
303                 config->fsr = 4000;
304                 config->ctrl_reg1 |= 0x08;
305         } else {
306                 config->fsr = 8000;
307                 config->ctrl_reg1 |= 0x10;
308         }
309
310         MPL_LOGV("FSR: %d\n", config->fsr);
311         if (apply) {
312                 /* Must clear bit 7 before writing new configuration */
313                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
314                                         KXTF9_CTRL_REG1, 0x40);
315                 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
316                                         KXTF9_CTRL_REG1, config->ctrl_reg1);
317         }
318         return result;
319 }
320
321 static int kxtf9_suspend(void *mlsl_handle,
322                          struct ext_slave_descr *slave,
323                          struct ext_slave_platform_data *pdata)
324 {
325         int result;
326         unsigned char data;
327         struct kxtf9_private_data *private_data = pdata->private_data;
328
329         /* Wake up */
330         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
331                                 KXTF9_CTRL_REG1, 0x40);
332         ERROR_CHECK(result);
333         /* INT_CTRL_REG1: */
334         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
335                                 KXTF9_INT_CTRL_REG1,
336                                 private_data->suspend.reg_int_cfg1);
337         ERROR_CHECK(result);
338         /* WUF_THRESH: */
339         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
340                                 KXTF9_WUF_THRESH,
341                                 private_data->suspend.reg_ths);
342         ERROR_CHECK(result);
343         /* DATA_CTRL_REG */
344         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
345                                 KXTF9_DATA_CTRL_REG,
346                                 private_data->suspend.reg_odr);
347         ERROR_CHECK(result);
348         /* WUF_TIMER */
349         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
350                                 KXTF9_WUF_TIMER, private_data->suspend.reg_dur);
351         ERROR_CHECK(result);
352
353         /* Normal operation  */
354         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
355                                 KXTF9_CTRL_REG1,
356                                 private_data->suspend.ctrl_reg1);
357         ERROR_CHECK(result);
358         result = MLSLSerialRead(mlsl_handle, pdata->address,
359                                 KXTF9_INT_REL, 1, &data);
360         ERROR_CHECK(result);
361
362         return result;
363 }
364
365 /* full scale setting - register and mask */
366 #define ACCEL_KIONIX_CTRL_REG      (0x1b)
367 #define ACCEL_KIONIX_CTRL_MASK     (0x18)
368
369 static int kxtf9_resume(void *mlsl_handle,
370                         struct ext_slave_descr *slave,
371                         struct ext_slave_platform_data *pdata)
372 {
373         int result = ML_SUCCESS;
374         unsigned char data;
375         struct kxtf9_private_data *private_data = pdata->private_data;
376
377         /* Wake up */
378         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
379                                 KXTF9_CTRL_REG1, 0x40);
380         ERROR_CHECK(result);
381         /* INT_CTRL_REG1: */
382         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
383                                 KXTF9_INT_CTRL_REG1,
384                                 private_data->resume.reg_int_cfg1);
385         ERROR_CHECK(result);
386         /* WUF_THRESH: */
387         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
388                                 KXTF9_WUF_THRESH, private_data->resume.reg_ths);
389         ERROR_CHECK(result);
390         /* DATA_CTRL_REG */
391         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
392                                 KXTF9_DATA_CTRL_REG,
393                                 private_data->resume.reg_odr);
394         ERROR_CHECK(result);
395         /* WUF_TIMER */
396         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
397                                 KXTF9_WUF_TIMER, private_data->resume.reg_dur);
398         ERROR_CHECK(result);
399
400         /* Normal operation  */
401         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
402                                 KXTF9_CTRL_REG1,
403                                 private_data->resume.ctrl_reg1);
404         ERROR_CHECK(result);
405         result = MLSLSerialRead(mlsl_handle, pdata->address,
406                                 KXTF9_INT_REL, 1, &data);
407         ERROR_CHECK(result);
408
409         return ML_SUCCESS;
410 }
411
412 static int kxtf9_init(void *mlsl_handle,
413                 struct ext_slave_descr *slave,
414                 struct ext_slave_platform_data *pdata)
415 {
416
417         struct kxtf9_private_data *private_data;
418         int result = ML_SUCCESS;
419
420         private_data = (struct kxtf9_private_data *)
421                 MLOSMalloc(sizeof(struct kxtf9_private_data));
422
423         if (!private_data)
424                 return ML_ERROR_MEMORY_EXAUSTED;
425
426         /* RAM reset */
427         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
428                                 KXTF9_CTRL_REG1,
429                                 0x40); /* Fastest Reset */
430         ERROR_CHECK(result);
431         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
432                                 KXTF9_DATA_CTRL_REG,
433                                 0x36); /* Fastest Reset */
434         ERROR_CHECK(result);
435         result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
436                                 KXTF9_CTRL_REG3, 0xcd); /* Reset */
437         ERROR_CHECK(result);
438         MLOSSleep(2);
439
440         pdata->private_data = private_data;
441
442         private_data->resume.ctrl_reg1 = 0xC0;
443         private_data->suspend.ctrl_reg1 = 0x40;
444
445         result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend,
446                         FALSE, 1000);
447         ERROR_CHECK(result);
448         result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume,
449                         FALSE,  2540);
450         ERROR_CHECK(result);
451
452         result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend,
453                         FALSE, 50000);
454         ERROR_CHECK(result);
455         result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume,
456                         FALSE, 200000);
457
458         result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend,
459                         FALSE, 2000);
460         ERROR_CHECK(result);
461         result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume,
462                         FALSE, 2000);
463         ERROR_CHECK(result);
464
465         result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend,
466                         FALSE, 80);
467         ERROR_CHECK(result);
468         result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume,
469                         FALSE, 40);
470         ERROR_CHECK(result);
471
472         result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend,
473                         FALSE,
474                         MPU_SLAVE_IRQ_TYPE_NONE);
475         ERROR_CHECK(result);
476         result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume,
477                         FALSE,
478                         MPU_SLAVE_IRQ_TYPE_NONE);
479         ERROR_CHECK(result);
480         return result;
481 }
482
483 static int kxtf9_exit(void *mlsl_handle,
484                           struct ext_slave_descr *slave,
485                           struct ext_slave_platform_data *pdata)
486 {
487         if (pdata->private_data)
488                 return MLOSFree(pdata->private_data);
489         else
490                 return ML_SUCCESS;
491 }
492
493 static int kxtf9_config(void *mlsl_handle,
494                         struct ext_slave_descr *slave,
495                         struct ext_slave_platform_data *pdata,
496                         struct ext_slave_config *data)
497 {
498         int retval;
499         long odr;
500         struct kxtf9_private_data *private_data = pdata->private_data;
501         if (!data->data)
502                 return ML_ERROR_INVALID_PARAMETER;
503
504         switch (data->key) {
505         case MPU_SLAVE_CONFIG_ODR_SUSPEND:
506                 return kxtf9_set_odr(mlsl_handle, pdata,
507                                         &private_data->suspend,
508                                         data->apply,
509                                         *((long *)data->data));
510         case MPU_SLAVE_CONFIG_ODR_RESUME:
511                 odr = *((long *)data->data);
512                 if (odr != 0)
513                         private_data->resume.ctrl_reg1 |= 0x80;
514
515                 retval = kxtf9_set_odr(mlsl_handle, pdata,
516                                 &private_data->resume,
517                                 data->apply,
518                                 odr);
519                 return retval;
520         case MPU_SLAVE_CONFIG_FSR_SUSPEND:
521                 return kxtf9_set_fsr(mlsl_handle, pdata,
522                                         &private_data->suspend,
523                                         data->apply,
524                                         *((long *)data->data));
525         case MPU_SLAVE_CONFIG_FSR_RESUME:
526                 return kxtf9_set_fsr(mlsl_handle, pdata,
527                                         &private_data->resume,
528                                         data->apply,
529                                         *((long *)data->data));
530         case MPU_SLAVE_CONFIG_MOT_THS:
531                 return kxtf9_set_ths(mlsl_handle, pdata,
532                                         &private_data->suspend,
533                                         data->apply,
534                                         *((long *)data->data));
535         case MPU_SLAVE_CONFIG_NMOT_THS:
536                 return kxtf9_set_ths(mlsl_handle, pdata,
537                                         &private_data->resume,
538                                         data->apply,
539                                         *((long *)data->data));
540         case MPU_SLAVE_CONFIG_MOT_DUR:
541                 return kxtf9_set_dur(mlsl_handle, pdata,
542                                         &private_data->suspend,
543                                         data->apply,
544                                         *((long *)data->data));
545         case MPU_SLAVE_CONFIG_NMOT_DUR:
546                 return kxtf9_set_dur(mlsl_handle, pdata,
547                                         &private_data->resume,
548                                         data->apply,
549                                         *((long *)data->data));
550         case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
551                 return kxtf9_set_irq(mlsl_handle, pdata,
552                                         &private_data->suspend,
553                                         data->apply,
554                                         *((long *)data->data));
555         case MPU_SLAVE_CONFIG_IRQ_RESUME:
556                 return kxtf9_set_irq(mlsl_handle, pdata,
557                                         &private_data->resume,
558                                         data->apply,
559                                         *((long *)data->data));
560         default:
561                 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
562         };
563
564         return ML_SUCCESS;
565 }
566
567 static int kxtf9_get_config(void *mlsl_handle,
568                                 struct ext_slave_descr *slave,
569                                 struct ext_slave_platform_data *pdata,
570                                 struct ext_slave_config *data)
571 {
572         struct kxtf9_private_data *private_data = pdata->private_data;
573         if (!data->data)
574                 return ML_ERROR_INVALID_PARAMETER;
575
576         switch (data->key) {
577         case MPU_SLAVE_CONFIG_ODR_SUSPEND:
578                 (*(unsigned long *)data->data) =
579                         (unsigned long) private_data->suspend.odr;
580                 break;
581         case MPU_SLAVE_CONFIG_ODR_RESUME:
582                 (*(unsigned long *)data->data) =
583                         (unsigned long) private_data->resume.odr;
584                 break;
585         case MPU_SLAVE_CONFIG_FSR_SUSPEND:
586                 (*(unsigned long *)data->data) =
587                         (unsigned long) private_data->suspend.fsr;
588                 break;
589         case MPU_SLAVE_CONFIG_FSR_RESUME:
590                 (*(unsigned long *)data->data) =
591                         (unsigned long) private_data->resume.fsr;
592                 break;
593         case MPU_SLAVE_CONFIG_MOT_THS:
594                 (*(unsigned long *)data->data) =
595                         (unsigned long) private_data->suspend.ths;
596                 break;
597         case MPU_SLAVE_CONFIG_NMOT_THS:
598                 (*(unsigned long *)data->data) =
599                         (unsigned long) private_data->resume.ths;
600                 break;
601         case MPU_SLAVE_CONFIG_MOT_DUR:
602                 (*(unsigned long *)data->data) =
603                         (unsigned long) private_data->suspend.dur;
604                 break;
605         case MPU_SLAVE_CONFIG_NMOT_DUR:
606                 (*(unsigned long *)data->data) =
607                         (unsigned long) private_data->resume.dur;
608                 break;
609         case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
610                 (*(unsigned long *)data->data) =
611                         (unsigned long) private_data->suspend.irq_type;
612                 break;
613         case MPU_SLAVE_CONFIG_IRQ_RESUME:
614                 (*(unsigned long *)data->data) =
615                         (unsigned long) private_data->resume.irq_type;
616                 break;
617         default:
618                 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
619         };
620
621         return ML_SUCCESS;
622 }
623
624 static int kxtf9_read(void *mlsl_handle,
625                       struct ext_slave_descr *slave,
626                       struct ext_slave_platform_data *pdata,
627                       unsigned char *data)
628 {
629         int result;
630         unsigned char reg;
631         result = MLSLSerialRead(mlsl_handle, pdata->address,
632                                 KXTF9_INT_SRC_REG2, 1, &reg);
633         ERROR_CHECK(result);
634
635         if (!(reg & 0x10))
636                 return ML_ERROR_ACCEL_DATA_NOT_READY;
637
638         result = MLSLSerialRead(mlsl_handle, pdata->address,
639                                 slave->reg, slave->len, data);
640         ERROR_CHECK(result);
641         return result;
642 }
643
644 static struct ext_slave_descr kxtf9_descr = {
645         /*.init             = */ kxtf9_init,
646         /*.exit             = */ kxtf9_exit,
647         /*.suspend          = */ kxtf9_suspend,
648         /*.resume           = */ kxtf9_resume,
649         /*.read             = */ kxtf9_read,
650         /*.config           = */ kxtf9_config,
651         /*.get_config       = */ kxtf9_get_config,
652         /*.name             = */ "kxtf9",
653         /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
654         /*.id               = */ ACCEL_ID_KXTF9,
655         /*.reg              = */ 0x06,
656         /*.len              = */ 6,
657         /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
658         /*.range            = */ {2, 0},
659 };
660
661 struct ext_slave_descr *kxtf9_get_slave_descr(void)
662 {
663         return &kxtf9_descr;
664 }
665 EXPORT_SYMBOL(kxtf9_get_slave_descr);
666
667 /**
668  *  @}
669 **/