ARM: tegra12: loki: Fix regulator warnings
[linux-3.10.git] / drivers / misc / inv_mpu / accel / kxtf9.c
1 /*
2         $License:
3         Copyright (C) 2011 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  *  @addtogroup ACCELDL
22  *  @brief      Accelerometer setup and handling methods for Kionix KXTF9.
23  *
24  *  @{
25  *      @file   kxtf9.c
26  *      @brief  Accelerometer setup and handling methods for Kionix KXTF9.
27 */
28
29 /* -------------------------------------------------------------------------- */
30
31 #undef MPL_LOG_NDEBUG
32 #define MPL_LOG_NDEBUG 1
33
34 #include <linux/i2c.h>
35 #include <linux/module.h>
36 #include <linux/moduleparam.h>
37 #include <linux/kernel.h>
38 #include <linux/errno.h>
39 #include <linux/slab.h>
40 #include <linux/delay.h>
41 #include "mpu-dev.h"
42
43 #include <log.h>
44 #include <linux/mpu.h>
45 #include "mlsl.h"
46 #include "mldl_cfg.h"
47 #undef MPL_LOG_TAG
48 #define MPL_LOG_TAG "MPL-acc"
49
50 #define KXTF9_XOUT_HPF_L                (0x00)  /* 0000 0000 */
51 #define KXTF9_XOUT_HPF_H                (0x01)  /* 0000 0001 */
52 #define KXTF9_YOUT_HPF_L                (0x02)  /* 0000 0010 */
53 #define KXTF9_YOUT_HPF_H                (0x03)  /* 0000 0011 */
54 #define KXTF9_ZOUT_HPF_L                (0x04)  /* 0001 0100 */
55 #define KXTF9_ZOUT_HPF_H                (0x05)  /* 0001 0101 */
56 #define KXTF9_XOUT_L                    (0x06)  /* 0000 0110 */
57 #define KXTF9_XOUT_H                    (0x07)  /* 0000 0111 */
58 #define KXTF9_YOUT_L                    (0x08)  /* 0000 1000 */
59 #define KXTF9_YOUT_H                    (0x09)  /* 0000 1001 */
60 #define KXTF9_ZOUT_L                    (0x0A)  /* 0001 1010 */
61 #define KXTF9_ZOUT_H                    (0x0B)  /* 0001 1011 */
62 #define KXTF9_ST_RESP                   (0x0C)  /* 0000 1100 */
63 #define KXTF9_WHO_AM_I                  (0x0F)  /* 0000 1111 */
64 #define KXTF9_TILT_POS_CUR              (0x10)  /* 0001 0000 */
65 #define KXTF9_TILT_POS_PRE              (0x11)  /* 0001 0001 */
66 #define KXTF9_INT_SRC_REG1              (0x15)  /* 0001 0101 */
67 #define KXTF9_INT_SRC_REG2              (0x16)  /* 0001 0110 */
68 #define KXTF9_STATUS_REG                (0x18)  /* 0001 1000 */
69 #define KXTF9_INT_REL                   (0x1A)  /* 0001 1010 */
70 #define KXTF9_CTRL_REG1                 (0x1B)  /* 0001 1011 */
71 #define KXTF9_CTRL_REG2                 (0x1C)  /* 0001 1100 */
72 #define KXTF9_CTRL_REG3                 (0x1D)  /* 0001 1101 */
73 #define KXTF9_INT_CTRL_REG1             (0x1E)  /* 0001 1110 */
74 #define KXTF9_INT_CTRL_REG2             (0x1F)  /* 0001 1111 */
75 #define KXTF9_INT_CTRL_REG3             (0x20)  /* 0010 0000 */
76 #define KXTF9_DATA_CTRL_REG             (0x21)  /* 0010 0001 */
77 #define KXTF9_TILT_TIMER                (0x28)  /* 0010 1000 */
78 #define KXTF9_WUF_TIMER                 (0x29)  /* 0010 1001 */
79 #define KXTF9_TDT_TIMER                 (0x2B)  /* 0010 1011 */
80 #define KXTF9_TDT_H_THRESH              (0x2C)  /* 0010 1100 */
81 #define KXTF9_TDT_L_THRESH              (0x2D)  /* 0010 1101 */
82 #define KXTF9_TDT_TAP_TIMER             (0x2E)  /* 0010 1110 */
83 #define KXTF9_TDT_TOTAL_TIMER           (0x2F)  /* 0010 1111 */
84 #define KXTF9_TDT_LATENCY_TIMER         (0x30)  /* 0011 0000 */
85 #define KXTF9_TDT_WINDOW_TIMER          (0x31)  /* 0011 0001 */
86 #define KXTF9_WUF_THRESH                (0x5A)  /* 0101 1010 */
87 #define KXTF9_TILT_ANGLE                (0x5C)  /* 0101 1100 */
88 #define KXTF9_HYST_SET                  (0x5F)  /* 0101 1111 */
89
90 #define KXTF9_MAX_DUR (0xFF)
91 #define KXTF9_MAX_THS (0xFF)
92 #define KXTF9_THS_COUNTS_P_G (32)
93
94 /* -------------------------------------------------------------------------- */
95
96 struct kxtf9_config {
97         unsigned long odr;      /* Output data rate mHz */
98         unsigned int fsr;       /* full scale range mg */
99         unsigned int ths;       /* Motion no-motion thseshold mg */
100         unsigned int dur;       /* Motion no-motion duration ms */
101         unsigned int irq_type;
102         unsigned char reg_ths;
103         unsigned char reg_dur;
104         unsigned char reg_odr;
105         unsigned char reg_int_cfg1;
106         unsigned char reg_int_cfg2;
107         unsigned char ctrl_reg1;
108 };
109
110 struct kxtf9_private_data {
111         struct kxtf9_config suspend;
112         struct kxtf9_config resume;
113 };
114
115 static int kxtf9_set_ths(void *mlsl_handle,
116                          struct ext_slave_platform_data *pdata,
117                          struct kxtf9_config *config, int apply, long ths)
118 {
119         int result = INV_SUCCESS;
120         if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS)
121                 ths = (long)(KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G;
122
123         if (ths < 0)
124                 ths = 0;
125
126         config->ths = ths;
127         config->reg_ths = (unsigned char)
128             ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000);
129         MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
130         if (apply)
131                 result = inv_serial_single_write(mlsl_handle, pdata->address,
132                                                  KXTF9_WUF_THRESH,
133                                                  config->reg_ths);
134         return result;
135 }
136
137 static int kxtf9_set_dur(void *mlsl_handle,
138                          struct ext_slave_platform_data *pdata,
139                          struct kxtf9_config *config, int apply, long dur)
140 {
141         int result = INV_SUCCESS;
142         long reg_dur = (dur * config->odr) / 1000000L;
143         config->dur = dur;
144
145         if (reg_dur > KXTF9_MAX_DUR)
146                 reg_dur = KXTF9_MAX_DUR;
147
148         config->reg_dur = (unsigned char)reg_dur;
149         MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
150         if (apply)
151                 result = inv_serial_single_write(mlsl_handle, pdata->address,
152                                                  KXTF9_WUF_TIMER,
153                                                  (unsigned char)reg_dur);
154         return result;
155 }
156
157 /**
158  * Sets the IRQ to fire when one of the IRQ events occur.  Threshold and
159  * duration will not be used uless the type is MOT or NMOT.
160  *
161  * @param config configuration to apply to, suspend or resume
162  * @param irq_type The type of IRQ.  Valid values are
163  * - MPU_SLAVE_IRQ_TYPE_NONE
164  * - MPU_SLAVE_IRQ_TYPE_MOTION
165  * - MPU_SLAVE_IRQ_TYPE_DATA_READY
166  */
167 static int kxtf9_set_irq(void *mlsl_handle,
168                          struct ext_slave_platform_data *pdata,
169                          struct kxtf9_config *config, int apply, long irq_type)
170 {
171         int result = INV_SUCCESS;
172         struct kxtf9_private_data *private_data = pdata->private_data;
173
174         config->irq_type = (unsigned char)irq_type;
175         config->ctrl_reg1 &= ~0x22;
176         if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
177                 config->ctrl_reg1 |= 0x20;
178                 config->reg_int_cfg1 = 0x38;
179                 config->reg_int_cfg2 = 0x00;
180         } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
181                 config->ctrl_reg1 |= 0x02;
182                 if ((unsigned long)config ==
183                     (unsigned long)&private_data->suspend)
184                         config->reg_int_cfg1 = 0x34;
185                 else
186                         config->reg_int_cfg1 = 0x24;
187                 config->reg_int_cfg2 = 0xE0;
188         } else {
189                 config->reg_int_cfg1 = 0x00;
190                 config->reg_int_cfg2 = 0x00;
191         }
192
193         if (apply) {
194                 /* Must clear bit 7 before writing new configuration */
195                 result = inv_serial_single_write(mlsl_handle, pdata->address,
196                                                  KXTF9_CTRL_REG1, 0x40);
197                 result = inv_serial_single_write(mlsl_handle, pdata->address,
198                                                  KXTF9_INT_CTRL_REG1,
199                                                  config->reg_int_cfg1);
200                 result = inv_serial_single_write(mlsl_handle, pdata->address,
201                                                  KXTF9_INT_CTRL_REG2,
202                                                  config->reg_int_cfg2);
203                 result = inv_serial_single_write(mlsl_handle, pdata->address,
204                                                  KXTF9_CTRL_REG1,
205                                                  config->ctrl_reg1);
206         }
207         MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n",
208                  (unsigned long)config->ctrl_reg1,
209                  (unsigned long)config->reg_int_cfg1,
210                  (unsigned long)config->reg_int_cfg2);
211
212         return result;
213 }
214
215 /**
216  * Set the Output data rate for the particular configuration
217  *
218  * @param config Config to modify with new ODR
219  * @param odr Output data rate in units of 1/1000Hz
220  */
221 static int kxtf9_set_odr(void *mlsl_handle,
222                          struct ext_slave_platform_data *pdata,
223                          struct kxtf9_config *config, int apply, long odr)
224 {
225         unsigned char bits;
226         int result = INV_SUCCESS;
227
228         /* Data sheet says there is 12.5 hz, but that seems to produce a single
229          * correct data value, thus we remove it from the table */
230         if (odr > 400000L) {
231                 config->odr = 800000L;
232                 bits = 0x06;
233         } else if (odr > 200000L) {
234                 config->odr = 400000L;
235                 bits = 0x05;
236         } else if (odr > 100000L) {
237                 config->odr = 200000L;
238                 bits = 0x04;
239         } else if (odr > 50000) {
240                 config->odr = 100000L;
241                 bits = 0x03;
242         } else if (odr > 25000) {
243                 config->odr = 50000;
244                 bits = 0x02;
245         } else if (odr != 0) {
246                 config->odr = 25000;
247                 bits = 0x01;
248         } else {
249                 config->odr = 0;
250                 bits = 0;
251         }
252
253         if (odr != 0)
254                 config->ctrl_reg1 |= 0x80;
255         else
256                 config->ctrl_reg1 &= ~0x80;
257
258         config->reg_odr = bits;
259         kxtf9_set_dur(mlsl_handle, pdata, config, apply, config->dur);
260         MPL_LOGV("ODR: %ld, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
261         if (apply) {
262                 result = inv_serial_single_write(mlsl_handle, pdata->address,
263                                                  KXTF9_DATA_CTRL_REG,
264                                                  config->reg_odr);
265                 result = inv_serial_single_write(mlsl_handle, pdata->address,
266                                                  KXTF9_CTRL_REG1, 0x40);
267                 result = inv_serial_single_write(mlsl_handle, pdata->address,
268                                                  KXTF9_CTRL_REG1,
269                                                  config->ctrl_reg1);
270         }
271         return result;
272 }
273
274 /**
275  * Set the full scale range of the accels
276  *
277  * @param config pointer to configuration
278  * @param fsr requested full scale range
279  */
280 static int kxtf9_set_fsr(void *mlsl_handle,
281                          struct ext_slave_platform_data *pdata,
282                          struct kxtf9_config *config, int apply, long fsr)
283 {
284         int result = INV_SUCCESS;
285
286         config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7);
287         if (fsr <= 2000) {
288                 config->fsr = 2000;
289                 config->ctrl_reg1 |= 0x00;
290         } else if (fsr <= 4000) {
291                 config->fsr = 4000;
292                 config->ctrl_reg1 |= 0x08;
293         } else {
294                 config->fsr = 8000;
295                 config->ctrl_reg1 |= 0x10;
296         }
297
298         MPL_LOGV("FSR: %d\n", config->fsr);
299         if (apply) {
300                 /* Must clear bit 7 before writing new configuration */
301                 result = inv_serial_single_write(mlsl_handle, pdata->address,
302                                                  KXTF9_CTRL_REG1, 0x40);
303                 result = inv_serial_single_write(mlsl_handle, pdata->address,
304                                                  KXTF9_CTRL_REG1,
305                                                  config->ctrl_reg1);
306         }
307         return result;
308 }
309
310 static int kxtf9_suspend(void *mlsl_handle,
311                          struct ext_slave_descr *slave,
312                          struct ext_slave_platform_data *pdata)
313 {
314         int result;
315         unsigned char data;
316         struct kxtf9_private_data *private_data = pdata->private_data;
317
318         /* Wake up */
319         result = inv_serial_single_write(mlsl_handle, pdata->address,
320                                          KXTF9_CTRL_REG1, 0x40);
321         if (result) {
322                 LOG_RESULT_LOCATION(result);
323                 return result;
324         }
325         /* INT_CTRL_REG1: */
326         result = inv_serial_single_write(mlsl_handle, pdata->address,
327                                          KXTF9_INT_CTRL_REG1,
328                                          private_data->suspend.reg_int_cfg1);
329         if (result) {
330                 LOG_RESULT_LOCATION(result);
331                 return result;
332         }
333         /* WUF_THRESH: */
334         result = inv_serial_single_write(mlsl_handle, pdata->address,
335                                          KXTF9_WUF_THRESH,
336                                          private_data->suspend.reg_ths);
337         if (result) {
338                 LOG_RESULT_LOCATION(result);
339                 return result;
340         }
341         /* DATA_CTRL_REG */
342         result = inv_serial_single_write(mlsl_handle, pdata->address,
343                                          KXTF9_DATA_CTRL_REG,
344                                          private_data->suspend.reg_odr);
345         if (result) {
346                 LOG_RESULT_LOCATION(result);
347                 return result;
348         }
349         /* WUF_TIMER */
350         result = inv_serial_single_write(mlsl_handle, pdata->address,
351                                          KXTF9_WUF_TIMER,
352                                          private_data->suspend.reg_dur);
353         if (result) {
354                 LOG_RESULT_LOCATION(result);
355                 return result;
356         }
357
358         /* Normal operation  */
359         result = inv_serial_single_write(mlsl_handle, pdata->address,
360                                          KXTF9_CTRL_REG1,
361                                          private_data->suspend.ctrl_reg1);
362         if (result) {
363                 LOG_RESULT_LOCATION(result);
364                 return result;
365         }
366         result = inv_serial_read(mlsl_handle, pdata->address,
367                                  KXTF9_INT_REL, 1, &data);
368         if (result) {
369                 LOG_RESULT_LOCATION(result);
370                 return result;
371         }
372
373         return result;
374 }
375
376 /* full scale setting - register and mask */
377 #define ACCEL_KIONIX_CTRL_REG      (0x1b)
378 #define ACCEL_KIONIX_CTRL_MASK     (0x18)
379
380 static int kxtf9_resume(void *mlsl_handle,
381                         struct ext_slave_descr *slave,
382                         struct ext_slave_platform_data *pdata)
383 {
384         int result = INV_SUCCESS;
385         unsigned char data;
386         struct kxtf9_private_data *private_data = pdata->private_data;
387
388         /* Wake up */
389         result = inv_serial_single_write(mlsl_handle, pdata->address,
390                                          KXTF9_CTRL_REG1, 0x40);
391         if (result) {
392                 LOG_RESULT_LOCATION(result);
393                 return result;
394         }
395         /* INT_CTRL_REG1: */
396         result = inv_serial_single_write(mlsl_handle, pdata->address,
397                                          KXTF9_INT_CTRL_REG1,
398                                          private_data->resume.reg_int_cfg1);
399         if (result) {
400                 LOG_RESULT_LOCATION(result);
401                 return result;
402         }
403         /* WUF_THRESH: */
404         result = inv_serial_single_write(mlsl_handle, pdata->address,
405                                          KXTF9_WUF_THRESH,
406                                          private_data->resume.reg_ths);
407         if (result) {
408                 LOG_RESULT_LOCATION(result);
409                 return result;
410         }
411         /* DATA_CTRL_REG */
412         result = inv_serial_single_write(mlsl_handle, pdata->address,
413                                          KXTF9_DATA_CTRL_REG,
414                                          private_data->resume.reg_odr);
415         if (result) {
416                 LOG_RESULT_LOCATION(result);
417                 return result;
418         }
419         /* WUF_TIMER */
420         result = inv_serial_single_write(mlsl_handle, pdata->address,
421                                          KXTF9_WUF_TIMER,
422                                          private_data->resume.reg_dur);
423         if (result) {
424                 LOG_RESULT_LOCATION(result);
425                 return result;
426         }
427
428         /* Normal operation  */
429         result = inv_serial_single_write(mlsl_handle, pdata->address,
430                                          KXTF9_CTRL_REG1,
431                                          private_data->resume.ctrl_reg1);
432         if (result) {
433                 LOG_RESULT_LOCATION(result);
434                 return result;
435         }
436         result = inv_serial_read(mlsl_handle, pdata->address,
437                                  KXTF9_INT_REL, 1, &data);
438         if (result) {
439                 LOG_RESULT_LOCATION(result);
440                 return result;
441         }
442
443         return INV_SUCCESS;
444 }
445
446 static int kxtf9_init(void *mlsl_handle,
447                       struct ext_slave_descr *slave,
448                       struct ext_slave_platform_data *pdata)
449 {
450
451         struct kxtf9_private_data *private_data;
452         int result = INV_SUCCESS;
453
454         private_data = (struct kxtf9_private_data *)
455             kzalloc(sizeof(struct kxtf9_private_data), GFP_KERNEL);
456
457         if (!private_data)
458                 return INV_ERROR_MEMORY_EXAUSTED;
459
460         /* RAM reset */
461         /* Fastest Reset */
462         result = inv_serial_single_write(mlsl_handle, pdata->address,
463                                          KXTF9_CTRL_REG1, 0x40);
464         if (result) {
465                 LOG_RESULT_LOCATION(result);
466                 return result;
467         }
468         /* Fastest Reset */
469         result = inv_serial_single_write(mlsl_handle, pdata->address,
470                                          KXTF9_DATA_CTRL_REG, 0x36);
471         if (result) {
472                 LOG_RESULT_LOCATION(result);
473                 return result;
474         }
475         /* Reset */
476         result = inv_serial_single_write(mlsl_handle, pdata->address,
477                                          KXTF9_CTRL_REG3, 0xcd);
478         if (result) {
479                 LOG_RESULT_LOCATION(result);
480                 return result;
481         }
482         msleep(2);
483
484         pdata->private_data = private_data;
485
486         private_data->resume.ctrl_reg1 = 0xC0;
487         private_data->suspend.ctrl_reg1 = 0x40;
488
489         result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend,
490                                false, 1000);
491         if (result) {
492                 LOG_RESULT_LOCATION(result);
493                 return result;
494         }
495         result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume,
496                                false, 2540);
497         if (result) {
498                 LOG_RESULT_LOCATION(result);
499                 return result;
500         }
501
502         result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend,
503                                false, 50000);
504         if (result) {
505                 LOG_RESULT_LOCATION(result);
506                 return result;
507         }
508         result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume,
509                                false, 200000L);
510
511         result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend,
512                                false, 2000);
513         if (result) {
514                 LOG_RESULT_LOCATION(result);
515                 return result;
516         }
517         result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume,
518                                false, 2000);
519         if (result) {
520                 LOG_RESULT_LOCATION(result);
521                 return result;
522         }
523
524         result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend,
525                                false, 80);
526         if (result) {
527                 LOG_RESULT_LOCATION(result);
528                 return result;
529         }
530         result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume,
531                                false, 40);
532         if (result) {
533                 LOG_RESULT_LOCATION(result);
534                 return result;
535         }
536
537         result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend,
538                                false, MPU_SLAVE_IRQ_TYPE_NONE);
539         if (result) {
540                 LOG_RESULT_LOCATION(result);
541                 return result;
542         }
543         result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume,
544                                false, MPU_SLAVE_IRQ_TYPE_NONE);
545         if (result) {
546                 LOG_RESULT_LOCATION(result);
547                 return result;
548         }
549         return result;
550 }
551
552 static int kxtf9_exit(void *mlsl_handle,
553                       struct ext_slave_descr *slave,
554                       struct ext_slave_platform_data *pdata)
555 {
556         kfree(pdata->private_data);
557         return INV_SUCCESS;
558 }
559
560 static int kxtf9_config(void *mlsl_handle,
561                         struct ext_slave_descr *slave,
562                         struct ext_slave_platform_data *pdata,
563                         struct ext_slave_config *data)
564 {
565         struct kxtf9_private_data *private_data = pdata->private_data;
566         if (!data->data)
567                 return INV_ERROR_INVALID_PARAMETER;
568
569         switch (data->key) {
570         case MPU_SLAVE_CONFIG_ODR_SUSPEND:
571                 return kxtf9_set_odr(mlsl_handle, pdata,
572                                      &private_data->suspend,
573                                      data->apply, *((long *)data->data));
574         case MPU_SLAVE_CONFIG_ODR_RESUME:
575                 return kxtf9_set_odr(mlsl_handle, pdata,
576                                      &private_data->resume,
577                                      data->apply, *((long *)data->data));
578         case MPU_SLAVE_CONFIG_FSR_SUSPEND:
579                 return kxtf9_set_fsr(mlsl_handle, pdata,
580                                      &private_data->suspend,
581                                      data->apply, *((long *)data->data));
582         case MPU_SLAVE_CONFIG_FSR_RESUME:
583                 return kxtf9_set_fsr(mlsl_handle, pdata,
584                                      &private_data->resume,
585                                      data->apply, *((long *)data->data));
586         case MPU_SLAVE_CONFIG_MOT_THS:
587                 return kxtf9_set_ths(mlsl_handle, pdata,
588                                      &private_data->suspend,
589                                      data->apply, *((long *)data->data));
590         case MPU_SLAVE_CONFIG_NMOT_THS:
591                 return kxtf9_set_ths(mlsl_handle, pdata,
592                                      &private_data->resume,
593                                      data->apply, *((long *)data->data));
594         case MPU_SLAVE_CONFIG_MOT_DUR:
595                 return kxtf9_set_dur(mlsl_handle, pdata,
596                                      &private_data->suspend,
597                                      data->apply, *((long *)data->data));
598         case MPU_SLAVE_CONFIG_NMOT_DUR:
599                 return kxtf9_set_dur(mlsl_handle, pdata,
600                                      &private_data->resume,
601                                      data->apply, *((long *)data->data));
602         case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
603                 return kxtf9_set_irq(mlsl_handle, pdata,
604                                      &private_data->suspend,
605                                      data->apply, *((long *)data->data));
606         case MPU_SLAVE_CONFIG_IRQ_RESUME:
607                 return kxtf9_set_irq(mlsl_handle, pdata,
608                                      &private_data->resume,
609                                      data->apply, *((long *)data->data));
610         default:
611                 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
612         };
613
614         return INV_SUCCESS;
615 }
616
617 static int kxtf9_get_config(void *mlsl_handle,
618                             struct ext_slave_descr *slave,
619                             struct ext_slave_platform_data *pdata,
620                             struct ext_slave_config *data)
621 {
622         struct kxtf9_private_data *private_data = pdata->private_data;
623         if (!data->data)
624                 return INV_ERROR_INVALID_PARAMETER;
625
626         switch (data->key) {
627         case MPU_SLAVE_CONFIG_ODR_SUSPEND:
628                 (*(unsigned long *)data->data) =
629                     (unsigned long)private_data->suspend.odr;
630                 break;
631         case MPU_SLAVE_CONFIG_ODR_RESUME:
632                 (*(unsigned long *)data->data) =
633                     (unsigned long)private_data->resume.odr;
634                 break;
635         case MPU_SLAVE_CONFIG_FSR_SUSPEND:
636                 (*(unsigned long *)data->data) =
637                     (unsigned long)private_data->suspend.fsr;
638                 break;
639         case MPU_SLAVE_CONFIG_FSR_RESUME:
640                 (*(unsigned long *)data->data) =
641                     (unsigned long)private_data->resume.fsr;
642                 break;
643         case MPU_SLAVE_CONFIG_MOT_THS:
644                 (*(unsigned long *)data->data) =
645                     (unsigned long)private_data->suspend.ths;
646                 break;
647         case MPU_SLAVE_CONFIG_NMOT_THS:
648                 (*(unsigned long *)data->data) =
649                     (unsigned long)private_data->resume.ths;
650                 break;
651         case MPU_SLAVE_CONFIG_MOT_DUR:
652                 (*(unsigned long *)data->data) =
653                     (unsigned long)private_data->suspend.dur;
654                 break;
655         case MPU_SLAVE_CONFIG_NMOT_DUR:
656                 (*(unsigned long *)data->data) =
657                     (unsigned long)private_data->resume.dur;
658                 break;
659         case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
660                 (*(unsigned long *)data->data) =
661                     (unsigned long)private_data->suspend.irq_type;
662                 break;
663         case MPU_SLAVE_CONFIG_IRQ_RESUME:
664                 (*(unsigned long *)data->data) =
665                     (unsigned long)private_data->resume.irq_type;
666                 break;
667         default:
668                 return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
669         };
670
671         return INV_SUCCESS;
672 }
673
674 static int kxtf9_read(void *mlsl_handle,
675                       struct ext_slave_descr *slave,
676                       struct ext_slave_platform_data *pdata,
677                       unsigned char *data)
678 {
679         int result;
680         unsigned char reg;
681         result = inv_serial_read(mlsl_handle, pdata->address,
682                                  KXTF9_INT_SRC_REG2, 1, &reg);
683         if (result) {
684                 LOG_RESULT_LOCATION(result);
685                 return result;
686         }
687
688         if (!(reg & 0x10))
689                 return INV_ERROR_ACCEL_DATA_NOT_READY;
690
691         result = inv_serial_read(mlsl_handle, pdata->address,
692                                  slave->read_reg, slave->read_len, data);
693         if (result) {
694                 LOG_RESULT_LOCATION(result);
695                 return result;
696         }
697         return result;
698 }
699
700 static struct ext_slave_descr kxtf9_descr = {
701         .init             = kxtf9_init,
702         .exit             = kxtf9_exit,
703         .suspend          = kxtf9_suspend,
704         .resume           = kxtf9_resume,
705         .read             = kxtf9_read,
706         .config           = kxtf9_config,
707         .get_config       = kxtf9_get_config,
708         .name             = "kxtf9",
709         .type             = EXT_SLAVE_TYPE_ACCEL,
710         .id               = ACCEL_ID_KXTF9,
711         .read_reg         = 0x06,
712         .read_len         = 6,
713         .endian           = EXT_SLAVE_LITTLE_ENDIAN,
714         .range            = {2, 0},
715         .trigger          = NULL,
716 };
717
718 static
719 struct ext_slave_descr *kxtf9_get_slave_descr(void)
720 {
721         return &kxtf9_descr;
722 }
723
724 /* -------------------------------------------------------------------------- */
725 struct kxtf9_mod_private_data {
726         struct i2c_client *client;
727         struct ext_slave_platform_data *pdata;
728 };
729
730 static unsigned short normal_i2c[] = { I2C_CLIENT_END };
731
732 static int kxtf9_mod_probe(struct i2c_client *client,
733                            const struct i2c_device_id *devid)
734 {
735         struct ext_slave_platform_data *pdata;
736         struct kxtf9_mod_private_data *private_data;
737         int result = 0;
738
739         dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
740
741         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
742                 result = -ENODEV;
743                 goto out_no_free;
744         }
745
746         pdata = client->dev.platform_data;
747         if (!pdata) {
748                 dev_err(&client->adapter->dev,
749                         "Missing platform data for slave %s\n", devid->name);
750                 result = -EFAULT;
751                 goto out_no_free;
752         }
753
754         private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
755         if (!private_data) {
756                 result = -ENOMEM;
757                 goto out_no_free;
758         }
759
760         i2c_set_clientdata(client, private_data);
761         private_data->client = client;
762         private_data->pdata = pdata;
763
764         result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
765                                         kxtf9_get_slave_descr);
766         if (result) {
767                 dev_err(&client->adapter->dev,
768                         "Slave registration failed: %s, %d\n",
769                         devid->name, result);
770                 goto out_free_memory;
771         }
772
773         return result;
774
775 out_free_memory:
776         kfree(private_data);
777 out_no_free:
778         dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
779         return result;
780
781 }
782
783 static int kxtf9_mod_remove(struct i2c_client *client)
784 {
785         struct kxtf9_mod_private_data *private_data =
786                 i2c_get_clientdata(client);
787
788         dev_dbg(&client->adapter->dev, "%s\n", __func__);
789
790         inv_mpu_unregister_slave(client, private_data->pdata,
791                                 kxtf9_get_slave_descr);
792
793         kfree(private_data);
794         return 0;
795 }
796
797 static const struct i2c_device_id kxtf9_mod_id[] = {
798         { "kxtf9", ACCEL_ID_KXTF9 },
799         {}
800 };
801
802 MODULE_DEVICE_TABLE(i2c, kxtf9_mod_id);
803
804 static struct i2c_driver kxtf9_mod_driver = {
805         .class = I2C_CLASS_HWMON,
806         .probe = kxtf9_mod_probe,
807         .remove = kxtf9_mod_remove,
808         .id_table = kxtf9_mod_id,
809         .driver = {
810                    .owner = THIS_MODULE,
811                    .name = "kxtf9_mod",
812                    },
813         .address_list = normal_i2c,
814 };
815
816 static int __init kxtf9_mod_init(void)
817 {
818         int res = i2c_add_driver(&kxtf9_mod_driver);
819         pr_info("%s: Probe name %s\n", __func__, "kxtf9_mod");
820         if (res)
821                 pr_err("%s failed\n", __func__);
822         return res;
823 }
824
825 static void __exit kxtf9_mod_exit(void)
826 {
827         pr_info("%s\n", __func__);
828         i2c_del_driver(&kxtf9_mod_driver);
829 }
830
831 module_init(kxtf9_mod_init);
832 module_exit(kxtf9_mod_exit);
833
834 MODULE_AUTHOR("Invensense Corporation");
835 MODULE_DESCRIPTION("Driver to integrate KXTF9 sensor with the MPU");
836 MODULE_LICENSE("GPL");
837 MODULE_ALIAS("kxtf9_mod");
838
839 /**
840  *  @}
841  */