BMA150 博世 三轴加速度传感器
SPI(4线,3线),i2c,中断引脚
频响+/- 2g,4g,8g;带宽25~1500hz,中断触发内部加速度求值
低功耗,快速唤醒
包含数据寄存器,控制寄存器,状态寄存器,设置寄存器及EEPROM
寄存器读写使用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;
}