diff options
Diffstat (limited to 'drivers/input/misc/mpu/inv_mpu3050.c')
-rw-r--r-- | drivers/input/misc/mpu/inv_mpu3050.c | 756 |
1 files changed, 552 insertions, 204 deletions
diff --git a/drivers/input/misc/mpu/inv_mpu3050.c b/drivers/input/misc/mpu/inv_mpu3050.c index 96a6e22d5665..205bf456f974 100644 --- a/drivers/input/misc/mpu/inv_mpu3050.c +++ b/drivers/input/misc/mpu/inv_mpu3050.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Invensense, Inc. +* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -38,77 +39,292 @@ #include <linux/spinlock.h> #include "inv_gyro.h" -int set_3050_bypass(struct inv_gyro_state_s *st, int enable) + +static unsigned long nvi_lpf_us_tbl[] = { + 0, /* N/A */ + 5319, /* 188Hz */ + 10204, /* 98Hz */ + 23810, /* 42Hz */ + 50000, /* 20Hz */ + 100000, /* 10Hz */ + /* 200000, 5Hz */ +}; + + +/** + * inv_clear_kfifo() - clear time stamp fifo + * @st: Device driver instance. + */ +static void inv_clear_kfifo(struct inv_gyro_state_s *st) +{ + unsigned long flags; + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->trigger.timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + +/** + * mpu3050_fifo_reset() - Reset FIFO related registers + * @st: Device driver instance. + */ +static int mpu3050_fifo_reset(struct inv_gyro_state_s *st) { struct inv_reg_map_s *reg; int result; - unsigned char b; + unsigned char val, user_ctrl; reg = st->reg; - result = inv_i2c_read(st, reg->user_ctrl, 1, &b); + /* disable interrupt */ + result = inv_i2c_single_write(st, reg->int_enable, 0); if (result) return result; - if (((b & BIT_3050_AUX_IF_EN) == 0) && enable) - return 0; - if ((b & BIT_3050_AUX_IF_EN) && (enable == 0)) - return 0; - b &= ~BIT_3050_AUX_IF_EN; - if (!enable) { - b |= BIT_3050_AUX_IF_EN; - result = inv_i2c_single_write(st, reg->user_ctrl, b); - return result; + + inv_clear_kfifo(st); + /* disable the sensor output to FIFO */ + result = inv_i2c_single_write(st, reg->fifo_en, 0); + if (result) + goto reset_fifo_fail; + result = inv_i2c_read(st, reg->user_ctrl, 1, &user_ctrl); + if (result) + goto reset_fifo_fail; + /* disable fifo reading */ + user_ctrl &= ~BIT_FIFO_EN; + st->fifo_counter = 0; + /* reset fifo */ + val = (BIT_3050_FIFO_RST | user_ctrl); + result = inv_i2c_single_write(st, reg->user_ctrl, val); + if (result) + goto reset_fifo_fail; + mdelay(POWER_UP_TIME); + st->last_isr_time = get_time_ns(); + if (st->chip_config.dmp_on) { + /* enable interrupt when DMP is done */ + result = inv_i2c_single_write(st, reg->int_enable, + BIT_DMP_INT_EN); + if (result) + return result; + + result = inv_i2c_single_write(st, reg->user_ctrl, + BIT_FIFO_EN|user_ctrl); + if (result) + return result; } else { - /* Coming out of I2C is tricky due to several erratta. Do not - * modify this algorithm - */ - /* - * 1) wait for the right time and send the command to change - * the aux i2c slave address to an invalid address that will - * get nack'ed - * - * 0x00 is broadcast. 0x7F is unlikely to be used by any aux. - */ - result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR, - 0x7F); + /* enable interrupt */ + if (st->chip_config.accl_fifo_enable || + st->chip_config.gyro_fifo_enable){ + result = inv_i2c_single_write(st, reg->int_enable, + BIT_DATA_RDY_EN); + if (result) + return result; + } + /* enable FIFO reading and I2C master interface*/ + result = inv_i2c_single_write(st, reg->user_ctrl, + BIT_FIFO_EN | user_ctrl); if (result) return result; - /* - * 2) wait enough time for a nack to occur, then go into - * bypass mode: - */ - mdelay(2); - result = inv_i2c_single_write(st, reg->user_ctrl, b); + /* enable sensor output to FIFO and FIFO footer*/ + val = 1; + if (st->chip_config.accl_fifo_enable) + val |= BITS_3050_ACCL_OUT; + if (st->chip_config.gyro_fifo_enable) + val |= BITS_GYRO_OUT; + result = inv_i2c_single_write(st, reg->fifo_en, val); if (result) return result; - /* - * 3) wait for up to one MPU cycle then restore the slave - * address - */ - mdelay(20); - result = inv_i2c_single_write(st, REG_3050_SLAVE_REG, - st->plat_data.secondary_read_reg); + } + + return 0; +reset_fifo_fail: + if (st->chip_config.dmp_on) + val = BIT_DMP_INT_EN; + else + val = BIT_DATA_RDY_EN; + inv_i2c_single_write(st, reg->int_enable, val); + pr_err("%s failed\n", __func__); + return result; +} + +/** + * set_power_mpu3050() - set power of mpu3050. + * @st: Device driver instance. + * @power_on: on/off + */ +int set_power_mpu3050(struct inv_gyro_state_s *st, unsigned char power_on) +{ + struct inv_reg_map_s *reg; + unsigned char data, p; + int result; + reg = st->reg; + if (power_on) { + data = 0; + } else { + if (st->mpu_slave) { + result = st->mpu_slave->suspend(st); + if (result) + return result; + } + + data = BIT_SLEEP; + } + if (st->chip_config.gyro_enable) { + p = (BITS_3050_POWER1 | INV_CLK_PLL); + result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p); if (result) return result; - result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR, - st->plat_data.secondary_i2c_addr); + p = (BITS_3050_POWER2 | INV_CLK_PLL); + result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p); if (result) return result; - result = inv_i2c_single_write(st, reg->user_ctrl, - (b | BIT_3050_AUX_IF_RST)); + p = INV_CLK_PLL; + result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p); if (result) return result; - mdelay(2); + st->chip_config.clk_src = INV_CLK_PLL; + } else { + data |= (BITS_3050_GYRO_STANDBY | INV_CLK_INTERNAL); + result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data); + if (result) + return result; + st->chip_config.clk_src = INV_CLK_INTERNAL; } + if (power_on) { + mdelay(POWER_UP_TIME); + if (st->mpu_slave) { + result = st->mpu_slave->resume(st); + if (result) + return result; + } + } + return 0; } /** + * inv_set_power_state() - Turn device on/off. + * @st: Device driver instance. + * @power_on: 1 to turn on, 0 to suspend. + */ +int inv_set_power_state(struct inv_gyro_state_s *st, unsigned char power_on) +{ + return set_power_mpu3050(st, power_on); +} + +/** + * set_inv_enable() - Reset FIFO related registers. + * @st: Device driver instance. + * @fifo_enable: enable/disable + */ +int set_inv_enable(struct inv_gyro_state_s *st, unsigned long enable) +{ + struct inv_reg_map_s *reg; + int result; + + reg = st->reg; + if (enable) { + result = mpu3050_fifo_reset(st); + if (result) + return result; + + st->chip_config.enable = 1; + } else { + result = inv_i2c_single_write(st, reg->fifo_en, 0); + if (result) + return result; + + result = inv_i2c_single_write(st, reg->int_enable, 0); + if (result) + return result; + + st->chip_config.enable = 0; + } + + return 0; +} + +static int mpu3050_global_delay(struct inv_gyro_state_s *inf) +{ + unsigned long delay_us; + unsigned char val; + int rate; + int err = 0; + + /* find the fastest polling of all the devices */ + delay_us = -1; + if (inf->chip_config.gyro_enable && inf->chip_config.gyro_delay_us) { + if (inf->chip_config.gyro_delay_us < delay_us) + delay_us = inf->chip_config.gyro_delay_us; + } + if (inf->chip_config.accl_enable && inf->chip_config.accl_delay_us) { + if (inf->chip_config.accl_delay_us < delay_us) + delay_us = inf->chip_config.accl_delay_us; + } + if (delay_us == -1) + delay_us = NVI_DELAY_DEFAULT; /* default if nothing found */ + if (delay_us < MIN_FIFO_RATE) + delay_us = MIN_FIFO_RATE; + if (delay_us > MAX_FIFO_RATE) + delay_us = MAX_FIFO_RATE; + /* program if new value */ + if (delay_us != inf->sample_delay_us) { + dev_dbg(&inf->i2c->dev, "%s %lu\n", __func__, delay_us); + inf->sample_delay_us = delay_us; + val = delay_us / ONE_K_HZ - 1; + err = inv_i2c_single_write(inf, inf->reg->sample_rate_div, + val); + rate = 1000000 / delay_us; + inf->irq_dur_us = delay_us; + delay_us <<= 1; + for (val = 1; val < ARRAY_SIZE(nvi_lpf_us_tbl); val++) { + if (delay_us < nvi_lpf_us_tbl[val]) + break; + } + if (inf->mpu_slave != NULL) + err |= inf->mpu_slave->set_lpf(inf, rate); + err |= inv_i2c_single_write(inf, inf->reg->lpf, val | + (inf->chip_config.gyro_fsr << 3)); + inf->last_isr_time = get_time_ns(); + } + return err; +} + +static int mpu3050_gyro_enable(struct inv_gyro_state_s *inf, + unsigned char enable, unsigned char fifo_enable) +{ + unsigned char enable_old; + unsigned char fifo_enable_old; + unsigned char val; + int err = 0; + + enable_old = inf->chip_config.gyro_enable; + fifo_enable_old = inf->chip_config.gyro_fifo_enable; + inf->chip_config.gyro_fifo_enable = fifo_enable; + inf->chip_config.gyro_enable = enable; + set_power_mpu3050(inf, 1); + if (enable != enable_old) { + if (enable) { + val = (inf->chip_config.gyro_fsr << 3); + val |= inf->chip_config.lpf; + err = inv_i2c_single_write(inf, inf->reg->lpf, val); + } + mpu3050_global_delay(inf); + } + if (fifo_enable_old != fifo_enable) + mpu3050_fifo_reset(inf); + if (err) { + inf->chip_config.gyro_enable = enable_old; + inf->chip_config.gyro_fifo_enable = fifo_enable_old; + } + set_power_mpu3050(inf, 1); + return err; +} + +/** * inv_raw_accl_show() - Read accel data directly from registers. */ -static ssize_t inv_raw_accl_mpu3050_show(struct device *dev, +static ssize_t mpu3050_raw_accl_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char data[6]; @@ -132,14 +348,12 @@ static ssize_t inv_raw_accl_mpu3050_show(struct device *dev, /** * inv_accl_fifo_enable_store() - Enable/disable accl fifo output. */ -static ssize_t inv_accl_fifo_mpu3050_enable_store(struct device *dev, +static ssize_t mpu3050_accl_fifo_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long en; struct inv_gyro_state_s *st; st = dev_get_drvdata(dev); - if (st->chip_config.is_asleep) - return -EINVAL; if (kstrtoul(buf, 10, &en)) return -EINVAL; if (en == !(!(st->chip_config.accl_fifo_enable))) @@ -147,22 +361,19 @@ static ssize_t inv_accl_fifo_mpu3050_enable_store(struct device *dev, st->chip_config.accl_fifo_enable = en; if (en && (0 == st->chip_config.accl_enable)) { st->chip_config.accl_enable = en; - if (st->mpu_slave != NULL) - st->mpu_slave->resume(st); + set_power_mpu3050(st, 1); } return count; } /** - * inv_accl_mpu3050_enable_store() - Enable/disable accl. + * mpu3050_accl_enable_store() - Enable/disable accl. */ -static ssize_t inv_accl_mpu3050_enable_store(struct device *dev, +static ssize_t mpu3050_accl_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long en; struct inv_gyro_state_s *st; st = dev_get_drvdata(dev); - if (st->chip_config.is_asleep) - return -EINVAL; if (kstrtoul(buf, 10, &en)) return -EINVAL; if (en == !(!(st->chip_config.accl_enable))) @@ -172,36 +383,245 @@ static ssize_t inv_accl_mpu3050_enable_store(struct device *dev, st->chip_config.accl_fifo_enable = 0; if (st->mpu_slave != NULL) { if (en) - st->mpu_slave->resume(st); + set_power_mpu3050(st, 1); + else + set_power_mpu3050(st, 0); + } + return count; +} + +static ssize_t mpu3050_accl_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct inv_gyro_state_s *inf; + unsigned long accl_delay_us; + unsigned long accl_delay_us_old; + int err; + + inf = dev_get_drvdata(dev); + err = kstrtoul(buf, 10, &accl_delay_us); + if (err) + return err; + + mutex_lock(&inf->mutex); + dev_dbg(&inf->i2c->dev, "%s: %lu\n", __func__, accl_delay_us); + if (accl_delay_us < NVI_INPUT_ACCL_DELAY_US_MIN) + accl_delay_us = NVI_INPUT_ACCL_DELAY_US_MIN; + if (accl_delay_us != inf->chip_config.accl_delay_us) { + accl_delay_us_old = inf->chip_config.accl_delay_us; + inf->chip_config.accl_delay_us = accl_delay_us; + if (inf->chip_config.accl_enable) { + err = mpu3050_global_delay(inf); + if (!err) + inf->chip_config.accl_delay_us = + accl_delay_us_old; + } + } + mutex_unlock(&inf->mutex); + if (err) { + dev_err(&inf->i2c->dev, "%s: %lu ERR=%d\n", + __func__, accl_delay_us, err); + return err; + } + + return count; +} + +static ssize_t mpu3050_accl_max_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct inv_gyro_state_s *inf; + unsigned char fsr; + int err; + + inf = dev_get_drvdata(dev); + err = kstrtou8(buf, 10, &fsr); + if (err) + return -EINVAL; + + if (fsr > 3) + return -EINVAL; + + mutex_lock(&inf->mutex); + dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fsr); + if (fsr != inf->chip_config.accl_fsr) { + inf->chip_config.accl_fsr = fsr; + if (inf->chip_config.accl_enable) { + if ((inf->chip_type == INV_MPU3050) && + (inf->mpu_slave != NULL)) { + err = inf->mpu_slave->set_fs(inf, fsr); + /* reset fifo to purge old data */ + mpu3050_fifo_reset(inf); + } + } + } + mutex_unlock(&inf->mutex); + if (err < 0) { + dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", __func__, fsr, err); + return err; + } + + return count; +} + +static ssize_t mpu3050_gyro_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct inv_gyro_state_s *inf; + unsigned char enable; + unsigned char fifo_enable; + int err; + + inf = dev_get_drvdata(dev); + err = kstrtou8(buf, 10, &enable); + if (err) + return -EINVAL; + + if (enable > 7) + return -EINVAL; + + mutex_lock(&inf->mutex); + dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, enable); + if (enable != inf->chip_config.gyro_enable) { + if (enable) + fifo_enable = inf->chip_config.gyro_fifo_enable; else - st->mpu_slave->suspend(st); + fifo_enable = 0; + err = mpu3050_gyro_enable(inf, enable, fifo_enable); + } + mutex_unlock(&inf->mutex); + if (err) { + dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", + __func__, enable, err); + return err; } + return count; } +static ssize_t mpu3050_gyro_fifo_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct inv_gyro_state_s *inf; + unsigned char fifo_enable; + unsigned char enable; + int err; + + inf = dev_get_drvdata(dev); + err = kstrtou8(buf, 10, &fifo_enable); + if (err) + return -EINVAL; + + mutex_lock(&inf->mutex); + dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fifo_enable); + enable = inf->chip_config.gyro_enable; + if (fifo_enable) { + fifo_enable = 1; + if (!enable) + enable = 7; + } + if (fifo_enable != inf->chip_config.gyro_fifo_enable) + err = mpu3050_gyro_enable(inf, enable, fifo_enable); + mutex_unlock(&inf->mutex); + if (err) { + dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", + __func__, fifo_enable, err); + return err; + } + + return count; +} + +static ssize_t mpu3050_gyro_max_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct inv_gyro_state_s *inf; + unsigned char fsr; + int err; + + inf = dev_get_drvdata(dev); + err = kstrtou8(buf, 10, &fsr); + if (err) + return -EINVAL; + + if (fsr > 3) + return -EINVAL; + + mutex_lock(&inf->mutex); + dev_dbg(&inf->i2c->dev, "%s: %x\n", __func__, fsr); + if (fsr != inf->chip_config.gyro_fsr) { + inf->chip_config.gyro_fsr = fsr; + if (inf->chip_config.gyro_enable) { + fsr = (fsr << 3) | inf->chip_config.lpf; + err = inv_i2c_single_write(inf, inf->reg->lpf, fsr); + mpu3050_fifo_reset(inf); + } + } + mutex_unlock(&inf->mutex); + if (err < 0) { + dev_err(&inf->i2c->dev, "%s: %x ERR=%d\n", __func__, fsr, err); + return err; + } + + return count; +} + +static ssize_t mpu3050_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct inv_gyro_state_s *inf; + unsigned char enable; + int err; + + inf = dev_get_drvdata(dev); + err = kstrtou8(buf, 10, &enable); + if (err) + return -EINVAL; + + if (enable) + enable = 1; + inf->chip_config.enable = enable; + return count; +} + +static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR, + nvi_gyro_enable_show, mpu3050_gyro_enable_store); static DEVICE_ATTR(gyro_fifo_enable, S_IRUGO | S_IWUSR, - inv_gyro_fifo_enable_show, - inv_gyro_fifo_enable_store); -static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR, inv_gyro_enable_show, - inv_gyro_enable_store); -static DEVICE_ATTR(raw_accl, S_IRUGO, inv_raw_accl_mpu3050_show, NULL); + nvi_gyro_fifo_enable_show, mpu3050_gyro_fifo_enable_store); +static DEVICE_ATTR(gyro_max_range, S_IRUGO | S_IWUSR | S_IWOTH, + nvi_gyro_max_range_show, mpu3050_gyro_max_range_store); +static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR, + nvi_accl_enable_show, mpu3050_accl_enable_store); static DEVICE_ATTR(accl_fifo_enable, S_IRUGO | S_IWUSR, - inv_accl_fifo_enable_show, - inv_accl_fifo_mpu3050_enable_store); -static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR, inv_accl_enable_show, - inv_accl_mpu3050_enable_store); -static DEVICE_ATTR(accl_matrix, S_IRUGO, inv_accl_matrix_show, NULL); -static DEVICE_ATTR(accl_fs, S_IRUGO | S_IWUSR, inv_accl_fs_show, - inv_accl_fs_store); + nvi_accl_fifo_enable_show, mpu3050_accl_fifo_enable_store); +static DEVICE_ATTR(accl_delay, S_IRUGO | S_IWUSR | S_IWOTH, + nvi_accl_delay_show, mpu3050_accl_delay_store); +static DEVICE_ATTR(accl_max_range, S_IRUGO | S_IWUSR, + nvi_accl_max_range_show, mpu3050_accl_max_range_store); +static DEVICE_ATTR(accl_orientation, S_IRUGO, + inv_accl_matrix_show, NULL); +static DEVICE_ATTR(raw_accl, S_IRUGO, + mpu3050_raw_accl_show, NULL); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWOTH, + nvi_enable_show, mpu3050_enable_store); static struct device_attribute *inv_mpu3050_attributes[] = { - &dev_attr_gyro_fifo_enable, &dev_attr_gyro_enable, - &dev_attr_accl_fifo_enable, + &dev_attr_gyro_fifo_enable, + &dev_attr_gyro_max_range, &dev_attr_accl_enable, + &dev_attr_accl_fifo_enable, + &dev_attr_accl_delay, + &dev_attr_accl_max_range, + &dev_attr_accl_orientation, &dev_attr_raw_accl, - &dev_attr_accl_matrix, - &dev_attr_accl_fs, + &dev_attr_enable, NULL }; @@ -219,8 +639,8 @@ int inv_mpu3050_remove_sysfs(struct inv_gyro_state_s *st) return 0; } -static void inv_report_data_3050(struct inv_gyro_state_s *st, s64 t, - int counter, unsigned char *data) +static void mpu3050_report(struct inv_gyro_state_s *st, s64 t, + int counter, unsigned char *data) { short x = 0, y = 0, z = 0; int ind; @@ -278,6 +698,7 @@ static void inv_report_data_3050(struct inv_gyro_state_s *st, s64 t, input_sync(st->idev); } } + /** * inv_read_fifo() - Transfer data from FIFO to ring buffer. */ @@ -296,15 +717,19 @@ irqreturn_t inv_read_fifo_mpu3050(int irq, void *dev_id) st = (struct inv_gyro_state_s *)dev_id; reg = st->reg; - if (st->chip_config.is_asleep) - goto end_session; - if (!(st->chip_config.enable)) - goto end_session; if (!(st->chip_config.accl_fifo_enable | st->chip_config.gyro_fifo_enable | - st->chip_config.dmp_on | - st->chip_config.compass_enable)) + st->chip_config.dmp_on)) goto end_session; + + result = inv_i2c_read(st, reg->temperature, 2, data); + if (!result) { + mutex_lock(&st->mutex_temp); + st->temp_val = (data[0] << 8) | data[1]; + st->temp_ts = timestamp; + mutex_unlock(&st->mutex_temp); + } + if (st->chip_config.dmp_on) bytes_per_datum = BYTES_FOR_DMP; else @@ -353,7 +778,7 @@ irqreturn_t inv_read_fifo_mpu3050(int irq, void *dev_id) ×tamp, sizeof(timestamp), &copied); if (result) goto flush_fifo; - inv_report_data_3050(st, timestamp, st->fifo_counter, data); + mpu3050_report(st, timestamp, st->fifo_counter, data); fifo_count -= byte_read; if (st->fifo_counter == 0) { st->fifo_counter = 1; @@ -364,8 +789,7 @@ end_session: return IRQ_HANDLED; flush_fifo: /* Flush HW and SW FIFOs. */ - inv_reset_fifo(st); - inv_clear_kfifo(st); + mpu3050_fifo_reset(st); return IRQ_HANDLED; } void inv_setup_reg_mpu3050(struct inv_reg_map_s *reg) @@ -399,9 +823,6 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st) int result; unsigned char data; - if (st->chip_config.is_asleep) - return -EPERM; - /*reading AUX VDDIO register */ result = inv_i2c_read(st, REG_3050_AUX_VDDIO, 1, &data); if (result) @@ -421,7 +842,7 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st) | INV_FILTER_42HZ); if (result) return result; - st->chip_config.fsr = INV_FSR_2000DPS; + st->chip_config.gyro_fsr = INV_FSR_2000DPS; st->chip_config.lpf = INV_FILTER_42HZ; result = inv_i2c_single_write(st, reg->sample_rate_div, 19); if (result) @@ -430,9 +851,6 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st) st->irq_dur_us = 20*1000; st->chip_config.enable = 0; st->chip_config.dmp_on = 0; - st->compass_divider = 0; - st->compass_counter = 0; - st->chip_config.compass_enable = 0; st->chip_config.firmware_loaded = 0; st->chip_config.prog_start_addr = DMP_START_ADDR; st->chip_config.gyro_enable = 1; @@ -460,142 +878,72 @@ int inv_init_config_mpu3050(struct inv_gyro_state_s *st) } return 0; } -/** - * set_power_mpu3050() - set power of mpu3050. - * @st: Device driver instance. - * @power_on: on/off - */ -int set_power_mpu3050(struct inv_gyro_state_s *st, - unsigned char power_on) + +int set_3050_bypass(struct inv_gyro_state_s *st, int enable) { struct inv_reg_map_s *reg; - unsigned char data, p; int result; + unsigned char b; + reg = st->reg; - if (power_on) { - data = 0; + result = inv_i2c_read(st, reg->user_ctrl, 1, &b); + if (result) + return result; + if (((b & BIT_3050_AUX_IF_EN) == 0) && enable) + return 0; + if ((b & BIT_3050_AUX_IF_EN) && (enable == 0)) + return 0; + b &= ~BIT_3050_AUX_IF_EN; + if (!enable) { + b |= BIT_3050_AUX_IF_EN; + result = inv_i2c_single_write(st, reg->user_ctrl, b); + return result; } else { - if (st->mpu_slave) { - result = st->mpu_slave->suspend(st); - if (result) - return result; - } - - data = BIT_SLEEP; - } - if (st->chip_config.gyro_enable) { - p = (BITS_3050_POWER1 | INV_CLK_PLL); - result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p); - if (result) - return result; - - p = (BITS_3050_POWER2 | INV_CLK_PLL); - result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p); + /* Coming out of I2C is tricky due to several erratta. Do not + * modify this algorithm + */ + /* + * 1) wait for the right time and send the command to change + * the aux i2c slave address to an invalid address that will + * get nack'ed + * + * 0x00 is broadcast. 0x7F is unlikely to be used by any aux. + */ + result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR, + 0x7F); if (result) return result; - - p = INV_CLK_PLL; - result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data | p); + /* + * 2) wait enough time for a nack to occur, then go into + * bypass mode: + */ + mdelay(2); + result = inv_i2c_single_write(st, reg->user_ctrl, b); if (result) return result; - - st->chip_config.clk_src = INV_CLK_PLL; - } else { - data |= (BITS_3050_GYRO_STANDBY | INV_CLK_INTERNAL); - result = inv_i2c_single_write(st, reg->pwr_mgmt_1, data); + /* + * 3) wait for up to one MPU cycle then restore the slave + * address + */ + mdelay(20); + result = inv_i2c_single_write(st, REG_3050_SLAVE_REG, + st->plat_data.secondary_read_reg); if (result) return result; - st->chip_config.clk_src = INV_CLK_INTERNAL; - } - if (power_on) { - mdelay(POWER_UP_TIME); - if (st->mpu_slave) { - result = st->mpu_slave->resume(st); - if (result) - return result; - } - st->chip_config.is_asleep = 0; - } else - st->chip_config.is_asleep = 1; - return 0; -} -/** - * reset_fifo_mpu3050() - Reset FIFO related registers - * @st: Device driver instance. - */ -int reset_fifo_mpu3050(struct inv_gyro_state_s *st) -{ - struct inv_reg_map_s *reg; - int result; - unsigned char val, user_ctrl; - reg = st->reg; - /* disable interrupt */ - result = inv_i2c_single_write(st, reg->int_enable, 0); - if (result) - return result; - /* disable the sensor output to FIFO */ - result = inv_i2c_single_write(st, reg->fifo_en, 0); - if (result) - goto reset_fifo_fail; - result = inv_i2c_read(st, reg->user_ctrl, 1, &user_ctrl); - if (result) - goto reset_fifo_fail; - /* disable fifo reading */ - user_ctrl &= ~BIT_FIFO_EN; - st->fifo_counter = 0; - /* reset fifo */ - val = (BIT_3050_FIFO_RST | user_ctrl); - result = inv_i2c_single_write(st, reg->user_ctrl, val); - if (result) - goto reset_fifo_fail; - mdelay(POWER_UP_TIME); - st->last_isr_time = get_time_ns(); - if (st->chip_config.dmp_on) { - /* enable interrupt when DMP is done */ - result = inv_i2c_single_write(st, reg->int_enable, - BIT_DMP_INT_EN); + result = inv_i2c_single_write(st, REG_3050_SLAVE_ADDR, + st->plat_data.secondary_i2c_addr); if (result) return result; result = inv_i2c_single_write(st, reg->user_ctrl, - BIT_FIFO_EN|user_ctrl); - if (result) - return result; - } else { - /* enable interrupt */ - if (st->chip_config.accl_fifo_enable || - st->chip_config.gyro_fifo_enable){ - result = inv_i2c_single_write(st, reg->int_enable, - BIT_DATA_RDY_EN); - if (result) - return result; - } - /* enable FIFO reading and I2C master interface*/ - result = inv_i2c_single_write(st, reg->user_ctrl, - BIT_FIFO_EN | user_ctrl); - if (result) - return result; - /* enable sensor output to FIFO and FIFO footer*/ - val = 1; - if (st->chip_config.accl_fifo_enable) - val |= BITS_3050_ACCL_OUT; - if (st->chip_config.gyro_fifo_enable) - val |= BITS_GYRO_OUT; - result = inv_i2c_single_write(st, reg->fifo_en, val); + (b | BIT_3050_AUX_IF_RST)); if (result) return result; - } + mdelay(2); + } return 0; -reset_fifo_fail: - if (st->chip_config.dmp_on) - val = BIT_DMP_INT_EN; - else - val = BIT_DATA_RDY_EN; - inv_i2c_single_write(st, reg->int_enable, val); - pr_err("%s failed\n", __func__); - return result; } /** * @} |