三轴加速度传感器bma150驱动解析

BMA150 博世 三轴加速度传感器
SPI(4线,3线),i2c,中断引脚
频响+/- 2g,4g,8g;带宽25~1500hz,中断触发内部加速度求值
低功耗,快速唤醒

包含数据寄存器,控制寄存器,状态寄存器,设置寄存器及EEPROM

三轴加速度传感器bma150驱动解析_第1张图片

寄存器读写使用i2c接口,所以需要驱动i2c设备
数据需要获取xyz值,所以可以添加成input设备

用一个bma150_data数据对象来描述整个设备

struct bma150_data {
	struct i2c_client *client;	//i2c 客户端
	struct input_polled_dev *input_polled;	//轮询输入设备
	struct input_dev *input;	//输入设备
	u8 mode;	//记录状态模式
};

如果bma150有中断响应则用输入设备,数据在中断处理完上报
没有则使用轮询输入设备,不断访问数据

bma150的配置信息用一个结构体bma150_cfg去表述

struct bma150_cfg {	//bma150配置
	bool any_motion_int;		/*any-motion 中断*/
	bool hg_int;				/*high-G 中断 */
	bool lg_int;				/*low-G 中断 */
	unsigned char any_motion_dur;	/* Any-motion 持续时间 */
	unsigned char any_motion_thres;	/* Any-motion 阀值 */
	unsigned char hg_hyst;		/* High-G 延迟 */
	unsigned char hg_dur;		/* High-G 持续时间 */
	unsigned char hg_thres;		/* High-G 阀值 */
	unsigned char lg_hyst;		/* Low-G 延迟 */
	unsigned char lg_dur;		/* Low-G 持续时间 */
	unsigned char lg_thres;		/* Low-G 阀值 */
	unsigned char range;		/* 频响 */
	unsigned char bandwidth;	/* 带宽 */
};

三个中断使能值及其中断属性,频响,带宽

驱动i2c设备需要i2c设备驱动及i2c设备
所以板级驱动用I2C_BOARD_INFO("bma150", (0x38))注册i2c设备
内核中bma150.c文件包含bma150芯片的i2c设备驱动
module_i2c_driver(bma150_driver);//声明模块入口出口
加载模块的时候注册bma150对应的i2c设备驱动bma150_driver

static struct i2c_driver bma150_driver = {	//i2c设备驱动
	.driver = {
		.owner	= THIS_MODULE,
		.name	= BMA150_DRIVER,	//"bma150"
		.pm	= &bma150_pm,
	},
	.class		= I2C_CLASS_HWMON,
	.id_table	= bma150_id,	//匹配id表(兼容smb380,bma023)
	.probe		= bma150_probe,	//probe方法
	.remove		= bma150_remove,	//remove方法
};

i2c设备与驱动匹配后会调用驱动的probe方法bma150_probe

static int bma150_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
	const struct bma150_platform_data *pdata = client->dev.platform_data;	//获取bma150平台数据
	const struct bma150_cfg *cfg;	//bma150配置
	struct bma150_data *bma150;	//bma150数据
	int chip_id;
	int error;

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {	//检查i2c适配器性能是否支持
		dev_err(&client->dev, "i2c_check_functionality error\n");
		return -EIO;
	}

	chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);	//获取芯片ID,0x00寄存器
	if (chip_id != BMA150_CHIP_ID) {	//-----010b
		dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
		return -EINVAL;
	}

	bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);	//分配bna150数据内存
	if (!bma150)
		return -ENOMEM;

	bma150->client = client;	//bma150数据捆绑i2c客户端

	if (pdata) {	//存在平台数据?(板级驱动提供)
		if (pdata->irq_gpio_cfg) {	//存在中断gpio配置函数?
			error = pdata->irq_gpio_cfg();	//调用中断gpiio配置函数
			if (error) {
				dev_err(&client->dev,"IRQ GPIO conf. error %d, error %d\n",client->irq, error);
				goto err_free_mem;
			}
		}
		cfg = &pdata->cfg;	//获取bma150配置
	} else {
		cfg = &default_cfg;	//默认bma150配置
	}

	error = bma150_initialize(bma150, cfg);	//bma150初始化--解析1
	if (error)
		goto err_free_mem;

	if (client->irq > 0) {	//存在中断号
		error = bma150_register_input_device(bma150);	//注册输入设备--解析2
		if (error)
			goto err_free_mem;

		error = request_threaded_irq(client->irq,	//请求中断
					NULL, bma150_irq_thread,		//中断回调函数--解析3
					IRQF_TRIGGER_RISING | IRQF_ONESHOT,//上升沿触发|线程函数执行完才会重开中断
					BMA150_DRIVER, bma150);
		if (error) {
			dev_err(&client->dev,"irq request failed %d, error %d\n",client->irq, error);
			input_unregister_device(bma150->input);
			goto err_free_mem;
		}
	} else {	//不中断则轮询
		error = bma150_register_polled_device(bma150);	//注册轮询输入设备--解析4
		if (error)
			goto err_free_mem;
	}

	i2c_set_clientdata(client, bma150);//&client->dev->p->driver_data=bma150
	pm_runtime_enable(&client->dev);

	return 0;

err_free_mem:
	kfree(bma150);
	return error;
}

解析1:bma150初始化

static int bma150_initialize(struct bma150_data *bma150,const struct bma150_cfg *cfg)
{
	int error;

	error = bma150_soft_reset(bma150);	//bma150软复位(0x0a寄存器位1置1)
	if (error)
		return error;

	error = bma150_set_bandwidth(bma150, cfg->bandwidth);	//bma设置带宽(0x14寄存器0~2位)
	if (error)
		return error;

	error = bma150_set_range(bma150, cfg->range);	//bma150设置频响(0x14寄存器3~4位)
	if (error)
		return error;

	if (bma150->client->irq) {	//设置中断触发
		error = bma150_set_any_motion_interrupt(bma150,	//设置any_motion中断(0x0b寄存器6位)
					cfg->any_motion_int,	//(0x15寄存器6位)
					cfg->any_motion_dur,	//(0x11寄存器6,7位)
					cfg->any_motion_thres);	//(0x10寄存器)
		if (error)
			return error;

		error = bma150_set_high_g_interrupt(bma150,	//设置high_g中断
					cfg->hg_int, 	//(0x0b寄存器1位)
					cfg->hg_hyst,	//(0x11寄存器3~5位)
					cfg->hg_dur, 	//(0x0f寄存器)
					cfg->hg_thres);	//(0x0e寄存器)
		if (error)
			return error;

		error = bma150_set_low_g_interrupt(bma150,	//设置low_g中断
					cfg->lg_int, 	//(0x00寄存器0位)
					cfg->lg_hyst,	//(0x11寄存器0~2位)
					cfg->lg_dur, 	//(0x0D寄存器)
					cfg->lg_thres);	//(0x0C寄存器)
		if (error)
			return error;
	}
	//(0x15寄存器0位,0x0a寄存器0位)
	return bma150_set_mode(bma150, BMA150_MODE_SLEEP);	//设置睡眠唤醒模式
}

解析2:注册输入设备

static int bma150_register_input_device(struct bma150_data *bma150)
{
	struct input_dev *idev;
	int error;

	idev = input_allocate_device();	//分配输入设备内存
	if (!idev)
		return -ENOMEM;

	bma150_init_input_device(bma150, idev);	//初始化输入设备--2.1

	idev->open = bma150_irq_open;	//设置打开方法
	idev->close = bma150_irq_close;	//设置关闭方法
	input_set_drvdata(idev, bma150);	//&idev->dev->p->driver_data=bma150

	error = input_register_device(idev);	//注册输入设备
	if (error) {
		input_free_device(idev);
		return error;
	}

	bma150->input = idev;	//捆绑输入设备
	return 0;
}

2.1初始化输入设备

static void bma150_init_input_device(struct bma150_data *bma150,struct input_dev *idev)
{
	idev->name = BMA150_DRIVER;
	idev->phys = BMA150_DRIVER "/input0";
	idev->id.bustype = BUS_I2C;
	idev->dev.parent = &bma150->client->dev;

	idev->evbit[0] = BIT_MASK(EV_ABS);	//绝对位移事件
	input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);//x轴位移	
	input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);//y轴位移
	input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);//z轴位移
}

解析3:中断回调函数

static irqreturn_t bma150_irq_thread(int irq, void *dev)
{
	bma150_report_xyz(dev);	//上报事件数据--3.1

	return IRQ_HANDLED;
}

3.1上报事件数据

static void bma150_report_xyz(struct bma150_data *bma150)
{
	u8 data[BMA150_XYZ_DATA_SIZE];
	s16 x, y, z;
	s32 ret;
	//(0x02~0x07寄存器获取xyz轴数据)
	ret = i2c_smbus_read_i2c_block_data(bma150->client,BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data);
	if (ret != BMA150_XYZ_DATA_SIZE)
		return;

	x = ((0xc0 & data[0]) >> 6) | (data[1] << 2);//x轴数据
	y = ((0xc0 & data[2]) >> 6) | (data[3] << 2);//y轴数据
	z = ((0xc0 & data[4]) >> 6) | (data[5] << 2);//z轴数据

	/* sign extension */
	x = (s16) (x << 6) >> 6;
	y = (s16) (y << 6) >> 6;
	z = (s16) (z << 6) >> 6;

	input_report_abs(bma150->input, ABS_X, x);//上报x轴数据
	input_report_abs(bma150->input, ABS_Y, y);//上报y轴数据
	input_report_abs(bma150->input, ABS_Z, z);//上报z轴数据
	input_sync(bma150->input);//同步数据
}

解析4:注册轮询输入设备

static int bma150_register_polled_device(struct bma150_data *bma150)
{
	struct input_polled_dev *ipoll_dev;
	int error;

	ipoll_dev = input_allocate_polled_device();	//分配轮询输入设备内存
	if (!ipoll_dev)
		return -ENOMEM;

	ipoll_dev->private = bma150;//私有数据位bma150数据
	ipoll_dev->open = bma150_poll_open;	//设置打开方法
	ipoll_dev->close = bma150_poll_close;	//设置关闭方法
	ipoll_dev->poll = bma150_poll;	//设置轮询方法
	ipoll_dev->poll_interval = BMA150_POLL_INTERVAL;	//设置轮询时间戳
	ipoll_dev->poll_interval_min = BMA150_POLL_MIN;
	ipoll_dev->poll_interval_max = BMA150_POLL_MAX;

	bma150_init_input_device(bma150, ipoll_dev->input);	//初始化bma150输入设备--4.1

	error = input_register_polled_device(ipoll_dev);	//注册轮询输入设备
	if (error) {
		input_free_polled_device(ipoll_dev);
		return error;
	}

	bma150->input_polled = ipoll_dev;//bma150数据捆绑轮询输入设备
	bma150->input = ipoll_dev->input;//bma150数据的输入设备指向轮询输入设备的输入设备

	return 0;
}

4.1 初始化bma150输入设备

static void bma150_init_input_device(struct bma150_data *bma150,struct input_dev *idev)
{
	idev->name = BMA150_DRIVER;
	idev->phys = BMA150_DRIVER "/input0";
	idev->id.bustype = BUS_I2C;
	idev->dev.parent = &bma150->client->dev;

	idev->evbit[0] = BIT_MASK(EV_ABS);	//绝对位移事件
	input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);//x轴位移	
	input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);//y轴位移
	input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);//z轴位移
}

解析5 输入设备打开关闭方式
打开

static int bma150_open(struct bma150_data *bma150)
{
	int error;

	error = pm_runtime_get_sync(&bma150->client->dev);
	if (error < 0 && error != -ENOSYS)
		return error;

	/*
	 * See if runtime PM woke up the device. If runtime PM
	 * is disabled we need to do it ourselves.
	 */
	if (bma150->mode != BMA150_MODE_NORMAL) {
		error = bma150_set_mode(bma150, BMA150_MODE_NORMAL);//设置正常模式
		if (error)
			return error;
	}

	return 0;
}

关闭

static void bma150_close(struct bma150_data *bma150)
{
	pm_runtime_put_sync(&bma150->client->dev);

	if (bma150->mode != BMA150_MODE_SLEEP)
		bma150_set_mode(bma150, BMA150_MODE_SLEEP);//设置睡眠模式
}

打开关闭bma150都调用bma150_set_mode函数来设置模式

static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
{
	int error;

	error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS,
				BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG);//(0x15寄存器0位)
	if (error)
		return error;

	error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS,
				BMA150_SLEEP_MSK, BMA150_SLEEP_REG);//(0x0a寄存器0位)
	if (error)
		return error;

	if (mode == BMA150_MODE_NORMAL)
		msleep(2);

	bma150->mode = mode;	//记录住模式
	return 0;
}










你可能感兴趣的:(linux,传感器)