diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
| commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
| tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/mpu3050/accel | |
| parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) | |
Diffstat (limited to 'drivers/misc/mpu3050/accel')
| -rw-r--r-- | drivers/misc/mpu3050/accel/kxtf9.c | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c new file mode 100644 index 00000000000..938cd572a8f --- /dev/null +++ b/drivers/misc/mpu3050/accel/kxtf9.c | |||
| @@ -0,0 +1,669 @@ | |||
| 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, ®); | ||
| 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 | **/ | ||
