bma150

#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>

#define BMA150_VERSION "1.2.0"

#define BMA150_NAME "bma150"

/* for debugging */
#define DEBUG 0
#define DEBUG_THRESHOLD 0
#define TRACE_FUNC() pr_debug(BMA150_NAME ": <trace> %s()\n", __FUNCTION__)

/*
 * Default parameters
 */
#define SENSOR_DELAY_FASTEST            0       // delay = 10
#define SENSOR_DELAY_GAME               1       // delay = 20
#define SENSOR_DELAY_UI                 2       // delay = 60
#define SENSOR_DELAY_NORMAL             3       // delay = 200

#define BMA150_DEFAULT_DELAY            SENSOR_DELAY_NORMAL
#define BMA150_MAX_DELAY                SENSOR_DELAY_NORMAL
#define BMA150_DEFAULT_THRESHOLD        0
/*
 * Registers
 */
#define BMA150_CHIP_ID_REG              0x00
#define BMA150_CHIP_ID                  0x02

#define BMA150_AL_VERSION_REG           0x01
#define BMA150_AL_VERSION_MASK          0x0f
#define BMA150_AL_VERSION_SHIFT         0

#define BMA150_ML_VERSION_REG           0x01
#define BMA150_ML_VERSION_MASK          0xf0
#define BMA150_ML_VERSION_SHIFT         4

#define BMA150_ACC_REG                  0x02

#define BMA150_SOFT_RESET_REG           0x0a
#define BMA150_SOFT_RESET_MASK          0x02
#define BMA150_SOFT_RESET_SHIFT         1

#define BMA150_SLEEP_REG                0x0a
#define BMA150_SLEEP_MASK               0x01
#define BMA150_SLEEP_SHIFT              0

#define BMA150_RANGE_REG                0x14//量测
#define BMA150_RANGE_MASK               0x18
#define BMA150_RANGE_SHIFT              3
#define BMA150_RANGE_2G                 0//量测为2g
#define BMA150_RANGE_4G                 1
#define BMA150_RANGE_8G                 2

#define BMA150_BANDWIDTH_REG            0x14//带宽
#define BMA150_BANDWIDTH_MASK           0x07
#define BMA150_BANDWIDTH_SHIFT          0
#define BMA150_BANDWIDTH_25HZ           0
#define BMA150_BANDWIDTH_50HZ           1
#define BMA150_BANDWIDTH_100HZ          2
#define BMA150_BANDWIDTH_190HZ          3
#define BMA150_BANDWIDTH_375HZ          4
#define BMA150_BANDWIDTH_750HZ          5
#define BMA150_BANDWIDTH_1500HZ         6

#define BMA150_SHADOW_DIS_REG           0x15
#define BMA150_SHADOW_DIS_MASK          0x08
#define BMA150_SHADOW_DIS_SHIFT         3

#define BMA150_WAKE_UP_PAUSE_REG        0x15
#define BMA150_WAKE_UP_PAUSE_MASK       0x06
#define BMA150_WAKE_UP_PAUSE_SHIFT      1

#define BMA150_WAKE_UP_REG              0x15
#define BMA150_WAKE_UP_MASK             0x01
#define BMA150_WAKE_UP_SHIFT            0

/*
 * Acceleration measurement
 */
#define BMA150_RESOLUTION               256

/* ABS axes parameter range [um/s^2] (for input event) */
#define GRAVITY_EARTH                   9806550
#define ABSMIN_2G                       (-GRAVITY_EARTH * 2)
#define ABSMAX_2G                       (GRAVITY_EARTH * 2)

struct acceleration {
	int x;
	int y;
	int z;
};

/*
 * Output data rate
 */
struct bma150_odr {
        unsigned long delay;            /* min delay (msec) in the range of ODR */
        u8 odr;                         /* bandwidth register value */
};

static const struct bma150_odr bma150_odr_table[] = {
	{1,  BMA150_BANDWIDTH_1500HZ},
	{2,  BMA150_BANDWIDTH_750HZ},
	{3,  BMA150_BANDWIDTH_375HZ},
	{6,  BMA150_BANDWIDTH_190HZ},
	{10, BMA150_BANDWIDTH_100HZ},
	{20, BMA150_BANDWIDTH_50HZ},
	{40, BMA150_BANDWIDTH_25HZ},
};

/*
 * Transformation matrix for chip mounting position
 */
static const int bma150_position_map[][3][3] = {
	{{ 0, -1,  0}, { 1,  0,  0}, { 0,  0,  1}}, /* top/upper-left */
	{{ 1,  0,  0}, { 0,  1,  0}, { 0,  0,  1}}, /* top/upper-right */
	{{ 0,  1,  0}, {-1,  0,  0}, { 0,  0,  1}}, /* top/lower-right */
	{{-1,  0,  0}, { 0, -1,  0}, { 0,  0,  1}}, /* top/lower-left */
	{{ 0,  1,  0}, { 1,  0,  0}, { 0,  0, -1}}, /* bottom/upper-right */
	{{-1,  0,  0}, { 0,  1,  0}, { 0,  0, -1}}, /* bottom/upper-left */
	{{ 0, -1,  0}, {-1,  0,  0}, { 0,  0, -1}}, /* bottom/lower-left */
	{{ 1,  0,  0}, { 0, -1,  0}, { 0,  0, -1}}, /* bottom/lower-right */
};

/*
 * driver private data
 */
struct bma150_data {
	atomic_t enable;                /* attribute value */
	atomic_t delay;                 /* attribute value */
	atomic_t position;              /* attribute value */
	atomic_t threshold;             /* attribute value */
	struct acceleration last;       /* last measured data */
	struct mutex enable_mutex;
	struct mutex data_mutex;
	struct i2c_client *client;
	struct input_dev *input;
	struct delayed_work work;
#if DEBUG
	int suspend;
#endif
};
static struct bma150_data *bma150_ptr;

#define BMAIO			       	0x50
#define BMA_IOCTL_ENABLE		_IO(BMAIO, 0x31)
#define BMA_IOCTL_DISABLE		_IO(BMAIO, 0x32)
#define BMA_IOCTL_IS_ENABLE		_IOR(BMAIO, 0x33, int)
#define BMA_IOCTL_DELAY_GET		_IOR(BMAIO, 0x34, int)
#define BMA_IOCTL_DELAY_SET		_IOW(BMAIO, 0x35, int)
#define BMA_IOCTL_POSITION_GET		_IOR(BMAIO, 0x36, int)
#define BMA_IOCTL_POSITION_SET		_IOW(BMAIO, 0x37, int)
#define BMA_IOCTL_THRESHOLD_GET		_IOR(BMAIO, 0x38, int)
#define BMA_IOCTL_THRESHOLD_SET		_IOW(BMAIO, 0x39, int)
#define BMA_IOCTL_DATA			_IOR(BMAIO, 0x3a, int[3])

static int bma150_device_open( struct inode*, struct file* );
static int bma150_device_release( struct inode*, struct file* );
static int bma150_device_ioctl( struct inode*, struct file*, unsigned int, unsigned long );
static ssize_t bma150_device_read( struct file *filp, char *buf, size_t count, loff_t *ofs );
static ssize_t bma150_device_write( struct file *filp, const char *buf, size_t count, loff_t *ofs );
static unsigned int bma150_device_poll( struct file *filp, struct poll_table_struct *pwait );

static struct file_operations bma150_device_fops =
{
	.owner = THIS_MODULE,
	.open = bma150_device_open,
	.ioctl = bma150_device_ioctl,
	.release = bma150_device_release,
	.read = bma150_device_read,
	.write = bma150_device_write,
	.poll = bma150_device_poll,
};

static struct miscdevice bma150_misc =
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = BMA150_NAME,
	.fops = &bma150_device_fops,
};

#define delay_to_jiffies(d) ((d)?msecs_to_jiffies(d):1)
#define actual_delay(d)     (jiffies_to_msecs(delay_to_jiffies(d)))

/* register access functions */
#define bma150_read_bits(p,r) \
	((i2c_smbus_read_byte_data((p)->client, r##_REG) & r##_MASK) >> r##_SHIFT)

#define bma150_update_bits(p,r,v) \
        i2c_smbus_write_byte_data((p)->client, r##_REG, \
                ((i2c_smbus_read_byte_data((p)->client,r##_REG) & ~r##_MASK) | ((v) << r##_SHIFT)))

/*
 * Device dependant operations
 */

static int bma150_power_up(struct bma150_data *bma150)
{
	bma150_update_bits(bma150, BMA150_SLEEP, 0);//上电
	/* wait 1ms for wake-up time from sleep to operational mode */
	msleep(1);

	return 0;
}

static int bma150_power_down(struct bma150_data *bma150)
{
	bma150_update_bits(bma150, BMA150_SLEEP, 1);//断电

	return 0;
}

static int bma150_hw_init(struct bma150_data *bma150)
{
	/* reset hardware */
	bma150_power_up(bma150);//上电
	i2c_smbus_write_byte_data(bma150->client,
				  BMA150_SOFT_RESET_REG, BMA150_SOFT_RESET_MASK);//复位

	/* wait 10us after soft_reset to start I2C transaction */
	msleep(1);

	bma150_update_bits(bma150, BMA150_RANGE, BMA150_RANGE_2G);//设置量测

	bma150_power_down(bma150);//掉电

	return 0;
}

static int bma150_get_enable(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	return atomic_read(&bma150->enable);
}

static void bma150_set_enable(struct device *dev, int enable)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);
	int delay = atomic_read(&bma150->delay);

	mutex_lock(&bma150->enable_mutex);

	if (enable)
	{                   /* enable if state will be changed */
		if (!atomic_cmpxchg(&bma150->enable, 0, 1))
		{
			bma150_power_up(bma150);//上电
			schedule_delayed_work(&bma150->work,
					      delay_to_jiffies(delay) + 1);//调用延时队列
		}
	}
	else
	{                        /* disable if state will be changed */
		if (atomic_cmpxchg(&bma150->enable, 1, 0))
		{
			cancel_delayed_work_sync(&bma150->work);//取消延时队列
			bma150_power_down(bma150);//断电
		}
	}
	atomic_set(&bma150->enable, enable);

	mutex_unlock(&bma150->enable_mutex);
}

static int bma150_get_delay(struct device *dev)//获得延时
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	return atomic_read(&bma150->delay);
}

static void bma150_set_delay(struct device *dev, int delay)//设置延时
{
	int delay_ms;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);
	u8 odr;
	int i;

	/* determine optimum ODR */
	for (i = 1; (i < ARRAY_SIZE(bma150_odr_table)) &&
		     (actual_delay(delay) >= bma150_odr_table[i].delay); i++)
		;
	odr = bma150_odr_table[i-1].odr;
	atomic_set(&bma150->delay, delay);

	mutex_lock(&bma150->enable_mutex);

	if (bma150_get_enable(dev))
	{
#if 0
		switch(delay)
		{
		case SENSOR_DELAY_FASTEST:
			delay_ms = 50;
			break;
		case SENSOR_DELAY_GAME:
			delay_ms = 80;
			break;
		case SENSOR_DELAY_UI:
			delay_ms = 100;
			break;
		default:
		case SENSOR_DELAY_NORMAL:
			delay_ms = 200;
			break;
		}
#else
		delay_ms = delay;printk(KERN_INFO "test delay :%d\n", delay_ms);
#endif		
		cancel_delayed_work_sync(&bma150->work);
		bma150_update_bits(bma150, BMA150_BANDWIDTH, odr);
		schedule_delayed_work(&bma150->work,
				      delay_to_jiffies(delay_ms) + 1);
	}
	else
	{
		bma150_power_up(bma150);
		bma150_update_bits(bma150, BMA150_BANDWIDTH, odr);
		bma150_power_down(bma150);
	}

	mutex_unlock(&bma150->enable_mutex);
}

static int bma150_get_position(struct device *dev)// 获得位置
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	return atomic_read(&bma150->position);
}

static void bma150_set_position(struct device *dev, int position)//设置位置
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	atomic_set(&bma150->position, position);
}

static int bma150_get_threshold(struct device *dev)//获得阀值
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	return atomic_read(&bma150->threshold);
}

static void bma150_set_threshold(struct device *dev, int threshold)//设置阀值
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma150_data *bma150 = i2c_get_clientdata(client);

        atomic_set(&bma150->threshold, threshold);
}

static int bma150_data_filter(struct bma150_data *bma150, struct acceleration *accel, int data[])//数据处理
{
	int threshold = atomic_read(&bma150->threshold);
#if DEBUG_THRESHOLD
	struct i2c_client *client = bma150->client;
        int update;
#endif
#if DEBUG_THRESHOLD
        update = 0;
#endif
	mutex_lock(&bma150->data_mutex);
	if ((abs(bma150->last.x - data[0]) > threshold) ||
            (abs(bma150->last.y - data[1]) > threshold) ||
            (abs(bma150->last.z - data[2]) > threshold))
	{
		accel->x = (-1)*data[0];
		accel->y = data[1];
		accel->z = data[2];
#if DEBUG_THRESHOLD
                update = 1;
#endif
        }
	else
	{
		*accel = bma150->last;
	}

#if DEBUG_THRESHOLD
        if (update == 1)
	{
            dev_info(&client->dev, "threshold=%d x(%d) y(%d) z(%d) accel(%d,%d,%d) ****\n", threshold,
                     bma150->last.x - data[0], bma150->last.y - data[1], bma150->last.z - data[2], accel->x, accel->y, accel->z);
        }
	else
	{
            dev_info(&client->dev, "threshold=%d x(%d) y(%d) z(%d) accel(%d,%d,%d)\n", threshold,
                     bma150->last.x - data[0], bma150->last.y - data[1], bma150->last.z - data[2], accel->x, accel->y, accel->z);
        }
#endif
	mutex_unlock(&bma150->data_mutex);

    return 0;
}

static int bma150_measure(struct bma150_data *bma150, struct acceleration *accel)
{
	struct i2c_client *client = bma150->client;
	u8 buf[6];
	int raw[3], data[3];
	int pos = atomic_read(&bma150->position);
	long long g;
	int i, j;

	/* read acceleration data */
	if (i2c_smbus_read_i2c_block_data(client, BMA150_ACC_REG, 6, buf) != 6)//出iic读出数据
	{
		dev_err(&client->dev,
			"I2C block read error: addr=0x%02x, len=%d\n",
			BMA150_ACC_REG, 6);
		for (i = 0; i < 3; i++)
			raw[i] = 0;
	}
	else
	{
		for (i = 0; i < 3; i++)
			raw[i] = (*(s16 *)&buf[i*2]) >> 6;
	}

	/* for X, Y, Z axis */
	for (i = 0; i < 3; i++)
	{
		/* coordinate transformation */
		data[i] = 0;
		for (j = 0; j < 3; j++)
			data[i] += raw[j] * bma150_position_map[pos][i][j];

		/* normalization */
		g = (long long)data[i] * GRAVITY_EARTH / BMA150_RESOLUTION;
		data[i] = g;
	}

	dev_dbg(&client->dev, "raw(%5d,%5d,%5d) => norm(%8d,%8d,%8d)\n",
		raw[0], raw[1], raw[2], data[0], data[1], data[2]);

        bma150_data_filter(bma150, accel, data);//数据处理

	return 0;
}

static void bma150_work_func(struct work_struct *work)
{
	struct bma150_data *bma150 = container_of((struct delayed_work *)work,
						  struct bma150_data, work);
	struct acceleration accel;
	unsigned long delay = delay_to_jiffies(atomic_read(&bma150->delay));

	bma150_measure(bma150, &accel);

	input_report_abs(bma150->input, ABS_X, accel.x);//上报x极
	input_report_abs(bma150->input, ABS_Y, accel.y);//上报y极
	input_report_abs(bma150->input, ABS_Z, accel.z);//上报z极
	input_sync(bma150->input);

	mutex_lock(&bma150->data_mutex);
	bma150->last = accel;
	mutex_unlock(&bma150->data_mutex);

	schedule_delayed_work(&bma150->work, delay);//调用延时队列
}

/*
 * Input device interface
 */
static int bma150_input_init(struct bma150_data *bma150)
{
	struct input_dev *dev;
	int err;

	dev = input_allocate_device(); //分配input设备
	if (!dev)
		return -ENOMEM;

	dev->name = "bma150";
	dev->id.bustype = BUS_I2C;

	set_bit(EV_ABS, dev->evbit);
	set_bit(EV_SYN, dev->evbit);
	input_set_abs_params(dev, ABS_X, ABSMIN_2G, ABSMAX_2G, 0, 0);//x方向的范围
	input_set_abs_params(dev, ABS_Y, ABSMIN_2G, ABSMAX_2G, 0, 0);//y方向的范围
	input_set_abs_params(dev, ABS_Z, ABSMIN_2G, ABSMAX_2G, 0, 0);//z方向的范围
	input_set_drvdata(dev, bma150);//把bma150放入input设备的某个成员的data

	err = input_register_device(dev);//注册input
	if (err < 0) {
		input_free_device(dev);
		return err;
	}
	bma150->input = dev;//把input设备保存到bma150的input成员

	return 0;
}

static void bma150_input_fini(struct bma150_data *bma150)
{
	struct input_dev *dev = bma150->input;

	input_unregister_device(dev);//注销input设备
	input_free_device(dev);
}

/*
 * sysfs device attributes
 */
static ssize_t bma150_enable_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", bma150_get_enable(dev));
}

static ssize_t bma150_enable_store(struct device *dev,
				   struct device_attribute *attr,
				   const char *buf, size_t count)
{
	unsigned long enable = simple_strtoul(buf, NULL, 10);

	if ((enable == 0) || (enable == 1))
		bma150_set_enable(dev, enable);//使能

	return count;
}

static ssize_t bma150_delay_show(struct device *dev,
				 struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", bma150_get_delay(dev));
}

static ssize_t bma150_delay_store(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t count)
{
	unsigned long delay = simple_strtoul(buf, NULL, 10);

//	if (delay > BMA150_MAX_DELAY)
//		delay = BMA150_MAX_DELAY;

	bma150_set_delay(dev, delay);

	return count;
}

static ssize_t bma150_position_show(struct device *dev,
				    struct device_attribute *attr, char *buf)//显示位置属性
{
	return sprintf(buf, "%d\n", bma150_get_position(dev));
}

static ssize_t bma150_position_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)//写位置属性
{
	unsigned long position;

	position = simple_strtoul(buf, NULL,10);
	if ((position >= 0) && (position <= 7))
		bma150_set_position(dev, position);

	return count;
}

static ssize_t bma150_threshold_show(struct device *dev,
				     struct device_attribute *attr, char *buf) //显示阀值属性
{
	return sprintf(buf, "%d\n", bma150_get_threshold(dev));
}

static ssize_t bma150_threshold_store(struct device *dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)//写阀值属性
{
	unsigned long threshold;

	threshold = simple_strtoul(buf, NULL,10);
        if (threshold >= 0 && threshold <= ABSMAX_2G)
		bma150_set_threshold(dev, threshold);

	return count;
}

static ssize_t bma150_wake_store(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)//显示唤醒属性
{
	struct input_dev *input = to_input_dev(dev);
	static atomic_t serial = ATOMIC_INIT(0);

	input_report_abs(input, ABS_MISC, atomic_inc_return(&serial));

	return count;
}

static ssize_t bma150_data_show(struct device *dev,
				struct device_attribute *attr, char *buf) //显示数据 
{
	struct input_dev *input = to_input_dev(dev);
	struct bma150_data *bma150 = input_get_drvdata(input);
	struct acceleration accel;

	mutex_lock(&bma150->data_mutex);
	accel = bma150->last;
	mutex_unlock(&bma150->data_mutex);

	return sprintf(buf, "%d %d %d\n", accel.x, accel.y, accel.z);
}

#if DEBUG
static ssize_t bma150_debug_reg_show(struct device *dev,
				     struct device_attribute *attr, char *buf) //显示寄存器
{
	struct input_dev *input = to_input_dev(dev);
	struct bma150_data *bma150 = input_get_drvdata(input);
	struct i2c_client *client = bma150->client;
	ssize_t count = 0;
	u8 reg[0x16];
	int i;

	i2c_smbus_read_i2c_block_data(client, 0x00, 0x16, reg);
	for (i = 0; i < 0x16; i++)
		count += sprintf(&buf[count], "%02x: %d\n", i, reg[i]);

	return count;
}

static int bma150_suspend(struct i2c_client *client, pm_message_t mesg);
static int bma150_resume(struct i2c_client *client);

static ssize_t bma150_debug_suspend_show(struct device *dev,
					 struct device_attribute *attr, char *buf) //挂起属性显示
{
	struct input_dev *input = to_input_dev(dev);
	struct bma150_data *bma150 = input_get_drvdata(input);

	return sprintf(buf, "%d\n", bma150->suspend);
}

static ssize_t bma150_debug_suspend_store(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count) //写挂起属性
{
	struct input_dev *input = to_input_dev(dev);
	struct bma150_data *bma150 = input_get_drvdata(input);
	struct i2c_client *client = bma150->client;
	unsigned long suspend = simple_strtoul(buf, NULL, 10);

	if (suspend)
	{
		pm_message_t msg;
		bma150_suspend(client, msg);
	}
	else
	{
		bma150_resume(client);
	}

	return count;
}
#endif /* DEBUG */

static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,
		   bma150_enable_show, bma150_enable_store);
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,
		   bma150_delay_show, bma150_delay_store);
static DEVICE_ATTR(position, S_IRUGO|S_IWUSR,
		   bma150_position_show, bma150_position_store);
static DEVICE_ATTR(threshold, S_IRUGO|S_IWUSR,
		   bma150_threshold_show, bma150_threshold_store);
static DEVICE_ATTR(wake, S_IWUSR|S_IWGRP,
		   NULL, bma150_wake_store);
static DEVICE_ATTR(data, S_IRUGO,
		   bma150_data_show, NULL);

#if DEBUG
static DEVICE_ATTR(debug_reg, S_IRUGO,
		   bma150_debug_reg_show, NULL);
static DEVICE_ATTR(debug_suspend, S_IRUGO|S_IWUSR,
		   bma150_debug_suspend_show, bma150_debug_suspend_store);
#endif /* DEBUG */

static struct attribute *bma150_attributes[] = {
	&dev_attr_enable.attr,
	&dev_attr_delay.attr,
	&dev_attr_position.attr,
	&dev_attr_threshold.attr,
	&dev_attr_wake.attr,
	&dev_attr_data.attr,
#if DEBUG
	&dev_attr_debug_reg.attr,
	&dev_attr_debug_suspend.attr,
#endif /* DEBUG */
	NULL
};

static struct attribute_group bma150_attribute_group = {
	.attrs = bma150_attributes
};

/* bma150 file operation */
static int bma150_device_open( struct inode* inode, struct file* file)
{
	return 0;
}

static int bma150_device_release( struct inode* inode, struct file* file)
{
	return 0;
}

static int bma150_device_ioctl( struct inode* inode, struct file* file, unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	int ret=0;
	int kbuf = 0;
	int axis_data[3];

	switch( cmd )
	{
	case BMA_IOCTL_ENABLE:
//		printk(KERN_INFO "test : enabled\n");
		bma150_set_enable(&bma150_ptr->client->dev, 1);//时能设备
		break;
	case BMA_IOCTL_DISABLE:
//		printk(KERN_INFO "test : disabled\n");
		bma150_set_enable(&bma150_ptr->client->dev, 0);//禁止设备
		break;
	case BMA_IOCTL_IS_ENABLE:
//		printk(KERN_INFO "test : is enabled\n");
		kbuf = bma150_get_enable(&bma150_ptr->client->dev);//控制使能
		if(copy_to_user(argp, &kbuf, sizeof(kbuf)))
			return -EFAULT;
		break;
	case BMA_IOCTL_DELAY_GET:
		kbuf = bma150_get_delay(&bma150_ptr->client->dev);//获得延时
		if(copy_to_user(argp, &kbuf, sizeof(kbuf)))
			return -EFAULT;
		break;
	case BMA_IOCTL_DELAY_SET:
		if(copy_from_user(&kbuf, argp, sizeof(kbuf)))//设置延时
			return -EFAULT;
//		printk(KERN_INFO "test : delay : %d\n", kbuf);
//		if(kbuf > BMA150_MAX_DELAY)
//			kbuf = BMA150_MAX_DELAY;
		bma150_set_delay(&bma150_ptr->client->dev, kbuf);
		break;
 	case BMA_IOCTL_POSITION_GET:			//获得 位置
		kbuf = bma150_get_position(&bma150_ptr->client->dev);
		if(copy_to_user(argp, &kbuf, sizeof(kbuf)))
			return -EFAULT;
		break;
	case BMA_IOCTL_POSITION_SET:	//设置位置
		if(copy_from_user(&kbuf, argp, sizeof(kbuf)))
			return -EFAULT;
		if ((kbuf >= 0) && (kbuf <= 7))
			kbuf = CONFIG_SENSORS_BMA150_POSITION_V2;
		bma150_set_position(&bma150_ptr->client->dev, kbuf);
		break;
	case BMA_IOCTL_THRESHOLD_GET:   //获得阀值
		kbuf = bma150_get_threshold(&bma150_ptr->client->dev);
		if(copy_to_user(argp, &kbuf, sizeof(kbuf)))
			return -EFAULT;
		break;
	case BMA_IOCTL_THRESHOLD_SET:	//设置阀值
		if(copy_from_user(&kbuf, argp, sizeof(kbuf)))
			return -EFAULT;
        	if (kbuf >= 0 && kbuf <= ABSMAX_2G)
			kbuf = BMA150_DEFAULT_THRESHOLD;
		bma150_set_threshold(&bma150_ptr->client->dev, kbuf);
		break;
	case BMA_IOCTL_DATA:  //获得x ,y,z方向
		axis_data[0] = bma150_ptr->last.x;
		axis_data[1] = bma150_ptr->last.y;
		axis_data[2] = bma150_ptr->last.z;
		if(copy_to_user(argp, &axis_data, sizeof(axis_data)))
			return -EFAULT;
		break;
	default:
		return -ENOTTY;
	}

	return ret;
}

static ssize_t bma150_device_read( struct file *filp, char *buf, size_t count, loff_t *ofs )
{
	return 0;
}

static ssize_t bma150_device_write( struct file *filp, const char *buf, size_t count, loff_t *ofs )
{
	return 0;
}

static unsigned int bma150_device_poll( struct file *filp, struct poll_table_struct *pwait )
{
	return 0;
}

/*
 * I2C client
 */
static int bma150_detect(struct i2c_client *client, struct i2c_board_info *info)
{
	int id;

	id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);//读出id
	if (id != BMA150_CHIP_ID)//检测设备是否存在
		return -ENODEV;

	return 0;
}

static int bma150_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct bma150_data *bma150;
	int err;

	/* setup private data */
	bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);//分配一个bma150设备结构体
	if (!bma150)
	{
		err = -ENOMEM;
		goto error_0;
	}
	mutex_init(&bma150->enable_mutex);//初始化时能互斥锁
	mutex_init(&bma150->data_mutex);//初始化数据互斥锁

	/* setup i2c client */
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))//检测是否支持 I2C_FUNC_I2C
	{
		err = -ENODEV;
		goto error_1;
	}
	i2c_set_clientdata(client, bma150);//把bma150放入client某个成员的data
	bma150->client = client;

	/* detect and init hardware */
	if ((err = bma150_detect(client, NULL)))//检测设备是否存在
		goto error_1;

	dev_info(&client->dev, "%s found\n", id->name);
	dev_info(&client->dev, "al_version=%d, ml_version=%d\n",
		 bma150_read_bits(bma150, BMA150_AL_VERSION),
		 bma150_read_bits(bma150, BMA150_ML_VERSION));

        bma150_hw_init(bma150);//硬件一些初始化
	//bma150_set_delay(&client->dev, BMA150_DEFAULT_DELAY);
	bma150_set_delay(&client->dev, 100);
	bma150_set_position(&client->dev, CONFIG_SENSORS_BMA150_POSITION_V2);
	bma150_set_threshold(&client->dev, BMA150_DEFAULT_THRESHOLD);

	/* setup driver interfaces */
	INIT_DELAYED_WORK(&bma150->work, bma150_work_func);//初始化工作队列

	err = bma150_input_init(bma150);//设置input的一些事件和注册input
	if (err < 0)
		goto error_1;

	err = sysfs_create_group(&bma150->input->dev.kobj, &bma150_attribute_group);//创建属
	if (err < 0)
		goto error_2;

	err = misc_register(&bma150_misc);//注册杂项设备
	if (err < 0)
		goto error_3;

	bma150_ptr = bma150;

	return 0;

error_3:
	sysfs_remove_group(&bma150->input->dev.kobj, &bma150_attribute_group);
error_2:
	bma150_input_fini(bma150);
error_1:
	kfree(bma150);
error_0:
	return err;
}

static int bma150_remove(struct i2c_client *client)
{
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	bma150_set_enable(&client->dev, 0);

	misc_deregister(&bma150_misc);
	sysfs_remove_group(&bma150->input->dev.kobj, &bma150_attribute_group); 
	bma150_input_fini(bma150);
	kfree(bma150);

	return 0;
}

static int bma150_suspend(struct i2c_client *client, pm_message_t mesg)
{
	struct bma150_data *bma150 = i2c_get_clientdata(client);

	TRACE_FUNC();

	mutex_lock(&bma150->enable_mutex);

	if (bma150_get_enable(&client->dev))
	{
		cancel_delayed_work_sync(&bma150->work);
		bma150_power_down(bma150);
	}
#if DEBUG
	bma150->suspend = 1;
#endif

	mutex_unlock(&bma150->enable_mutex);

	return 0;
}

static int bma150_resume(struct i2c_client *client)
{
	struct bma150_data *bma150 = i2c_get_clientdata(client);
	int delay = atomic_read(&bma150->delay);

	TRACE_FUNC();

	bma150_hw_init(bma150);
	bma150_set_delay(&client->dev, delay);

	mutex_lock(&bma150->enable_mutex);

	if (bma150_get_enable(&client->dev))
	{
		bma150_power_up(bma150);
		schedule_delayed_work(&bma150->work,
				      delay_to_jiffies(delay) + 1);
	}
#if DEBUG
	bma150->suspend = 0;
#endif

	mutex_unlock(&bma150->enable_mutex);

	return 0;
}

static const struct i2c_device_id bma150_id[] =
{
	{BMA150_NAME, 0},
	{},
};

MODULE_DEVICE_TABLE(i2c, bma150_id);

struct i2c_driver bma150_driver =
{
	.driver = {
		.name = "bma150",
		.owner = THIS_MODULE,
	},
	.probe = bma150_probe,
	.remove = bma150_remove,
	.suspend = bma150_suspend,
	.resume = bma150_resume,
	.id_table = bma150_id,
};

/*
 * Module init and exit
 */
static int __init bma150_init(void)
{
	return i2c_add_driver(&bma150_driver);
}
module_init(bma150_init);

static void __exit bma150_exit(void)
{
	i2c_del_driver(&bma150_driver);
}
module_exit(bma150_exit);

MODULE_DESCRIPTION("BMA150 accelerometer driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(BMA150_VERSION);


//所要移植的内容就是在mach-smdkc100.c文件的static struct i2c_board_info i2c_devs2[] __initdata 结构数组里加一项

{
  I2C_BOARD_INFO("bma150", 0x38),
 },

看到这里我都怀疑学驱动有啥用的。。。檫。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值