mma7660(gsensor)的hwmon驱动

本文详细介绍了Linux内核中mma7660 gsensor驱动的设计与实现,包括驱动设计要求、I2C总线配置、硬件连接和驱动流程。内容涵盖gsensor如何通过I2C与输入子系统交互,创建工作队列读取传感器数据,并通过sysfs接口注册到Input子系统,以及驱动调试方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

gsensor驱动在系统中的层次如下图所示:

[转载]linux <wbr>Gsensor驱动(bma250为例子)

图中包含三个部分:hardware, driver, input

n         Hardware:其实我们可以认为Gsensor也是一个I2C设备。整个Gsensor芯片分为两部分,一个是sensor传感器,另一个是controller控制器,用于将sensor挂载在linux系统的I2C上。驱动程序则通过I2CGsensor做通信。

n         Gsensor Driver:是驻留于操作系统中,为gsensor hardware服务的一个内核模块;它将gsensor hardware采集到的原始数据,进行降噪,滤波,获得当前平板的空间状态,并按照操作系统的要求,将这些信息通过input core上报给操作系统。

n         Input core: linux为简化设备驱动程序开发,而开发的一个内核子系统;发给input core的数据将提供给操作系统使用。

实际使用时,驱动按照一定的时间间隔,通过数据总线,获取gsensor hardware采集到的数据,并按照操作系统的要求,将这些信息通过input core上报给操作系统。

2 Gsensor驱动设计要求

gsensor驱动在系统中的层次,上有Input core,下有I2C,驱动需要通过I2C采集信息,并准确及时的上报数据至input core。驱动上报的数据,是被input core管理并被上层使用的,应符合input core和上层应用框架的要求;

2.1符合Input输入子系统的设计规范

接口:Gsensor驱动,在设计上,不应自行决定是否上报,上报频率等,应提供接口,供上层应用控制驱动的运行和数据上报:包括使能控制Enable 上报时延delay等;通常通过sysfs文件系统提供,这部分实现,遵循标准的linux规范;

上报数据的方式:或者提供接口供上层访问(eg: ioctl),或者挂接在系统子系统上,使用系统子系统的接口,供上层使用(eg: input core)

读取数据的支持:应满足读取数据的要求,进行相应的配置;i2c总线为例,简要说明在tiny4412平台上,配置总线传输相关信息;

2.2 I2c总线的配置

要使用i2c总线进行数据传输,需注册i2c driver,创建i2c-client,以便使用i2c-adapter进行数据传输;

要成功注册i2c driver有两种方式:

n         使用i2c_register_board_info:此方式,需要在系统启动时,进行相关信息的注册,不利于模块化开发,现已不推荐;目前,在2.6内核上,还支持此方式,在3.0上已不再支持;

n         使用detect方式:在模块加载时,进行检测,在条件成立时,注册i2c设备相关信息,创建i2c-client,并注册i2c driver,执行probe操作;

 

需要说明的是,此两种方式可共存,目前2.6就是这样的;在共存时,以i2c_register_board_info信息为更高优先级,在i2c_register_board_info已经占用设备的前提下,内核发现设备被占用,不会执行detect, 因而不会有冲突。

3 gsensor模块硬件说明

n         gsensor硬件,负责获取gsensor传感器所处的空间状态信息,存放于fifo中,供主控使用,不同的硬件平台,数据准备好后,告知主控的方式及主控获取数据的方式略有不同。

n         告知主控的方式:gsensor作为传感器,本身无法区分哪些数据是应该上报的,哪些数据是无效的,它只能接受主控的控制,以主控主动查询为主;

n         主控获取数据的方式:通过ahb, i2c, spi,usb等方式获取都是可能的。以下以一种典型的硬件连接为例,描述gsensor 传感器,gsensor ic, 主控之间的连接关系;

3.1 gsensor硬件连接

[转载]linux <wbr>Gsensor驱动(bma250为例子)

Gsensor在硬件上,只有i2c连接,这些连接信息,需要事先告知驱动,从而从指定的设备上读取数据;这些连接信息,通过sysconfig1描述,在驱动中使用;

4.2:mma7660平台资源数据(gsensor的配置):

static struct mma7660_platform_data mma7660_pdata = {
.irq = IRQ_EINT(25),
.poll_interval= 100,   // * @poll_interval: specifies how often the poll() method should be called.
  //*Defaults to 500 msec unless overridden when registering the device.

.input_fuzz= 4,
.input_flat = 4,
};

static struct i2c_board_info smdk4x12_i2c_devs3[] __initdata = {
#ifdef CONFIG_SENSORS_MMA7660
{
I2C_BOARD_INFO("mma7660", 0x4c),  //0x4c is in datasheet. is slave address
.platform_data = &mma7660_pdata,
},
#endif
};

4.3关键数据结构

4.3.1   i2c_driver

static const struct i2c_device_id mma7660_ids[] = {
{ "mma7660", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, mma7660_ids);


static struct i2c_driver i2c_mma7660_driver = {
.driver = {
.name = MMA7660_NAME,
},


.probe = mma7660_probe,
.remove = __devexit_p(mma7660_remove),
.suspend = mma7660_suspend,
.resume = mma7660_resume,
.id_table = mma7660_ids,
};

5 驱动流程解析

5.1模块加载

static int __init init_mma7660(void)
{
int ret;
ret = i2c_add_driver(&i2c_mma7660_driver);
printk(KERN_INFO "MMA7660 sensor driver registered.\n");
return ret;
}
static void __exit exit_mma7660(void)
{
i2c_del_driver(&i2c_mma7660_driver);
printk(KERN_INFO "MMA7660 sensor driver removed.\n");
}


调用i2c_add_driver开始向IIC注册driver,完成注册后将调用mma7660_probe()方法

static int __devinit mma7660_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct input_dev *idev;
int poll_interval = POLL_INTERVAL;
int input_fuzz = INPUT_FUZZ;
int input_flat = INPUT_FLAT;
int ret;

ret = i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA);
if (!ret) {
dev_err(&client->dev, "I2C check functionality failed\n");
return -ENXIO;
}

plat_data = (struct mma7660_platform_data *)client->dev.platform_data;
if (plat_data == NULL) {
dev_err(&client->dev, "lack of platform data!\n");
return -ENODEV;
}

/* Get parameters from platfrom data */
if (plat_data->poll_interval > 0)
poll_interval = plat_data->poll_interval;
if (plat_data->input_fuzz > 0)
input_fuzz = plat_data->input_fuzz;
if (plat_data->input_flat > 0)
input_flat = plat_data->input_flat;

if (mma7660_initialize(client) < 0) {
goto error_init_client;
}

ret = sysfs_create_group(&client->dev.kobj, &mma7660_group);   ////创建sysfs接口
if (ret) {
dev_err(&client->dev, "create sysfs group failed!\n");
goto error_init_client;
}

/* register to hwmon device */
hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(hwmon_dev)) {
dev_err(&client->dev, "hwmon register failed!\n");
ret = PTR_ERR(hwmon_dev);
goto error_rm_dev_file;
}

/* input poll device register */
mma7660_idev = input_allocate_polled_device();  //申请一个新的input设备,即为一个input_dev申请内存空间
if (!mma7660_idev) {
dev_err(&client->dev, "alloc poll device failed!\n");
ret = -ENOMEM;
goto error_rm_hwmon_dev;
}

mma7660_idev->poll = mma7660_dev_poll;   //相当于select函数
mma7660_idev->poll_interval = plat_data->poll_interval; //每个多长时间调用一次poll函数
//input_dev
idev = mma7660_idev->input;
idev->name = MMA7660_NAME;
idev->id.bustype = BUS_I2C;
idev->id.vendor = 0x12FA;
idev->id.product = 0x7660;
idev->id.version = 0x0100;`
idev->dev.parent = &client->dev;
//EV_ABS表示支持绝对值坐标,后面都是针对这些坐标的一些参数访问范围设置
//设置idev->evbit中的相应位让它支持绝对值坐标
//表示该设备所支持的事件。在这里将其EV_SYN置位,即所有设备都支持这个事件

//分别用来设置设备所产生的事件以及上报的按键值。Struct iput_dev中有两个成员,一个是evbit.一个是keybit,分别用表示设备所支持的动作和按键类型
set_bit(EV_ABS, idev->evbit);
set_bit(ABS_X, idev->absbit);
set_bit(ABS_Y, idev->absbit);
set_bit(ABS_Z, idev->absbit);
//表示支持绝对值x坐标,并设置它在坐标系中的最大值和最小值,以及干扰值和平焊位置等

//设置input设备支持的数据类型

//input_set_abs_params(idev, ABS_X, -512, 512, input_fuzz, input_flat);

input_set_abs_params(idev, ABS_Y, -512, 512, input_fuzz, input_flat);
input_set_abs_params(idev, ABS_Z, -512, 512, input_fuzz, input_flat); //表示z轴的范围是-512到512,数据误差范围(漂移最好通过其他传感器动态补偿)为input_fuzz,中心平滑位置(零偏一般静态补偿)为input_flat.

{

input_set_abs_params(button_dev, ABS_X, 0, 255, 4, ;
This setting would be appropriate for a joystick X axis, with the minimum of
0, maximum of 255 (which the joystick *must* be able to reach, no problem if
it sometimes reports more, but it must be able to always reach the min and
max values), with noise in the data up to +- 4, and with a center flat
position of size 8.

If you don't need absfuzz and absflat, you can set them to zero, which mean
that the thing is precise and always returns to exactly the center position
(if it has any).
这是Documentation里面对该函数的举例说明

}

ret = input_register_polled_device(mma7660_idev);   //Input子系统注册轮询设备
if (ret) {
dev_err(&client->dev, "register poll device failed!\n");
goto error_free_poll_dev;
}
/* register interrupt handle */
ret = request_irq(plat_data->irq, mma7660_interrupt,
IRQF_TRIGGER_FALLING, MMA7660_NAME, idev);
if (ret) {
dev_err(&client->dev, "request irq (%d) failed %d\n", plat_data->irq, ret);
goto error_rm_poll_dev;
}
dev_info(&client->dev, "MMA7660 device is probed successfully.\n");
#if 0
set_mod(1);
#endif
return 0;
error_rm_poll_dev:
input_unregister_polled_device(mma7660_idev);
error_free_poll_dev:
input_free_polled_device(mma7660_idev);
error_rm_hwmon_dev:
hwmon_device_unregister(hwmon_dev);
error_rm_dev_file:
sysfs_remove_group(&client->dev.kobj, &mma7660_group);
error_init_client:
mma7660_client = NULL;
return 0;
}

驱动框架:

-构建i2c_dricer

-将i2c_driver注册到系统中

-实现i2c_driver中的probe函数

-在probe中注册input_polled_dev

-实现input_polled_dev中的poll函数

-在poll函数中读取加速度传感器的数值并提交给上层

-在poll开启工作队列,每隔一段时间读取加速度传感器的数值并提交给上层


-s

5.2.2 初始化工作队列

先提一个问题,为什么要创建工作队列?在前面的介绍中我们知道,sensor传感器获取数据后,将数据传给controller的寄存器中,供主控去查询读取数据。所以这里创建的工作队列,就是在一个工作者线程,通过IIC不断的去查询读取controller上的数据。

工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是如果写了一个函数,而现在不想马上执行它,想在将来某个时刻去执行它,那用工作队列准没错.大概会想到中断也是这样,提供一个中断服务函数,在发生中断的时候去执行,没错,和中断相比,工作队列最大的好处就是可以调度可以睡眠,灵活性更好。

上面代码中我们看到DECLARE_WORK(mma7660_work, mma7660_worker);,其实是一个宏的定义,在include/linux/workqueue.h中。mma7660_worker()就是我们定义的功能函数,用于查询读取Sensor数据的,并上报Input子系统,代码如下:

static void mma7660_worker(struct work_struct *work)
{
int bafro, pola, shake, tap;
int val = 0;
mma7660_read_tilt(mma7660_client, &val);
/* TODO: report it ? */
bafro = val & 0x03;
if (bafro != (last_tilt & 0x03)) {
printk("%s\n", mma7660_bafro[bafro]);
}
pola = (val >> 2) & 0x07;
if (pola != ((last_tilt >> 2) & 0x07)) {
printk("%s\n", mma7660_pola[pola]);
}
shake = (val >> 5) & 0x01;
if (shake && shake != ((last_tilt >> 5) & 0x01)) {
printk("Shake\n");
}
tap = (val >> 7) & 0x01;
if (tap && tap != ((last_tilt >> 7) & 0x01)) {
printk("Tap\n");
}
/* Save current status */
last_tilt = val;
}


我们调用INIT_DELAYED_WORK()宏初始化了工作队列之后,那么什么时候将执行我们定义的功能函数mma7660_worker()呢?那么只需要调用schedule_work()即可执行功能函数。
在驱动设计中,我们在
Sensor使能函数中调用schedule_work()开始启动工作队列

5.2.3input系统注册

Gsensor作为一个输入设备,按照linux设计标准,需要将Gsensor驱动注册到Input子系统中,注册代码如下:

mma7660_idev = input_allocate_polled_device();  //申请一个新的input设备,即为一个input_dev申请内存空间
if (!mma7660_idev) {
dev_err(&client->dev, "alloc poll device failed!\n");
ret = -ENOMEM;
goto error_rm_hwmon_dev;
}

mma7660_idev->poll = mma7660_dev_poll;
mma7660_idev->poll_interval = plat_data->poll_interval;
//input_dev
idev = mma7660_idev->input;
idev->name = MMA7660_NAME;
idev->id.bustype = BUS_I2C;
idev->id.vendor = 0x12FA;
idev->id.product = 0x7660;
idev->id.version = 0x0100;`
idev->dev.parent = &client->dev;
//EV_ABS表示支持绝对值坐标,后面都是针对这些坐标的一些参数访问范围设置
//设置idev->evbit中的相应位让它支持绝对值坐标
//表示该设备所支持的事件。在这里将其EV_SYN置位,即所有设备都支持这个事件
set_bit(EV_ABS, idev->evbit);
set_bit(ABS_X, idev->absbit);
set_bit(ABS_Y, idev->absbit);
set_bit(ABS_Z, idev->absbit);
//表示支持绝对值x坐标,并设置它在坐标系中的最大值和最小值,以及干扰值和平焊位置等

//设置input设备支持的数据类型

//         input_set_abs_params(idev, ABS_X, -512, 512, input_fuzz, input_flat);

input_set_abs_params(idev, ABS_Y, -512, 512, input_fuzz, input_flat);
input_set_abs_params(idev, ABS_Z, -512, 512, input_fuzz, input_flat);
ret = input_register_polled_device(mma7660_idev);   //Input子系统注册轮询设备
if (ret) {
dev_err(&client->dev, "register poll device failed!\n");
goto error_free_poll_dev;
}

就是由上面的代码,完成了Gsensor驱动向Input子系统注册,又三个步骤:

n         申请一个新的input设备,即为一个input_dev申请内存空间

n         设置input设备支持的数据类型

n         input系统注册

5.2.4 创建sysfs 接口

为什么要创建sysfs接口?在驱动层创建了sysfs接口,HAL层通过这些sysfs接口,对Sensor进行操作,如使能、设置delay等。

5.2.4.1 sysfs接口函数的建立SENSOR_DEVICE_ATTR

说道sysfs接口,就不得不提到函数宏 DEVICE_ATTR,原型在<include/linux/device.h> 

#define DEVICE_ATTR(_name, _mode, _show, _store)

struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

函数宏DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法:

n         _show:表示的是读方法,

n         _stroe表示的是写方法。

当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等:

n         对设备的使用         DEVICE_ATTR   

n         对驱动使用               DRIVER_ATTR

n         对总线使用               BUS_ATTR 

n         对类别 (class) 使用  CLASS_ATTR

对于DEVICE_ATTR(_name, _mode, _show, _store)的四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。

如果你完成了DEVICE_ATTR函数宏的填充,下面就需要创建接口了。例如如下:

1)         

 static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR, show_polling, set_polling);
    static struct attribute *dev_attrs[] = {
            &dev_attr_polling.attr,
            NULL,
    };

 

   

2)        当你想要实现的接口名字是polling的时候,需要实现结构体struct attribute *dev_attrs[]。其中成员变量的名字必须是&dev_attr_polling.attr。然后再封装:

         static struct attribute_group dev_attr_grp = {
            .attrs = dev_attrs,
        };

3)        在利用sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);创建接口

       通过以上简单的三个步骤,就可以在adb shell 终端查看到接口了。当我们将数据 echo 到接口中时,在上层实际上完成了一次 write 操作,对应到 kernel ,调用了驱动中的 “store”。同理,当我们cat 一个 接口时则会调用 “show” 。到这里,只是简单的建立了 android 层到 kernel 的桥梁,真正实现对硬件操作的,还是在 "show"  "store" 中完成的。

5.2.4.2 bma250驱动sysfs接口建立

Bma250驱动sysfs接口建立,按照5.2.4.1上面介绍的三个步骤来实现。

n         调用宏DEVICE_ATTR完成对功能函数的注册

    static SENSOR_DEVICE_ATTR(registers, S_IRUGO | S_IWUGO,
mma7660_show_regs, mma7660_write_reg, 0);
static SENSOR_DEVICE_ATTR(x_axis_g, S_IRUGO, mma7660_show_axis_g, NULL, 0);
static SENSOR_DEVICE_ATTR(y_axis_g, S_IRUGO, mma7660_show_axis_g, NULL, 1);
static SENSOR_DEVICE_ATTR(z_axis_g, S_IRUGO, mma7660_show_axis_g, NULL, 2);
static SENSOR_DEVICE_ATTR(all_axis_g, S_IRUGO, mma7660_show_xyz_g, NULL, 0);
static SENSOR_DEVICE_ATTR(tilt_status, S_IRUGO, mma7660_show_tilt, NULL, 0);


static struct attribute* mma7660_attrs[] = {
&sensor_dev_attr_registers.dev_attr.attr,
&sensor_dev_attr_x_axis_g.dev_attr.attr,
&sensor_dev_attr_y_axis_g.dev_attr.attr,
&sensor_dev_attr_z_axis_g.dev_attr.attr,
&sensor_dev_attr_all_axis_g.dev_attr.attr,
&sensor_dev_attr_tilt_status.dev_attr.attr,
NULL
};


static const struct attribute_group mma7660_group = {
.attrs = mma7660_attrs,
};

n         封装mma7660_group 数据结构   对于mma7660 Gsensor,我们需要用到的接口是对Gsensor设置和读取各种状态数据(x,y,z,斜度等)。设置的功能函数——读、写分别是mma7660_show_regsmma7660_write_regs

static const struct attribute_group mma7660_group = {
.attrs= mma7660_attrs,
};

n         真正创建接口

mma7660的初始化函数probe中——mma7660_probe(),调用:

ret = sysfs_create_group(&client->dev.kobj, &mma7660_group);

到此,完成了sysfs接口的创建,我们可以在根文件系统中看到/sys/class/input/input1/device目录,在该目录下我们可以看到多个节点,其中就包含了registers,tilt_status,y_axis_g,x_axis_g,z_axis_g,all_axis_g。我们以registers为例子,可以有两种方法完成对Gsensor的使能工作:

1)        直接使用shell命令

$cd /sys/class/input/input3/device

$echo 1 > registers

1写到enable节点,那么将“1”作为参数调用到驱动的mma7660_write_reg()方法,完成对Gsensor的设置工作。

2)        代码写设备节点

char buffer[20];

int len = sprintf(buffer, "%dn", 1);

fd =open(“/sys/class/input/input1/device/registers”, O_RDWR);

write(fd, value, len)

 在/sys/class/i2c-adapter/i2c-3/3-004c下也可找到其应用层接口

5.3 读取并上报数据

static ssize_t mma7660_show_regs(struct device *dev,
struct device_attribute *attr, char *buf)
{
int reg, val;
int i, len = 0;
       for (reg = 0; reg < 0x0b; reg++) {
val = i2c_smbus_read_byte_data(mma7660_client, reg);
len += sprintf(buf + len, "REG: 0x%02x = 0x%02x ...... [ ", reg, val);
for (i = 7; i >= 0; i--) {
len += sprintf(buf + len, "%d", (val >> i) & 1);
if ((i % 4) == 0) {
len += sprintf(buf + len, " ");
}
}
len += sprintf(buf + len, "]\n");
}
       return len;
}
static ssize_t mma7660_write_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned int reg, val;
int ret;
       ret = sscanf(buf, "%x %x", &reg, &val);
if (ret == 2) {
if (reg >= 0 && reg <= 0x0a) {
i2c_smbus_write_byte_data(mma7660_client, reg, val);
val = i2c_smbus_read_byte_data(mma7660_client, reg);
printk("REG: 0x%02x = 0x%02x\n", reg, val);
}
}
      return count;
}
/*-----------------------------------------------------------------------------
 * Input interfaces
 */
static void mma7660_report_abs(void)
{
int axis[3];
int i;


for (i = 0; i < 3; i++) {
mma7660_read_xyz(mma7660_client, i, &axis[i]);//读取数据
}


input_report_abs(mma7660_idev->input, ABS_X, axis[0]); //上报数据
input_report_abs(mma7660_idev->input, ABS_Y, axis[1]);
input_report_abs(mma7660_idev->input, ABS_Z, axis[2]);
input_sync(mma7660_idev->input);   //同步用于告诉input core子系统报告结束
//printk("3-Axis ... %3d, %3d, %3d\n", axis[0], axis[1], axis[2]);
}

static void mma7660_dev_poll(struct input_polled_dev *dev)
{
mma7660_report_abs();
}

6 驱动调试

1)确保硬件各个管脚的连接顺序正确;

2)上电,测试各个管脚信号的电压正常,只有在保证硬件正常的情况下,进行软件驱动调试,方可保证驱动能够正常工作(该处最容易被很多软件开发人员忽视,务必注意,方可节省大部分时间)

3)将串口打印信息打开,串口打印信息设置:在打包工具中的 crane-win-v2wbootbootfslinux目录下的paramsparamsr两个文件中的语句的最后加入loglevel=9即可。gsensor驱动中所有的打印信息打开,查看驱动程序的配置信息读取状态以及I2C的初始化状态。

4)查看probe是否成功,如probe不成功,根据打印信息定位驱动的运行情况,是因为什么原因导致失败。

5)当probe成功之后,gsensor没反应,查看打印信息,是否enable,确保enable

6)查看i2c通信状态,当串口打印信息显示i2C通信失败时,主要有以下两个原因,一是硬件上的,各个信号线接触不良,所以出现通信失败时,检查各引脚接触情况和电压情况。二是因为I2C的地址不正确导致,因为i2C地址为7位地址,所以可能是因为在配置的时候没有移位或者是主控IC有多个I2C地址,导致地址不匹配。在已知i2C地址的情况下,可以通过尝试的方法,进行I2C地址的匹配;在不知道I2C地址的情况下,可以通过扫描的方法查看在哪一个地址时,有应答,即可知道I2C通信地址,在将正确的地址填写sysconfig配置文件中即扫描i2c地址的示例代码如下所示:

static int goodix_iic_test(struct i2c_client * client)

{

       struct i2c_msg msg;

       int ret=-1;

       uint8_t data[0];

       int i;

       for(i =0; i<256;i++)

       {

       msg.flags = !I2C_M_RD;//写消息

       msg.addr = i;

       msg.len = 1;

       msg.buf = data;                  

      

       ret=i2c_transfer(client->adapter, &msg,1);

       if(ret == 1)

       {

         printk("IIC TEST OK addr = %xn",i);

         break;

       }

       mdelay(1000);

    }

       return ret;

}

 

 

若以上两种方法都不能正确进行i2c传输,则打开i2c传输打印,查看传输打印状态, 在编译服务器上,目录为workspaceexdroidlicheelinux-2.6.36上,输入命令:

make ARCH=arm menuconfig 选择Device Drivers->I2C support->I2C Hardware Bus support->SUN4I_IIC_PRINT_TRANSFER_INFO,输入Y进入bus num id(accepatable input:0,1,2)(new),输入数值,,若希望打印信息,数值对应相应的IIC号,gsensorIC用的是第二组,因此选择数值为2,若不希望打印信息,输入N退出保存即可。进行修改后,需要重新编译打包之后才能生效。

[转载]linux <wbr>Gsensor驱动(bma250为例子)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值