Re: inv_mpu_core.c for invensense mpu6050/mpu9150

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 05/15/2012 06:52 PM, Ge Gao wrote:
> Dear all,
> 	I'd like to submit the invensense mpu6050/mpu9150 driver, a
> reduced version of driver code yet still pretty big. This is the first
> file and biggest file.
> 	Welcome any comments.
> 	Thanks.
> 
> Best regards,
> 
> Ge GAO
Please do the patches with git-format patch and a cover letter.  Makes
things easier to apply and more predicitable for those who do lots
of kernel reviewing.

Obviously you got this out before I replied with which tree to use.
Staging-next has headers in different places.

Also, a patch must stand on it's own.  Hence here we need the headers
that are referenced as well.

Some comments inline to get you started.
> 
> +++ inv_mpu_core.c	2012-05-15 10:33:36.752543619 -0700
> @@ -0,0 +1,2211 @@
> +/*
> +* Copyright (C) 2012 Invensense, Inc.
> +*
> +* This software is licensed under the terms of the GNU General Public
> +* License version 2, as published by the Free Software Foundation, and
> +* may be copied, distributed, and modified under those terms.
> +*
> +* This program is distributed in the hope that it will be useful,
> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +* GNU General Public License for more details.
> +*
> +*/
> +
Loose the non kernel-doc docs...
> +/**
> + *  @addtogroup  DRIVERS
> + *  @brief       Hardware drivers.
> + *
> + *  @{
> + *      @file    inv_gyro.c
> + *      @brief   A sysfs device driver for Invensense devices
> + *      @details This driver currently works for the MPU6050, MPU9150
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/sysfs.h>
> +#include <linux/jiffies.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/kfifo.h>
> +#include <linux/poll.h>
> +#include <linux/miscdevice.h>
> +#include <linux/spinlock.h>
> +#include "inv_mpu_iio.h"
> +#include "../../sysfs.h"
> +static void inv_setup_reg(struct inv_reg_map_s *reg)
> +{
Copy from a static array rather than explicit setup like this.
> +	reg->who_am_i		= 0x75;
> +	reg->sample_rate_div	= 0x19;
> +	reg->lpf		= 0x1A;
> +	reg->product_id		= 0x0C;
> +	reg->bank_sel		= 0x6D;
> +	reg->user_ctrl		= 0x6A;
> +	reg->fifo_en		= 0x23;
> +	reg->gyro_config	= 0x1B;
> +	reg->accl_config	= 0x1C;
> +	reg->fifo_count_h	= 0x72;
> +	reg->fifo_r_w		= 0x74;
> +	reg->raw_gyro		= 0x43;
> +	reg->raw_accl		= 0x3B;
> +	reg->temperature	= 0x41;
> +	reg->int_enable		= 0x38;
> +	reg->int_status		= 0x3A;
> +	reg->pwr_mgmt_1		= 0x6B;
> +	reg->pwr_mgmt_2		= 0x6C;
> +	reg->mem_start_addr	= 0x6E;
> +	reg->mem_r_w		= 0x6F;
> +	reg->prgm_strt_addrh	= 0x70;
> +};
> +static const struct inv_hw_s hw_info[INV_NUM_PARTS] = {
> +	{117, "MPU6050"},
> +	{118, "MPU9150"}
> +};
> +/**
> + *  inv_i2c_read() - Read one or more bytes from the device registers.
> + *  @st:	Device driver instance.
> + *  @reg:	First device register to be read from.
> + *  @length:	Number of bytes to read.
> + *  @data:	Data read from device.
> + *  NOTE: The slave register will not increment when reading from the
> FIFO.
> + */
> +int inv_i2c_read_base(struct inv_gyro_state_s *st, unsigned short
> i2c_addr,
> +	unsigned char reg, unsigned short length, unsigned char *data)
> +{
> +	struct i2c_msg msgs[2];
use c99 assignment.

struct i2c_msg msgs[2] = {
{
	.addr = i2c_addr,
	.buf = &reg,
	.len = 1,
}, {
	.addr = i2c_addr,
	.flags = I2_M_RD,
	.buf = data,
	.len = length
};
hmm.. looks rather like an i2c_smbus_read_i2c_block call?

> +	int res;
> +
That's a code bug if this happens. Don't bother checking for it
(or check outside here if it ever makes sense...)
> +	if (!data)
> +		return -EINVAL;
> +
> +	msgs[0].addr = i2c_addr;
> +	msgs[0].flags = 0;	/* write */
> +	msgs[0].buf = &reg;
> +	msgs[0].len = 1;
> +
> +	msgs[1].addr = i2c_addr;
> +	msgs[1].flags = I2C_M_RD;
> +	msgs[1].buf = data;
> +	msgs[1].len = length;
> +
> +	res = i2c_transfer(st->sl_handle, msgs, 2);
> +	if (res < 2) {
> +		if (res >= 0)
> +			res = -EIO;
> +		return res;
> +	} else
> +		return 0;
> +}
> +
> +/**
> + *  inv_i2c_single_write() - Write a byte to a device register.
> + *  @st:	Device driver instance.
> + *  @reg:	Device register to be written to.
> + *  @data:	Byte to write to device.
> + */
> +int inv_i2c_single_write_base(struct inv_gyro_state_s *st,
> +	unsigned short i2c_addr, unsigned char reg, unsigned char data)
> +{
> +	unsigned char tmp[2];
> +	struct i2c_msg msg;
> +	int res;
> +
again, is this a standard i2c call reimplemented?
looks like an i2c_smbus_write_byte_data
> +	tmp[0] = reg;
> +	tmp[1] = data;
> +
> +	msg.addr = i2c_addr;
> +	msg.flags = 0;	/* write */
> +	msg.buf = tmp;
> +	msg.len = 2;
> +
> +	/*printk(KERN_ERR "WS%02X%02X%02X\n", i2c_addr, reg, data);*/
> +	res = i2c_transfer(st->sl_handle, &msg, 1);
> +	if (res < 1) {
> +		if (res == 0)
> +			res = -EIO;
> +		return res;
> +	} else
> +		return 0;
> +}
> +int inv_set_power_state(struct inv_gyro_state_s *st,
> +	unsigned char power_on)
> +{
> +	struct inv_reg_map_s *reg;
> +	unsigned char data;
> +	int result;
> +
> +	reg = &st->reg;
> +	if (power_on)
> +		data = 0;
> +	else
> +		data = BIT_SLEEP;
> +	if (st->chip_config.lpa_mode)
> +		data |= BIT_CYCLE;
> +	if (st->chip_config.gyro_enable) {
> +		result = inv_i2c_single_write(st,
> +			reg->pwr_mgmt_1, data | INV_CLK_PLL);
> +		if (result)
> +			return result;
> +		st->chip_config.clk_src = INV_CLK_PLL;
> +	} else {
> +		result = inv_i2c_single_write(st,
> +			reg->pwr_mgmt_1, data | INV_CLK_INTERNAL);
> +		if (result)
> +			return result;
> +		st->chip_config.clk_src = INV_CLK_INTERNAL;
> +	}
> +
> +	if (power_on) {
> +		msleep(POWER_UP_TIME);
> +		data = 0;
if(!chip->config.accl_enable) is clearer.
> +		if (0 == st->chip_config.accl_enable)
> +			data |= BIT_PWR_ACCL_STBY;
> +		if (0 == st->chip_config.gyro_enable)
> +			data |= BIT_PWR_GYRO_STBY;
> +		data |= (st->chip_config.lpa_freq << LPA_FREQ_SHIFT);
> +
> +		result = inv_i2c_single_write(st, reg->pwr_mgmt_2, data);
> +		if (result)
> +			return result;
> +		msleep(POWER_UP_TIME);
drop last line out of if statement and have
st->chip_config.is_asleep = !power_on;
> +		st->chip_config.is_asleep = 0;
> +	} else
> +		st->chip_config.is_asleep = 1;
blank line before return at end of function.
> +	return 0;
> +}
> +
> +/**
> + *  inv_init_config() - Initialize hardware, disable FIFO.
> + *  @indio_dev:	Device driver instance.
> + *  Initial configuration:
> + *  FSR: +/- 2000DPS
> + *  DLPF: 42Hz
> + *  FIFO rate: 50Hz
> + *  Clock source: Gyro PLL
> + */
> +static int inv_init_config(struct iio_dev *indio_dev)
> +{
> +	struct inv_reg_map_s *reg;
> +	int result;
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	reg = &st->reg;
> +	result = set_inv_enable(indio_dev, 0);
> +	if (result)
> +		return result;
> +
> +	result = inv_i2c_single_write(st, reg->gyro_config,
> +		INV_FSR_2000DPS << GYRO_CONFIG_FSR_SHIFT);
> +	if (result)
> +		return result;
> +	st->chip_config.fsr = INV_FSR_2000DPS;
> +
> +	result = inv_i2c_single_write(st, reg->lpf, INV_FILTER_42HZ);
> +	if (result)
> +		return result;
> +	st->chip_config.lpf = INV_FILTER_42HZ;
> +
> +	result = inv_i2c_single_write(st, reg->sample_rate_div,
> +					ONE_K_HZ/INIT_FIFO_RATE - 1);
> +	if (result)
> +		return result;
> +	st->chip_config.fifo_rate = INIT_FIFO_RATE;
> +	st->irq_dur_us            = INIT_DUR_TIME;
st is kzalloced so don't bother setting 0s

I'd do this with a memcpy of const static copy of chip_config
that has the defaults for start up. Much easier to read.

> +	st->chip_config.enable = 0;
> +	st->chip_config.dmp_on = 0;
> +	st->compass_divider = 0;
> +	st->compass_counter = 0;
> +	st->self_test_run_once = 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;
> +	st->chip_config.gyro_fifo_enable = 1;
> +	st->chip_config.accl_enable = 1;
> +	st->chip_config.accl_fifo_enable = 1;
> +	st->chip_config.accl_fs = INV_FS_02G;
> +	result = inv_i2c_single_write(st, reg->accl_config,
> +		(INV_FS_02G << ACCL_CONFIG_FSR_SHIFT));
> +	if (result)
> +		return result;
> +	st->tap.on = 0;
> +	st->tap.time = INIT_TAP_TIME;
> +	st->tap.thresh = INIT_TAP_THRESHOLD;
> +	st->tap.min_count = INIT_TAP_MIN_COUNT;
> +	return 0;
> +}
> +/**
> + *  inv_compass_scale_show() - show compass scale.
If doing kernel-doc you need to document all the parameters.
> + */
> +static int inv_compass_scale_show(struct inv_gyro_state_s *st, int
> *scale)
> +{
This doesn't look like it will generalize well. If these are inherent
to the devices, then it should be in the driver for them and
merely queried here.  Actually I'm not sure these should be
inherently part of this device driver at all.  Obviously if you
are doing magic stuff to the values in your device fair enough,
but this looks like a direct read.

> +	if (COMPASS_ID_AK8975 == st->plat_data.sec_slave_id)
> +		*scale = DATA_AKM8975_SCALE;
> +	else if (COMPASS_ID_AK8972 == st->plat_data.sec_slave_id)
> +		*scale = DATA_AKM8972_SCALE;
> +	else if (COMPASS_ID_AK8963 == st->plat_data.sec_slave_id)
> +		if (st->compass_scale)
> +			*scale = DATA_AKM8963_SCALE1;
> +		else
> +			*scale = DATA_AKM8963_SCALE0;
> +	else
> +		return -EINVAL;
> +	*scale *= (1L << 15);
> +	return IIO_VAL_INT;
> +}
> +
> +/**
> + *  mpu_read_raw() - read raw method.
> + */
> +static int mpu_read_raw(struct iio_dev *indio_dev,
> +			      struct iio_chan_spec const *chan,
> +			      int *val,
> +			      int *val2,
> +			      long mask) {
> +	struct inv_gyro_state_s  *st = iio_priv(indio_dev);
> +	int result;
> +	if (st->chip_config.is_asleep)
> +		return -EINVAL;
> +	switch (mask) {
> +	case 0:
> +		if (chan->type == IIO_ANGL_VEL) {
> +			*val = st->raw_gyro[chan->channel2 - IIO_MOD_X];
> +			return IIO_VAL_INT;
> +		}
> +		if (chan->type == IIO_ACCEL) {
> +			*val = st->raw_accel[chan->channel2 - IIO_MOD_X];
> +			return IIO_VAL_INT;
> +		}
> +		if (chan->type == IIO_MAGN) {
> +			*val = st->raw_compass[chan->channel2 -
> IIO_MOD_X];
> +			return IIO_VAL_INT;
> +		}
> +		return -EINVAL;
> +	case IIO_CHAN_INFO_SCALE:
> +		if (chan->type == IIO_ANGL_VEL) {
> +			*val = (1 << st->chip_config.fsr)*GYRO_DPS_SCALE;
> +			return IIO_VAL_INT;
> +		}
> +		if (chan->type == IIO_ACCEL) {
> +			*val = (2 << st->chip_config.accl_fs);
> +			return IIO_VAL_INT;
> +		}
> +		if (chan->type == IIO_MAGN)
> +			return inv_compass_scale_show(st, val);
> +		return -EINVAL;
> +	case IIO_CHAN_INFO_CALIBBIAS:
> +		if (st->self_test_run_once == 0) {
> +			result = inv_do_test(st, 0,  st->gyro_bias,
> +				st->accel_bias);
> +			if (result)
> +				return result;
> +			st->self_test_run_once = 1;
> +		}
> +
> +		if (chan->type == IIO_ANGL_VEL) {
> +			*val = st->gyro_bias[chan->channel2 - IIO_MOD_X];
> +			return IIO_VAL_INT;
> +		}
> +		if (chan->type == IIO_ACCEL) {
> +			*val = st->accel_bias[chan->channel2 - IIO_MOD_X];
> +			return IIO_VAL_INT;
> +		}
impossible condition I think, so pul lthe return IIO_VAL_INT out of
the above if statements and have a switch on chan->type that
sets *val
> +		return -EINVAL;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +/**
> + *  inv_write_fsr() - Configure the gyro's scale range.
> + */
fsr is a somewhat overloaded tla so probably worth just calling
it range.
> +static int inv_write_fsr(struct inv_gyro_state_s *st, int fsr)
> +{
> +	struct inv_reg_map_s *reg;
> +	int result;
> +	reg = &st->reg;
> +	if ((fsr < 0) || (fsr > MAX_GYRO_FS_PARAM))
> +		return -EINVAL;
> +	if (fsr == st->chip_config.fsr)
> +		return 0;
Surely an error if this happens...
> +
> +	result = inv_i2c_single_write(st, reg->gyro_config,
> +		fsr << GYRO_CONFIG_FSR_SHIFT);
> +	if (result)
> +		return result;
> +	st->chip_config.fsr = fsr;
> +	return 0;
> +}
> +
> +/**
> + *  inv_write_accel_fs() - Configure the accelerometer's scale range.
> + */
accel_fs uses gyro_state?  That's rather missnamed if so..
> +static int inv_write_accel_fs(struct inv_gyro_state_s *st, int fs)
> +{
> +	int result;
> +	struct inv_reg_map_s *reg;
> +	reg = &st->reg;
> +
> +	if (fs < 0 || fs > MAX_ACCL_FS_PARAM)
> +		return -EINVAL;
> +	if (fs == st->chip_config.accl_fs)
> +		return 0;
> +	result = inv_i2c_single_write(st, reg->accl_config,
> +			(fs << ACCL_CONFIG_FSR_SHIFT));
> +	if (result)
> +		return result;
> +	/* reset fifo because the data could be mixed with old bad data */
> +	st->chip_config.accl_fs = fs;
> +	return 0;
> +}
> +/**
> + *  inv_write_compass_scale() - Configure the compass's scale range.
> + */
> +static int inv_write_compass_scale(struct inv_gyro_state_s  *st, int
> data)
> +{
> +	char d, en;
> +	int result;
> +	if (COMPASS_ID_AK8963 != st->plat_data.sec_slave_id)
> +		return 0;
en = !!data;
> +	if (data)
> +		en = 1;
> +	else
> +		en = 0;
> +	if (st->compass_scale == en)
> +		return 0;
> +	d = (1 | (st->compass_scale << AKM8963_SCALE_SHIFT));
> +	result = inv_i2c_single_write(st, REG_I2C_SLV1_DO, d);
> +	if (result)
> +		return result;
> +	st->compass_scale = en;
> +	return 0;
> +
> +}
> +
> +/**
> + *  mpu_write_raw() - write raw method.
> + */
> +static int mpu_write_raw(struct iio_dev *indio_dev,
> +			       struct iio_chan_spec const *chan,
> +			       int val,
> +			       int val2,
> +			       long mask) {
> +	struct inv_gyro_state_s  *st = iio_priv(indio_dev);
> +	int result;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SCALE:
> +		result = -EINVAL;
switch. Only one can be true.
> +		if (chan->type == IIO_ANGL_VEL)
> +			result = inv_write_fsr(st, val);
> +		if (chan->type == IIO_ACCEL)
> +			result = inv_write_accel_fs(st, val);
> +		if (chan->type == IIO_MAGN)
> +			result = inv_write_compass_scale(st, val);
> +		return result;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +/**
> + *  inv_set_lpf() - set low pass filer based on fifo rate.
> + */
> +static int inv_set_lpf(struct inv_gyro_state_s *st, int rate)
> +{
> +	const short hz[] = {188, 98, 42, 20, 10, 5};
> +	const int   d[] = {INV_FILTER_188HZ, INV_FILTER_98HZ,
> +			INV_FILTER_42HZ, INV_FILTER_20HZ,
> +			INV_FILTER_10HZ, INV_FILTER_5HZ};
> +	int i, h, data, result;
> +	struct inv_reg_map_s *reg;
> +	reg = &st->reg;
> +	h = (rate >> 1);
> +	i = 0;
> +	while ((h < hz[i]) && (i < ARRAY_SIZE(d)))
> +		i++;
> +	if (i == ARRAY_SIZE(d))
> +		i -= 1;
> +	data = d[i];
> +	result = inv_i2c_single_write(st, reg->lpf, data);
> +	if (result)
> +		return result;
> +	st->chip_config.lpf = data;
> +	return 0;
> +}
> +
> +/**
> + *  inv_fifo_rate_store() - Set fifo rate.
> + */
> +static ssize_t inv_fifo_rate_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned long fifo_rate;
> +	unsigned char data;
> +	int result;
> +	struct inv_gyro_state_s *st;
> +	struct inv_reg_map_s *reg;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	reg = &st->reg;
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (kstrtoul(buf, 10, &fifo_rate))
> +		return -EINVAL;
> +	if ((fifo_rate < MIN_FIFO_RATE) || (fifo_rate > MAX_FIFO_RATE))
> +		return -EINVAL;
> +	if (fifo_rate == st->chip_config.fifo_rate)
> +		return count;
> +	if (st->has_compass) {
> +		data = COMPASS_RATE_SCALE*fifo_rate/ONE_K_HZ;
> +		if (data > 0)
> +			data -= 1;
> +		st->compass_divider = data;
> +		st->compass_counter = 0;
> +		/* I2C_MST_DLY is set according to sample rate,
> +		   AKM cannot be read or set at sample rate higher than
> 100Hz*/
> +		result = inv_i2c_single_write(st, REG_I2C_SLV4_CTRL,
> data);
> +		if (result)
> +			return result;
> +	}
> +	data = ONE_K_HZ / fifo_rate - 1;
> +	result = inv_i2c_single_write(st, reg->sample_rate_div, data);
> +	if (result)
> +		return result;
> +	st->chip_config.fifo_rate = fifo_rate;
> +	result = inv_set_lpf(st, fifo_rate);
> +	if (result)
> +		return result;
> +	st->irq_dur_us = (data + 1) * ONE_K_HZ;
> +	st->last_isr_time = iio_get_time_ns();
> +	return count;
> +}
> +/**
> + *  inv_fifo_rate_show() - Get the current sampling rate.
> + */
> +static ssize_t inv_fifo_rate_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->chip_config.fifo_rate);
> +}
> +
> +/**
> + *  inv_power_state_store() - Turn device on/off.
> + */
> +static ssize_t inv_power_state_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	int result;
> +	unsigned long power_state;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	if (kstrtoul(buf, 10, &power_state))
> +		return -EINVAL;
> +	if (!power_state == st->chip_config.is_asleep)
> +		return count;
> +	result = inv_set_power_state(st, power_state);
> +	return count;
> +}
> +
> +/**
> + *  inv_power_state_show() - Check if the device is on or in sleep mode.
> + */
> +static ssize_t inv_power_state_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !st->chip_config.is_asleep);
> +	if (st->chip_config.is_asleep)
> +		return sprintf(buf, "0\n");
> +	else
> +		return sprintf(buf, "1\n");
> +}
> +
> +/**
> + * inv_firmware_loaded_store() -  calling this function will change
> + *                        firmware load
> + */
> +static ssize_t inv_firmware_loaded_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned long data, result;
> +	result = kstrtoul(buf, 10, &data);
> +	if (result)
> +		return result;
> +	if (data != 0)
> +		return -EINVAL;
> +	st->chip_config.firmware_loaded = 0;
> +	st->chip_config.dmp_on = 0;
> +	return count;
> +}
> +/**
> + * inv_firmware_loaded_show() -  calling this function will show current
> + *                        firmware load status
> + */
> +static ssize_t inv_firmware_loaded_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->chip_config.firmware_loaded);
> +}
> +
> +/**
> + *  inv_lpa_mode_store() - store current low power settings
> + */
> +static ssize_t inv_lpa_mode_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned long result, lpa_mode;
> +	unsigned char d;
> +	struct inv_reg_map_s *reg;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, &lpa_mode);
> +	if (result)
> +		return result;
> +
> +	reg = &st->reg;
> +	result = inv_i2c_read(st, reg->pwr_mgmt_1, 1, &d);
> +	if (result)
> +		return result;
> +	d &= ~BIT_CYCLE;
> +	if (lpa_mode)
> +		d |= BIT_CYCLE;
> +	result = inv_i2c_single_write(st, reg->pwr_mgmt_1, d);
> +	if (result)
> +		return result;
> +	st->chip_config.lpa_mode = lpa_mode;
> +	return count;
> +}
> +/**
> + *  inv_lpa_mode_show() - show current low power settings
> + */
> +static ssize_t inv_lpa_mode_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->chip_config.lpa_mode);
> +}
> +
> +/**
> + *  inv_lpa_freq_store() - store current low power frequency setting.
> + */
> +static ssize_t inv_lpa_freq_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned long result, lpa_freq;
> +	unsigned char d;
> +	struct inv_reg_map_s *reg;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, &lpa_freq);
> +	if (result)
> +		return result;
> +	if (lpa_freq > MAX_LPA_FREQ_PARAM)
> +		return -EINVAL;
> +	reg = &st->reg;
> +	result = inv_i2c_read(st, reg->pwr_mgmt_2, 1, &d);
> +	if (result)
> +		return result;
> +	d &= ~BIT_LPA_FREQ;
> +	d |= (unsigned char)(lpa_freq << LPA_FREQ_SHIFT);
> +	result = inv_i2c_single_write(st, reg->pwr_mgmt_2, d);
> +	if (result)
> +		return result;
> +	st->chip_config.lpa_freq = lpa_freq;
> +	return count;
> +}
> +/**
> + *  inv_lpa_freq_show() - show current low power frequency setting
> + */
> +static ssize_t inv_lpa_freq_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	switch (st->chip_config.lpa_freq) {

const char * inv_freq[] = {"1.25", "5"...};

return sprintf(buf, inv_freq[st->chip_config.lpa_freq];

> +	case 0:
> +		return sprintf(buf, "1.25\n");
> +	case 1:
> +		return sprintf(buf, "5\n");
> +	case 2:
> +		return sprintf(buf, "20\n");
> +	case 3:
> +		return sprintf(buf, "40\n");
> +	default:
> +		return sprintf(buf, "0\n");
> +	}
> +}
> +/**
> + * inv_dmp_on_store() -  calling this function will store current dmp on
> + */
> +static ssize_t inv_dmp_on_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned int result, data;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (0 == st->chip_config.firmware_loaded)
> +		return -EPERM;
combine the two conditions above into
if (st->chip_config.is_asleep || !st->chip_config.firmware_loaded)
   return -EPERM;

> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
st->chip_config.dmp_on = !!data;
> +	if (data)
> +		st->chip_config.dmp_on = 1;
> +	else
> +		st->chip_config.dmp_on = 0;
> +
> +	return count;
> +}
> +/**
> + * inv_dmp_on_show() -  calling this function will show current dmp_on
> + */
> +static ssize_t inv_dmp_on_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->chip_config.dmp_on);
> +}
> +/**
> + * inv_orientation_on_store() -  calling this function will store
> + *                                 current orientation on
> + */
> +static ssize_t inv_orientation_on_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned int result, data, en;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
struct inv_gyro_state_s *st = iio_priv(dev_get_drvdata(dev));
(can do this all over the place)
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (0 == st->chip_config.firmware_loaded)
> +		return -EPERM;
again, combine the above.
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	if (data)
> +		en = 1;
> +	else
> +		en = 0;
> +	result = inv_enable_orientation_dmp(st, en);
> +	if (result)
> +		return result;
> +	st->chip_config.orientation_on = en;
> +	return count;
> +}
> +/**
> + * inv_orientation_on_show() -  calling this function will show
> + *				current orientation_on
> + */
> +static ssize_t inv_orientation_on_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->chip_config.orientation_on);
> +}
> +
> +/**
> + * inv_tap_on_store() -  calling this function will store current tap on
> + */
> +static ssize_t inv_tap_on_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned int result, data;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (0 == st->chip_config.firmware_loaded)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	if (data)
> +		st->tap.on = 1;
> +	else
> +		st->tap.on = 0;
> +	result = inv_enable_tap_dmp(st, st->tap.on);
> +	return count;
> +}
> +/**
> + * inv_tap_on_show() -  calling this function will show current tap_on
> + */
> +static ssize_t inv_tap_on_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
struct inv_gyro_state_s *st = iio_priv(dev_get_drvdata(dev));
> +
> +	return sprintf(buf, "%d\n", st->tap.on);
> +}
> +/**
> + * inv_tap_time_store() -  calling this function will store current tap
> time
> + */
> +static ssize_t inv_tap_time_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned int result, data;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (0 == st->chip_config.firmware_loaded)
> +		return -EPERM;
Another pair of conditions to combine...

> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	result = inv_set_tap_time_dmp(st, data);
> +	if (result)
> +		return result;
> +	st->tap.time = data;
> +	return count;
> +}
> +/**
> + * inv_tap_time_show() -  calling this function will show current tap
> time
> + */
> +static ssize_t inv_tap_time_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->tap.time);
> +}
> +
> +/**
> + * inv_tap_min_count_store() -  calling this function will store tap
> count
> + */
> +static ssize_t inv_tap_min_count_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned int result, data;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (0 == st->chip_config.firmware_loaded)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	result = inv_set_min_taps_dmp(st, data);
> +	if (result)
> +		return result;
> +	st->tap.min_count = data;
> +	return count;
> +}
> +/**
> + * inv_tap_min_count_show() -  calling this function show minimum count
> + */
> +static ssize_t inv_tap_min_count_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->tap.min_count);
> +}
> +
> +/**
> + * inv_tap_threshold_store() -  calling this function will store tap
> threshold
> + */
> +static ssize_t inv_tap_threshold_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned int result, data;
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (0 == st->chip_config.firmware_loaded)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
an array and a loop?
> +	result = inv_set_tap_threshold_dmp(st, INV_TAP_AXIS_X, data);
> +	if (result)
> +		return result;
> +	result = inv_set_tap_threshold_dmp(st, INV_TAP_AXIS_Y, data);
> +	if (result)
> +		return result;
> +	result = inv_set_tap_threshold_dmp(st, INV_TAP_AXIS_Z, data);
> +	if (result)
> +		return result;
> +
> +	st->tap.thresh = data;
> +	return count;
> +}
> +/**
> + * inv_tap_thresh_show() -  calling this function show current tap
> threshold
> + */
> +static ssize_t inv_tap_threshold_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->tap.thresh);
> +}
> +/**
> + *  inv_clk_src_show() - Show the device's clock source.
> + */
> +static ssize_t inv_clk_src_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	switch (st->chip_config.clk_src) {
> +	case INV_CLK_INTERNAL:
> +		return sprintf(buf, "INTERNAL\n");
> +	case INV_CLK_PLL:
> +		return sprintf(buf, "Gyro PLL\n");
> +	default:
> +		return -EPERM;
> +	}
> +}
> +/**
> + *  inv_reg_dump_show() - Register dump for testing.
> + *  TODO: Only for testing.
Got it in one.  Please drop from next patch submission.

> + */
> +static ssize_t inv_reg_dump_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	int ii;
> +	char data;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	ssize_t bytes_printed = 0;
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	for (ii = 0; ii < st->hw->num_reg; ii++) {
> +		inv_i2c_read(st, ii, 1, &data);
> +		bytes_printed += sprintf(buf+bytes_printed, "%#2x:
> %#2x\n",
> +			ii, data);
> +	}
> +	return bytes_printed;
> +}
> +
> +/**
> + * inv_self_test_show() - self test result. 0 for fail; 1 for success.
> + *                        calling this function will trigger self test
> + *                        and return test result.
> + */
> +static ssize_t inv_self_test_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	int result;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	result = inv_hw_self_test(st);
Given you don't check for error, just roll the above and below
lines together and don't bother with the intermediate variable.

> +	return sprintf(buf, "%d\n", result);
> +}
> +/**
> + * inv_key_show() -  calling this function will show the key
> + *
> + */
> +static ssize_t inv_key_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	unsigned char *key;
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	key = st->plat_data.key;
> +	return sprintf(buf,
> +
> "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> +		key[0],  key[1],  key[2],  key[3],
> +		key[4],  key[5],  key[6],  key[7],
> +		key[8],  key[9],  key[10], key[11],
> +		key[12], key[13], key[14], key[15]);
> +}
> +/**
> + * inv_gyro_matrix_show() - show orientation matrix
> + */
> +static ssize_t inv_gyro_matrix_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	signed char *m;
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	m = st->plat_data.orientation;
> +	return sprintf(buf,
> +	"%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
> +		m[0],  m[1],  m[2],  m[3], m[4], m[5], m[6], m[7], m[8]);
> +}
> +/**
> + * inv_accl_matrix_show() - show orientation matrix
> + */
> +static ssize_t inv_accl_matrix_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	signed char *m;
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	if (st->plat_data.sec_slave_type == SECONDARY_SLAVE_TYPE_ACCEL)
> +		m = st->plat_data.secondary_orientation;
> +	else
> +		m = st->plat_data.orientation;
> +	return sprintf(buf,
> +	"%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
> +		m[0],  m[1],  m[2],  m[3], m[4], m[5], m[6], m[7], m[8]);
> +}
> +/**
> + * inv_compass_matrix_show() - show orientation matrix
> + */
> +static ssize_t inv_compass_matrix_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	signed char *m;
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	if (st->plat_data.sec_slave_type == SECONDARY_SLAVE_TYPE_COMPASS)
> +		m = st->plat_data.secondary_orientation;
> +	else
> +		return -1;
> +	return sprintf(buf,
> +	"%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
> +		m[0],  m[1],  m[2],  m[3], m[4], m[5], m[6], m[7], m[8]);
> +}
> +
> +/**
> + * inv_flick_lower_store() -  calling this function will store current
> + *                        flick lower bound
> + */
> +static ssize_t inv_flick_lower_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	int result, data, out;
> +	unsigned char *p;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtol(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	out = cpu_to_be32p(&data);
> +	p = (unsigned char *)&out;
> +
> +	result = mem_w_key(KEY_FLICK_LOWER, 4, p);
> +	if (result)
> +		return result;
> +	st->flick.lower = data;
> +	return count;
> +}
> +
> +/**
> + * inv_flick_lower_show() -  calling this function will show current
> + *                        flick lower bound
> + */
> +static ssize_t inv_flick_lower_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->flick.lower);
> +}
> +/**
> + * inv_flick_upper_store() -  calling this function will store current
> + *                        flick upper bound
> + */
combine this and inv_flick_lower_store into one function.
Best way is to embed the device_attribute in a state containing
structure. This is what IIO_DEVICE_ATTR is for.

> +static ssize_t inv_flick_upper_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned int result, data, out;
> +	unsigned char *p;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	out = cpu_to_be32p(&data);
> +	p = (unsigned char *)&out;
> +	result = mem_w_key(KEY_FLICK_UPPER, 4, p);
> +	if (result)
> +		return result;
> +	st->flick.upper = data;
> +	return count;
> +}
> +
> +/**
> + * inv_flick_upper_show() -  calling this function will show current
> + *                        flick upper bound
> + */
> +static ssize_t inv_flick_upper_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->flick.upper);
> +}
> +/**
> + * inv_flick_counter_store() -  calling this function will store current
> + *                        flick counter value
> + */
> +static ssize_t inv_flick_counter_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned int result, data, out;
> +	unsigned char *p;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	out = cpu_to_be32p(&data);
> +	p = (unsigned char *)&out;
> +	result = mem_w_key(KEY_FLICK_COUNTER, 4, p);
> +	if (result)
> +		return result;
> +	st->flick.counter = data;
> +
> +	return count;
> +}
> +
> +/**
> + * inv_flick_counter_show() -  calling this function will show current
> + *                        flick counter value
> + */
> +static ssize_t inv_flick_counter_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->flick.counter);
> +}
> +
> +/**
> + * inv_flick_int_on_store() -  calling this function will store current
> + *                        flick interrupt on value
> + */
> +static ssize_t inv_flick_int_on_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned long result, data;
> +	unsigned char d[4];
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, &data);
> +	if (result)
> +		return result;
> +	if (data)
> +		/* Use interrupt to signal when gesture was observed */
> +		d[0] = DIND40+4;
> +	else
> +		d[0] = DINAA0+8;
> +	result = mem_w_key(KEY_CGNOTICE_INTR, 1, d);
> +	if (result)
> +		return result;
> +	st->flick.int_on = data;
> +	return count;
> +}
> +
> +/**
> + * inv_flick_int_on_show() -  calling this function will show current
> + *                        flick interrupt on value
> + */
> +static ssize_t inv_flick_int_on_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->flick.int_on);
> +}
> +/**
> + * inv_flick_axis_store() -  calling this function will store current
> + *                        flick axis value
> + */
> +static ssize_t inv_flick_axis_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned long result, data;
> +	unsigned char d[4];
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, &data);
> +	if (result)
> +		return result;
> +
> +	if (data == 0)
> +		d[0] = DINBC2;
> +	else if (data == 2)
> +		d[2] = DINBC6;
> +	else
> +		d[0] = DINBC4;
> +	result = mem_w_key(KEY_CFG_FLICK_IN, 1, d);
> +	if (result)
> +		return result;
> +	st->flick.axis = data;
> +
> +	return count;
> +}
> +
> +/**
> + * inv_flick_axis_show() -  calling this function will show current
> + *                        flick axis value
> + */
> +static ssize_t inv_flick_axis_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->flick.axis);
> +}

> +/**
> + * inv_flick_msg_on_store() -  calling this function will store current
> + *                        flick message on value
> + */
> +static ssize_t inv_flick_msg_on_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned int result, data, out;
> +	unsigned char *p;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +	if (data)
> +		data = DATA_MSG_ON;
> +	out = cpu_to_be32p(&data);
> +	p = (unsigned char *)&out;
> +	result = mem_w_key(KEY_FLICK_MSG, 4, p);
> +	if (result)
> +		return result;
> +	st->flick.msg_on = data;
> +
> +	return count;
> +}
> +
> +/**
> + * inv_flick_msg_on_show() -  calling this function will show current
> + *                        flick message on value
> + */
> +static ssize_t inv_flick_msg_on_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->flick.msg_on);
> +}
> +
> +/**
> + * inv_pedometer_steps_store() -  calling this function will store
> current
> + *                        pedometer steps into MPU memory
> + */
> +static ssize_t inv_pedometer_steps_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned int result, data, out;
> +	unsigned char *p;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +
> +	out = cpu_to_be32p(&data);
> +	p = (unsigned char *)&out;
> +	result = mem_w_key(KEY_D_PEDSTD_STEPCTR, 4, p);
> +	if (result)
> +		return result;
> +
> +	return count;
> +}
> +
> +/**
> + * inv_pedometer_steps_show() -  calling this function will store current
> + *                        pedometer steps into MPU memory
> + */
> +static ssize_t inv_pedometer_steps_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	int result, data;
> +	unsigned char d[4];
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = mpu_memory_read(st->sl_handle, st->i2c_addr,
> +		inv_dmp_get_address(KEY_D_PEDSTD_STEPCTR), 4, d);
> +	if (result)
> +		return result;
> +	data = be32_to_cpup((int *)d);
> +	return sprintf(buf, "%d\n", data);
> +}
> +/**
> + * inv_pedometer_time_store() -  calling this function will store current
> + *                        pedometer time into MPU memory
> + */
> +static ssize_t inv_pedometer_time_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	unsigned int result, data, out;
> +	unsigned char *p;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, (long unsigned int *)&data);
> +	if (result)
> +		return result;
> +
> +	out = cpu_to_be32p(&data);
> +	p = (unsigned char *)&out;
> +	result = mem_w_key(KEY_D_PEDSTD_TIMECTR, 4, p);
> +	if (result)
> +		return result;
> +	return count;
> +}
> +/**
> + * inv_pedometer_time_show() -  calling this function will store current
> + *                        pedometer steps into MPU memory
> + */
> +static ssize_t inv_pedometer_time_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	int result, data;
> +	unsigned char d[4];
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = mpu_memory_read(st->sl_handle, st->i2c_addr,
> +		inv_dmp_get_address(KEY_D_PEDSTD_TIMECTR), 4, d);
> +	if (result)
> +		return result;
> +	data = be32_to_cpup((int *)d);
> +	return sprintf(buf, "%d\n", data);
> +}
> +
> +/**
> + * inv_dmp_flick_show() -  calling this function will show flick event.
> + *                         This event must use poll.
> + */
> +static ssize_t inv_dmp_flick_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	return sprintf(buf, "1\n");
> +}
> +/**
> + * inv_dmp_orient_show() -  calling this function will show orientation
> + *                         This event must use poll.
> + */
> +static ssize_t inv_dmp_orient_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->orient_data);
> +}
> +/**
> + * inv_dmp_tap_show() -  calling this function will show tap
> + *                         This event must use poll.
> + */
> +static ssize_t inv_dmp_tap_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->tap_data);
> +}
> +/**
> + *  inv_temperature_show() - Read temperature data directly from
> registers.
> + */
> +static ssize_t inv_temperature_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	struct inv_reg_map_s *reg;
> +	int result;
> +	short temp;
> +	long scale_t;
> +	unsigned char data[2];
> +	reg = &st->reg;
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	result = inv_i2c_read(st, reg->temperature, 2, data);
> +	if (result) {
> +		printk(KERN_ERR "Could not read temperature register.\n");
> +		return result;
> +	}
> +	temp = (signed short)(be16_to_cpup((short *)&data[0]));
> +
> +	scale_t = MPU6050_TEMP_OFFSET +
> +		inv_q30_mult((long)temp << MPU_TEMP_SHIFT,
> +			MPU6050_TEMP_SCALE);
> +	return sprintf(buf, "%ld %lld\n", scale_t, iio_get_time_ns());
> +}
> +static int inv_switch_gyro_engine(struct inv_gyro_state_s *st, int en)
> +{
> +	struct inv_reg_map_s *reg;
> +	unsigned char data;
> +	int result;
> +	reg = &st->reg;
> +
> +	result = inv_i2c_read(st, reg->pwr_mgmt_2, 1, &data);
> +	if (result)
> +		return result;
> +	if (en)
> +		data &= (~BIT_PWR_GYRO_STBY);
> +	else
> +		data |= BIT_PWR_GYRO_STBY;
> +	result = inv_i2c_single_write(st, reg->pwr_mgmt_2, data);
> +	if (result)
> +		return result;
> +	msleep(SENSOR_UP_TIME);
> +
> +	if (en)
> +		st->chip_config.clk_src = INV_CLK_PLL;
> +	else
> +		st->chip_config.clk_src = INV_CLK_INTERNAL;
> +
> +	return 0;
> +}
> +static int inv_switch_accl_engine(struct inv_gyro_state_s *st, int en)
> +{
> +	struct inv_reg_map_s *reg;
> +	unsigned char data;
> +	int result;
> +	reg = &st->reg;
> +	result = inv_i2c_read(st, reg->pwr_mgmt_2, 1, &data);
> +	if (result)
> +		return result;
> +	if (en)
> +		data &= (~BIT_PWR_ACCL_STBY);
> +	else
> +		data |= BIT_PWR_ACCL_STBY;
> +	result = inv_i2c_single_write(st, reg->pwr_mgmt_2, data);
> +	if (result)
> +		return result;
> +	msleep(SENSOR_UP_TIME);
> +	return 0;
> +}
> +
> +/**
> + *  inv_gyro_enable_store() - Enable/disable gyro.
> + */

Look for ways to combine this and the accel version. Lots of
repeated code..

> +static ssize_t inv_gyro_enable_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned long data,  en;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	struct iio_buffer *ring = indio_dev->buffer;
> +	int result;
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (st->chip_config.enable)
> +		return -EPERM;
> +
> +	result = kstrtoul(buf, 10, &data);
> +	if (result)
> +		return -EINVAL;
> +	if (data)
> +		en = 1;
> +	else
> +		en = 0;
> +	if (en == st->chip_config.gyro_enable)
> +		return count;
> +	result = inv_switch_gyro_engine(st, en);
> +	if (result)
> +		return result;
> +
> +	if (0 == en) {
> +		st->chip_config.gyro_fifo_enable = 0;
> +		clear_bit(INV_MPU_SCAN_GYRO_X, ring->scan_mask);
> +		clear_bit(INV_MPU_SCAN_GYRO_Y, ring->scan_mask);
> +		clear_bit(INV_MPU_SCAN_GYRO_Z, ring->scan_mask);
> +	}
> +	st->chip_config.gyro_enable = en;
> +	return count;
> +}
> +/**
> + *  inv_gyro_enable_show() - Check if the FIFO and ring buffer are
> enabled.
> + */
> +static ssize_t inv_gyro_enable_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->chip_config.gyro_enable);
> +}
> +
> +/**
> + *  inv_accl_enable_store() - Enable/disable accl.
> + */
> +static ssize_t inv_accl_enable_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned long en, data;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	struct iio_buffer *ring = indio_dev->buffer;
> +	int result;
> +
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (st->chip_config.enable)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, &data);
> +	if (result)
> +		return -EINVAL;
> +	if (data)
> +		en = 1;
> +	else
> +		en = 0;
> +	if (en == st->chip_config.accl_enable)
> +		return count;
> +	result = inv_switch_accl_engine(st, en);
> +	if (result)
> +		return result;
> +	st->chip_config.accl_enable = en;
> +	if (0 == en) {
> +		st->chip_config.accl_fifo_enable = 0;
> +		clear_bit(INV_MPU_SCAN_ACCL_X, ring->scan_mask);
> +		clear_bit(INV_MPU_SCAN_ACCL_Y, ring->scan_mask);
> +		clear_bit(INV_MPU_SCAN_ACCL_Z, ring->scan_mask);
> +	}
> +	return count;
> +}
> +/**
> + *  inv_accl_enable_show() - Check if the FIFO and ring buffer are
> enabled.
> + */
> +static ssize_t inv_accl_enable_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	return sprintf(buf, "%d\n", st->chip_config.accl_enable);
> +}
> +
> +/**
> + * inv_compass_en_store() -  calling this function will store compass
> + *                         enable
> + */
> +static ssize_t inv_compass_en_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	unsigned long data, result, en;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	struct iio_buffer *ring = indio_dev->buffer;
> +	if (st->chip_config.is_asleep)
> +		return -EPERM;
> +	if (st->chip_config.enable)
> +		return -EPERM;
> +	result = kstrtoul(buf, 10, &data);
> +	if (result)
> +		return result;
> +	if (data)
> +		en = 1;
> +	else
> +		en = 0;
> +	if (en == st->chip_config.compass_enable)
> +		return count;
> +	st->chip_config.compass_enable = en;
> +	if (0 == en) {
> +		st->chip_config.compass_fifo_enable = 0;
> +		clear_bit(INV_MPU_SCAN_MAGN_X, ring->scan_mask);
> +		clear_bit(INV_MPU_SCAN_MAGN_Y, ring->scan_mask);
> +		clear_bit(INV_MPU_SCAN_MAGN_Z, ring->scan_mask);
> +	}
> +
> +	return count;
> +}
> +/**
> + * inv_compass_en_show() -  calling this function will show compass
> + *                         enable status
> + */
> +static ssize_t inv_compass_en_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", st->chip_config.compass_enable);
> +}
> +
> +static const struct iio_chan_spec gyro_accel_channels[] = {
Feel free to deploy local macros to cut down on lines of code
in the chan_spec definitions... (also make silly mistakes
a fair bit less likely.
> +	{
> +		.type = IIO_ANGL_VEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_X,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_GYRO_X,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ANGL_VEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Y,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_GYRO_Y,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ANGL_VEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Z,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_GYRO_Z,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ACCEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_X,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_ACCL_X,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ACCEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Y,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_ACCL_Y,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ACCEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Z,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_ACCL_Z,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	},
> +	IIO_CHAN_SOFT_TIMESTAMP(INV_MPU_SCAN_TIMESTAMP)
> +};
> +static const struct iio_chan_spec gyro_accel_compass_channels[] = {
> +	{
> +		.type = IIO_ANGL_VEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_X,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_GYRO_X,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ANGL_VEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Y,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_GYRO_Y,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ANGL_VEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Z,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_GYRO_Z,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ACCEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_X,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_ACCL_X,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ACCEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Y,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_ACCL_Y,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_ACCEL,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Z,
> +		.info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +		IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_ACCL_Z,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_MAGN,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_X,
> +		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_MAGN_X,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_MAGN,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Y,
> +		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_MAGN_Y,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	}, {
> +		.type = IIO_MAGN,
> +		.modified = 1,
> +		.channel2 = IIO_MOD_Z,
> +		.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +		.scan_index = INV_MPU_SCAN_MAGN_Z,
> +		.scan_type = IIO_ST('s', 16, 16, 0)
> +	},
> +
> +	IIO_CHAN_SOFT_TIMESTAMP(INV_MPU_SCAN_TIMESTAMP)
> +};
> +
> +static struct inv_chip_chan_info chip_channel_info[] = {
> +	{
> +		.channels = gyro_accel_channels,
> +		.num_channels = ARRAY_SIZE(gyro_accel_channels),

BIT(x) is handy for stuff like this.
> +		.default_scan_mask = (1 << INV_MPU_SCAN_GYRO_X) |
> +		(1 << INV_MPU_SCAN_GYRO_Y) | (1 << INV_MPU_SCAN_GYRO_Z) |
> +		(1 << INV_MPU_SCAN_ACCL_X) | (1 << INV_MPU_SCAN_ACCL_Y) |
> +		(1 << INV_MPU_SCAN_ACCL_Z) | (1 << INV_MPU_SCAN_TIMESTAMP)
> +	},
> +	{
> +		.channels = gyro_accel_compass_channels,
> +		.num_channels = ARRAY_SIZE(gyro_accel_compass_channels),
> +		.default_scan_mask = (1 << INV_MPU_SCAN_GYRO_X) |
> +		(1 << INV_MPU_SCAN_GYRO_Y) | (1 << INV_MPU_SCAN_GYRO_Z) |
> +		(1 << INV_MPU_SCAN_ACCL_X) | (1 << INV_MPU_SCAN_ACCL_Y) |
> +		(1 << INV_MPU_SCAN_ACCL_Z) | (1 << INV_MPU_SCAN_MAGN_X) |
> +		(1 << INV_MPU_SCAN_MAGN_Y) | (1 << INV_MPU_SCAN_MAGN_Z) |
> +		(1 << INV_MPU_SCAN_TIMESTAMP)
> +	}
> +};
> +
> +/*constant IIO attribute */

I'll have a look at these tomorrow.
> +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 50 100 200 500");
> +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
> +	inv_fifo_rate_store);
> +static DEVICE_ATTR(temperature, S_IRUGO, inv_temperature_show, NULL);
> +static DEVICE_ATTR(clock_source, S_IRUGO, inv_clk_src_show, NULL);
> +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, inv_power_state_show,
> +	inv_power_state_store);
> +static DEVICE_ATTR(firmware_loaded, S_IRUGO | S_IWUSR,
> +	inv_firmware_loaded_show, inv_firmware_loaded_store);
> +static DEVICE_ATTR(lpa_mode, S_IRUGO | S_IWUSR, inv_lpa_mode_show,
> +	inv_lpa_mode_store);
> +static DEVICE_ATTR(lpa_freq, S_IRUGO | S_IWUSR, inv_lpa_freq_show,
> +	inv_lpa_freq_store);
> +static DEVICE_ATTR(reg_dump, S_IRUGO, inv_reg_dump_show, NULL);
> +static DEVICE_ATTR(self_test, S_IRUGO, inv_self_test_show, NULL);
> +static DEVICE_ATTR(key, S_IRUGO, inv_key_show, NULL);
> +static DEVICE_ATTR(gyro_matrix, S_IRUGO, inv_gyro_matrix_show, NULL);
> +static DEVICE_ATTR(accl_matrix, S_IRUGO, inv_accl_matrix_show, NULL);
> +static DEVICE_ATTR(compass_matrix, S_IRUGO, inv_compass_matrix_show,
> NULL);
> +static DEVICE_ATTR(flick_lower, S_IRUGO | S_IWUSR, inv_flick_lower_show,
> +	inv_flick_lower_store);
> +static DEVICE_ATTR(flick_upper, S_IRUGO | S_IWUSR, inv_flick_upper_show,
> +	inv_flick_upper_store);
> +static DEVICE_ATTR(flick_counter, S_IRUGO | S_IWUSR,
> inv_flick_counter_show,
> +	inv_flick_counter_store);
> +static DEVICE_ATTR(flick_message_on, S_IRUGO | S_IWUSR,
> inv_flick_msg_on_show,
> +	inv_flick_msg_on_store);
> +static DEVICE_ATTR(flick_int_on, S_IRUGO | S_IWUSR,
> inv_flick_int_on_show,
> +	inv_flick_int_on_store);
> +static DEVICE_ATTR(flick_axis, S_IRUGO | S_IWUSR, inv_flick_axis_show,
> +	inv_flick_axis_store);
> +static DEVICE_ATTR(dmp_on, S_IRUGO | S_IWUSR, inv_dmp_on_show,
> +	inv_dmp_on_store);
> +static DEVICE_ATTR(orientation_on, S_IRUGO | S_IWUSR,
> +	inv_orientation_on_show, inv_orientation_on_store);
> +
> +static DEVICE_ATTR(tap_on, S_IRUGO | S_IWUSR, inv_tap_on_show,
> +	inv_tap_on_store);
> +static DEVICE_ATTR(tap_time, S_IRUGO | S_IWUSR, inv_tap_time_show,
> +	inv_tap_time_store);
> +static DEVICE_ATTR(tap_min_count, S_IRUGO | S_IWUSR,
> inv_tap_min_count_show,
> +	inv_tap_min_count_store);
> +static DEVICE_ATTR(tap_threshold, S_IRUGO | S_IWUSR,
> inv_tap_threshold_show,
> +	inv_tap_threshold_store);
> +static DEVICE_ATTR(pedometer_time, S_IRUGO | S_IWUSR,
> inv_pedometer_time_show,
> +	inv_pedometer_time_store);
> +static DEVICE_ATTR(pedometer_steps, S_IRUGO | S_IWUSR,
> +		inv_pedometer_steps_show, inv_pedometer_steps_store);
> +static DEVICE_ATTR(event_flick, S_IRUGO, inv_dmp_flick_show, NULL);
> +static DEVICE_ATTR(event_orientation, S_IRUGO, inv_dmp_orient_show,
> NULL);
> +static DEVICE_ATTR(event_tap, S_IRUGO, inv_dmp_tap_show, NULL);
> +static DEVICE_ATTR(gyro_enable, S_IRUGO | S_IWUSR, inv_gyro_enable_show,
> +	inv_gyro_enable_store);
> +static DEVICE_ATTR(accl_enable, S_IRUGO | S_IWUSR, inv_accl_enable_show,
> +	inv_accl_enable_store);
> +static DEVICE_ATTR(compass_enable, S_IRUGO | S_IWUSR,
> inv_compass_en_show,
> +	inv_compass_en_store);
> +
> +static const struct attribute *inv_mpu6050_attributes[] = {
> +	&dev_attr_gyro_enable.attr,
> +	&dev_attr_temperature.attr,
> +	&dev_attr_clock_source.attr,
> +	&dev_attr_power_state.attr,
> +	&dev_attr_reg_dump.attr,
> +	&dev_attr_self_test.attr,
> +	&dev_attr_key.attr,
> +	&dev_attr_gyro_matrix.attr,
> +	&iio_dev_attr_sampling_frequency.dev_attr.attr,
> +	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
> +	&dev_attr_accl_enable.attr,
> +	&dev_attr_accl_matrix.attr,
> +	&dev_attr_firmware_loaded.attr,
> +	&dev_attr_lpa_mode.attr,
> +	&dev_attr_lpa_freq.attr,
> +	&dev_attr_flick_lower.attr,
> +	&dev_attr_flick_upper.attr,
> +	&dev_attr_flick_counter.attr,
> +	&dev_attr_flick_message_on.attr,
> +	&dev_attr_flick_int_on.attr,
> +	&dev_attr_flick_axis.attr,
> +	&dev_attr_dmp_on.attr,
> +	&dev_attr_orientation_on.attr,
> +	&dev_attr_tap_on.attr,
> +	&dev_attr_tap_time.attr,
> +	&dev_attr_tap_min_count.attr,
> +	&dev_attr_tap_threshold.attr,
> +	&dev_attr_pedometer_time.attr,
> +	&dev_attr_pedometer_steps.attr,
> +	&dev_attr_event_flick.attr,
> +	&dev_attr_event_orientation.attr,
> +	&dev_attr_event_tap.attr,
> +};
> +
> +static const struct attribute *inv_compass_attributes[] = {
> +	&dev_attr_compass_matrix.attr,
> +	&dev_attr_compass_enable.attr,
> +};
> +
> +static struct attribute
> *inv_attributes[ARRAY_SIZE(inv_mpu6050_attributes) +
> +				ARRAY_SIZE(inv_compass_attributes) + 1];
> +static const struct attribute_group inv_attribute_group = {
> +	.name = "mpu",
> +	.attrs = inv_attributes
> +};
> +
> +static const struct iio_info mpu_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &mpu_read_raw,
> +	.write_raw = &mpu_write_raw,
> +	.attrs = &inv_attribute_group,
> +};
> +
> +/**
> + *  inv_setup_compass() - Configure compass.
> + */
> +static int inv_setup_compass(struct inv_gyro_state_s *st)
> +{
> +	int result;
> +	unsigned char data[4];
> +
> +	result = inv_i2c_read(st, REG_YGOFFS_TC, 1, data);
> +	if (result)
> +		return result;
> +	data[0] &= ~BIT_I2C_MST_VDDIO;
> +	if (st->plat_data.level_shifter)
> +		data[0] |= BIT_I2C_MST_VDDIO;
> +	/*set up VDDIO register */
> +	result = inv_i2c_single_write(st, REG_YGOFFS_TC, data[0]);
> +	if (result)
> +		return result;
> +	/* set to bypass mode */
> +	result = inv_i2c_single_write(st, REG_INT_PIN_CFG, BIT_BYPASS_EN);
> +	if (result)
> +		return result;
> +	/*read secondary i2c ID register */
> +	result = inv_secondary_read(REG_AKM_ID, 1, data);
> +	if (result)
> +		return result;
> +	if (data[0] != DATA_AKM_ID)
> +		return -ENXIO;
> +	/*set AKM to Fuse ROM access mode */
> +	result = inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_FR);
> +	if (result)
> +		return result;
> +	result = inv_secondary_read(REG_AKM_SENSITIVITY, THREE_AXIS,
> +					st->chip_info.compass_sens);
> +	if (result)
> +		return result;
> +	/*revert to power down mode */
> +	result = inv_secondary_write(REG_AKM_MODE, DATA_AKM_MODE_PW_DN);
> +	if (result)
> +		return result;
> +	pr_err("senx=%d, seny=%d,senz=%d\n",
> +		st->chip_info.compass_sens[0],
> +		st->chip_info.compass_sens[1],
> +		st->chip_info.compass_sens[2]);
> +	/*restore to non-bypass mode */
> +	result = inv_i2c_single_write(st, REG_INT_PIN_CFG, 0);
> +	if (result)
> +		return result;
> +
> +	/*setup master mode and master clock and ES bit*/
> +	result = inv_i2c_single_write(st, REG_I2C_MST_CTRL,
> BIT_WAIT_FOR_ES);
> +	if (result)
> +		return result;
> +	/* slave 0 is used to read data from compass */
> +	/*read mode */
> +	result = inv_i2c_single_write(st, REG_I2C_SLV0_ADDR, BIT_I2C_READ|
> +		st->plat_data.secondary_i2c_addr);
> +	if (result)
> +		return result;
> +	/* AKM status register address is 2 */
> +	result = inv_i2c_single_write(st, REG_I2C_SLV0_REG,
> REG_AKM_STATUS);
> +	if (result)
> +		return result;
> +	/* slave 0 is enabled at the beginning, read 8 bytes from here */
> +	result = inv_i2c_single_write(st, REG_I2C_SLV0_CTRL, BIT_SLV_EN |
> +				NUM_BYTES_COMPASS_SLAVE);
> +	if (result)
> +		return result;
> +	/*slave 1 is used for AKM mode change only*/
> +	result = inv_i2c_single_write(st, REG_I2C_SLV1_ADDR,
> +		st->plat_data.secondary_i2c_addr);
> +	if (result)
> +		return result;
> +	/* AKM mode register address is 0x0A */
> +	result = inv_i2c_single_write(st, REG_I2C_SLV1_REG, REG_AKM_MODE);
> +	if (result)
> +		return result;
> +	/* slave 1 is enabled, byte length is 1 */
> +	result = inv_i2c_single_write(st, REG_I2C_SLV1_CTRL, BIT_SLV_EN |
> 1);
> +	if (result)
> +		return result;
> +	/* output data for slave 1 is fixed, single measure mode*/
> +	st->compass_scale = 1;
> +	data[0] = 1;
> +	if (COMPASS_ID_AK8975 == st->plat_data.sec_slave_id) {

> +		st->compass_st_upper[0] = DATA_AKM8975_ST_X_UP;
> +		st->compass_st_upper[1] = DATA_AKM8975_ST_Y_UP;
> +		st->compass_st_upper[2] = DATA_AKM8975_ST_Z_UP;
> +		st->compass_st_lower[0] = DATA_AKM8975_ST_X_LW;
> +		st->compass_st_lower[1] = DATA_AKM8975_ST_Y_LW;
> +		st->compass_st_lower[2] = DATA_AKM8975_ST_Z_LW;
> +	} else if (COMPASS_ID_AK8972 == st->plat_data.sec_slave_id) {
> +		st->compass_st_upper[0] = DATA_AKM8972_ST_X_UP;
> +		st->compass_st_upper[1] = DATA_AKM8972_ST_Y_UP;
> +		st->compass_st_upper[2] = DATA_AKM8972_ST_Z_UP;
> +		st->compass_st_lower[0] = DATA_AKM8972_ST_X_LW;
> +		st->compass_st_lower[1] = DATA_AKM8972_ST_Y_LW;
> +		st->compass_st_lower[2] = DATA_AKM8972_ST_Z_LW;
> +	} else if (COMPASS_ID_AK8963 == st->plat_data.sec_slave_id) {
> +		st->compass_st_upper[0] = DATA_AKM8963_ST_X_UP;
> +		st->compass_st_upper[1] = DATA_AKM8963_ST_Y_UP;
> +		st->compass_st_upper[2] = DATA_AKM8963_ST_Z_UP;
> +		st->compass_st_lower[0] = DATA_AKM8963_ST_X_LW;
> +		st->compass_st_lower[1] = DATA_AKM8963_ST_Y_LW;
> +		st->compass_st_lower[2] = DATA_AKM8963_ST_Z_LW;
> +		data[0] |= (st->compass_scale << AKM8963_SCALE_SHIFT);
> +	}
> +	result = inv_i2c_single_write(st, REG_I2C_SLV1_DO, data[0]);
> +	if (result)
> +		return result;
> +	/* slave 0 and 1 timer action is enabled every sample*/
> +	result = inv_i2c_single_write(st, REG_I2C_MST_DELAY_CTRL,
> +				BIT_SLV0_DLY_EN | BIT_SLV1_DLY_EN);
> +	return result;
> +}
> +
> +/**
> + *  inv_check_chip_type() - check and setup chip type.
> + */
> +static int inv_check_chip_type(struct inv_gyro_state_s *st,
> +		const struct i2c_device_id *id)
> +{
> +	struct inv_reg_map_s *reg;
> +	int result, chan_index;
> +	int t_ind;
> +	if (!strcmp(id->name, "mpu6050"))
> +		st->chip_type = INV_MPU6050;
> +	else if (!strcmp(id->name, "mpu9150"))
> +		st->chip_type = INV_MPU9150;
> +	else
> +		return -EPERM;
> +	st->hw  = (struct inv_hw_s *)(hw_info  + st->chip_type);
> +	st->mpu_slave = NULL;
> +	chan_index = CHAN_INDEX_GYRO_ACCL;
> +	if (INV_MPU9150 == st->chip_type) {
> +		st->plat_data.sec_slave_type =
> SECONDARY_SLAVE_TYPE_COMPASS;
> +		st->plat_data.sec_slave_id = COMPASS_ID_AK8975;
> +		st->has_compass = 1;
> +		chan_index = CHAN_INDEX_GYRO_ACCL_MAGN;
> +	}
> +	if (SECONDARY_SLAVE_TYPE_COMPASS == st->plat_data.sec_slave_type)
> +		st->has_compass = 1;
> +	else
> +		st->has_compass = 0;
> +	if (INV_MPU6050 == st->chip_type) {
> +		if (st->has_compass)
> +			chan_index = CHAN_INDEX_GYRO_ACCL_MAGN;
> +		else
> +			chan_index = CHAN_INDEX_GYRO_ACCL;
> +	}
> +	st->chan_info = &chip_channel_info[chan_index];
> +	reg = &st->reg;
> +	inv_setup_reg(reg);
> +	st->chip_config.gyro_enable = 1;
> +	result = inv_set_power_state(st, 1);
> +	if (result)
> +		return result;
> +
> +	result = inv_get_silicon_rev_mpu6050(st);
> +	if (result) {
> +		inv_i2c_single_write(st, reg->pwr_mgmt_1,
> +					BIT_SLEEP | INV_CLK_PLL);
> +		return result;
> +	}
> +	if (st->has_compass) {
> +		result = inv_setup_compass(st);
> +		if (result) {
> +			inv_i2c_single_write(st, reg->pwr_mgmt_1,
> +					BIT_SLEEP | INV_CLK_PLL);
> +			return result;
> +		}
> +	}
> +
> +	t_ind = 0;
> +	memcpy(&inv_attributes[t_ind], inv_mpu6050_attributes,
> +			sizeof(inv_mpu6050_attributes));
> +	t_ind += ARRAY_SIZE(inv_mpu6050_attributes);
> +
> +	if (chan_index > CHAN_INDEX_GYRO_ACCL) {
> +		memcpy(&inv_attributes[t_ind], inv_compass_attributes,
> +				sizeof(inv_compass_attributes));
> +		t_ind += ARRAY_SIZE(inv_compass_attributes);
> +	}
> +	inv_attributes[t_ind] = NULL;
> +	return 0;
> +}
> +
> +/**
> + *  inv_create_dmp_sysfs() - create binary sysfs dmp entry.
> + */
> +static const struct bin_attribute dmp_firmware = {
> +	.attr = {
> +		.name = "dmp_firmware",
> +		.mode = S_IRUGO | S_IWUSR
> +	},
> +	.size = 4096,
> +	.read = inv_dmp_firmware_read,
> +	.write = inv_dmp_firmware_write,
> +};
> +
> +static int inv_create_dmp_sysfs(struct iio_dev *ind)
> +{
> +	int result;
> +	result = sysfs_create_bin_file(&ind->dev.kobj, &dmp_firmware);
> +	return result;
> +}
> +
> +/**
> + *  inv_mpu_probe() - probe function.
> + */
> +static int inv_mpu_probe(struct i2c_client *client,
> +	const struct i2c_device_id *id)
> +{
> +	struct inv_gyro_state_s *st;
> +	struct iio_dev *indio_dev;
> +	int result, reg_done;
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		result = -ENODEV;
> +		goto out_no_free;
> +	}
> +	indio_dev = iio_allocate_device(sizeof(*st));
> +	if (indio_dev == NULL) {
> +		result =  -ENOMEM;
> +		goto out_no_free;
> +	}
> +	reg_done = 0;
> +	st = iio_priv(indio_dev);
> +	st->i2c = client;
> +	st->sl_handle = client->adapter;
> +	st->i2c_addr = client->addr;
> +	st->plat_data =
> +		*(struct mpu_platform_data
> *)dev_get_platdata(&client->dev);
> +	/* power is turned on inside check chip type*/
> +	result = inv_check_chip_type(st, id);
> +	if (result)
> +		goto out_free;
> +	result = inv_init_config(indio_dev);
> +	if (result) {
> +		dev_err(&client->adapter->dev,
> +			"Could not initialize device.\n");
> +		goto out_free;
> +	}
> +	result = inv_set_power_state(st, 1);
> +	if (result) {
> +		dev_err(&client->adapter->dev,
> +			"%s could not be turned off.\n", st->hw->name);
> +		goto out_free;
> +	}
> +
> +	/* Make state variables available to all _show and _store
> functions. */
> +	i2c_set_clientdata(client, indio_dev);
> +	indio_dev->dev.parent = &client->dev;
> +	indio_dev->name = id->name;
> +	indio_dev->channels = st->chan_info->channels;
> +	indio_dev->num_channels = st->chan_info->num_channels;
> +	indio_dev->info = &mpu_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->currentmode = INDIO_DIRECT_MODE;
> +
> +	result = inv_mpu_configure_ring(indio_dev);
> +	if (result)
> +		goto out_free;
> +	result = iio_buffer_register(indio_dev, st->chan_info->channels,
> +					st->chan_info->num_channels);
> +	if (result)
> +		goto out_unreg_ring;
> +	st->irq = client->irq;
> +	result = inv_mpu_probe_trigger(indio_dev);
> +	if (result)
> +		goto out_remove_ring;
> +
> +	result = iio_device_register(indio_dev);
> +	if (result)
> +		goto out_remove_trigger;
> +	result = inv_create_dmp_sysfs(indio_dev);
> +	if (result)
> +		goto out_unreg_iio;
> +
> +	INIT_KFIFO(st->timestamps);
> +	spin_lock_init(&st->time_stamp_lock);
> +	pr_info("%s: Probe name %s\n", __func__, id->name);
> +	dev_info(&client->adapter->dev, "%s is ready to go!\n",
> st->hw->name);
> +	return 0;
> +out_unreg_iio:
> +	iio_device_unregister(indio_dev);
> +out_remove_trigger:
> +	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
> +		inv_mpu_remove_trigger(indio_dev);
> +out_remove_ring:
> +	iio_buffer_unregister(indio_dev);
> +out_unreg_ring:
> +	inv_mpu_unconfigure_ring(indio_dev);
> +out_free:
> +	iio_free_device(indio_dev);
> +out_no_free:
> +	dev_err(&client->adapter->dev, "%s failed %d\n", __func__,
> result);
> +	return -EIO;
> +}
> +
> +/**
> + *  inv_mpu_remove() - remove function.
> + */
> +static int inv_mpu_remove(struct i2c_client *client)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +	struct inv_gyro_state_s *st = iio_priv(indio_dev);
> +	kfifo_free(&st->timestamps);
> +	iio_device_unregister(indio_dev);
> +	inv_mpu_remove_trigger(indio_dev);
> +	iio_buffer_unregister(indio_dev);
> +	inv_mpu_unconfigure_ring(indio_dev);
> +	iio_free_device(indio_dev);
> +
> +	dev_info(&client->adapter->dev, "inv-mpu module removed.\n");
> +	return 0;
> +}
> +static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
> +/* device id table is used to identify what device can be
> + * supported by this driver
> + */
> +static const struct i2c_device_id inv_mpu_id[] = {
> +	{"mpu6050", INV_MPU6050},
> +	{"mpu9150", INV_MPU9150},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
> +
> +static struct i2c_driver inv_mpu_driver = {
> +	.class = I2C_CLASS_HWMON,
> +	.probe		=	inv_mpu_probe,
> +	.remove		=	inv_mpu_remove,
> +	.id_table	=	inv_mpu_id,
> +	.driver = {
> +		.owner	=	THIS_MODULE,
> +		.name	=	"inv-mpu6050-iio",
> +	},
> +	.address_list = normal_i2c,
> +};
> +
> +static int __init inv_mpu_init(void)
> +{
> +	int result = i2c_add_driver(&inv_mpu_driver);
> +	if (result) {
> +		pr_err("%s failed\n", __func__);
> +		return result;
> +	}
> +	return 0;
> +}
> +
> +static void __exit inv_mpu_exit(void)
> +{
> +	i2c_del_driver(&inv_mpu_driver);
> +}
> +
> +module_init(inv_mpu_init);
> +module_exit(inv_mpu_exit);
> +
> +MODULE_AUTHOR("Invensense Corporation");
> +MODULE_DESCRIPTION("Invensense device driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("inv-mpu6050-iio");
> +/**
> + *  @}
> + */
> +
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux