带MPU9250的飞思卡尔IMX6 [英] freescale imx6 with mpu9250

查看:237
本文介绍了带MPU9250的飞思卡尔IMX6的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Freescale imx6 SoC与mpu92/65传感器设备接口. 我已经从android( https://github.com/NoelMacwan/Kernel-10.4.1.B.0.101/tree/master/drivers/staging/iio/imu ),并已对驱动程序和设备进行了必要的修改树.

I am trying to interface freescale imx6 SoC with mpu92/65 sensor device. I have taken mpu92/65 device driver from android (https://github.com/NoelMacwan/Kernel-10.4.1.B.0.101/tree/master/drivers/staging/iio/imu ) and have done necessary modifications to the driver and device tree.

设备树修改:

&i2c3{
...
    extaccelerometer: mpu9250@68{
        compatible = "mpu9250";
        reg = <0x68>;
        interrupt-parent = <&gpio2>;
        interrupts = <9>;
        int_config  = /bits/ 8 <0x00>;
        level_shifter = /bits/ 8 <0>;
        orientation = [ 01 00 00 00 01 00 00 00 01 ];
        sec_slave_type = <2>;
        sec_slave_id = <0x12>;
        secondary_i2c_addr = /bits/ 16 <0x0C>;
        secondary_orientation = [ 00 01 00 ff 00 00 00 00 01 ];
    };
}

inv_mpu_iio驱动程序修改:

inv_mpu_iio driver modifications:

static void get_platdata(struct device *dev, struct inv_mpu_iio_s *st){
    struct device_node *np = dev->of_node;
    int i=0;
     of_property_read_u8(np, "int_config", &st->plat_data.int_config);
     of_property_read_u8(np, "level_shifter", &st->plat_data.level_shifter);
     of_property_read_u8_array(np, "orientation", &st->plat_data.orientation,9);
     of_property_read_u32(np, "sec_slave_type", &st->plat_data.sec_slave_type);
     of_property_read_u32(np, "sec_slave_id", &st->plat_data.sec_slave_id);
     of_property_read_u16(np, "secondary_i2c_addr", &st->plat_data.secondary_i2c_addr);
     of_property_read_u8_array(np, "secondary_orientation", &st->plat_data.secondary_orientation,9);
}

static int inv_mpu_probe(struct i2c_client *client,
    const struct i2c_device_id *id)
{
.....
    if (client->dev.of_node) {
        get_platdata(&client->dev, st);
    } else {
        st->plat_data =    *(struct mpu_platform_data *)dev_get_platdata(&client->dev);   
     }
.....
}

我已经以上述方式从设备树中检索了平台数据.在探测功能中,我得到了client->irq=0.但是我在设备树中提到了IRQ.请有人能告诉我我还需要做些什么来提及gpio2-9(Linux垫)作为此i2c设备的中断线.

I have retrieved the platform data from device tree in the above manner. In probe function I am getting client->irq=0. But I have mentioned about the IRQ in the device tree. Please can someone tell me what else I need to do to mention gpio2-9 (linux pad) as an interrupt line for this i2c device.

0x68是i2c设备的从设备地址.驱动程序探针功能正在尝试写入设备以初步验证芯片类型.因此,从站的数据和地址将发送到适配器驱动程序,在适配器驱动程序中,启动功能将在控制和状态寄存器中成功执行读写操作.

0x68 is the slave address of the i2c device. Driver probe functionality is trying to write on to the device for verifying the chip type initially. So the data and the address of the slave is sent to the adapter driver where in the adapter driver start function writes onto and reads from control and status registers is successfully executed.

static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
{
    unsigned int temp = 0;
    int result;

    dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);

    i2c_imx_set_clk(i2c_imx);

    result = clk_prepare_enable(i2c_imx->clk);
    if (result)
        return result;
    imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR,__func__);
    /* Enable I2C controller */
    imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR,__func__);
    imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR,__func__);

    /* Wait controller to be stable */
    udelay(50);

    /* Start I2C transaction */
    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
    temp |= I2CR_MSTA;
    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR,__func__);
    result = i2c_imx_bus_busy(i2c_imx, 1);
    if (result)
        return result;
    i2c_imx->stopped = 0;

    temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
    temp &= ~I2CR_DMAEN;
    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR,__func__);
    return result;
}

然后适配器驱动程序写入数据寄存器

Then the adapter driver writes on to the data register

imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR,__func__);

此后,将生成适配器中断(总线中断的i2c3:291).

After this the adapter interrupt is generated ( bus interrupt got i2c3: 291).

static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
{
    struct imx_i2c_struct *i2c_imx = dev_id;
    unsigned int temp;
    printk("irq:%d\n",irq);
    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
    if (temp & I2SR_IIF) {
        /* save status register */
        i2c_imx->i2csr = temp;
        temp &= ~I2SR_IIF;
        printk("temp=%d\n",temp);
        temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR,__func__);
        wake_up(&i2c_imx->queue);
        return IRQ_HANDLED;
    }

    return IRQ_NONE;
}

在读取状态寄存器后的ISR中,该值应为162(最后一位应为0以表示已确认),但是对于我的设备,我将得到该值作为163(最后一位为1,因此不是)确认).然后在确认成功函数-EIO中引发错误.对于连接到该总线的所有其他设备,写入数据寄存器后的状态寄存器为162.

In ISR after reading status register the value should be 162 (last bit should be 0 to indicate acknowledged) but for my device I am getting this value as 163 (last bit is 1 so it is not acknowledged). Then in acknowledge success function -EIO error is thrown. For all the other device connected to this bus the status register after writing onto the data register is 162.

我不知道为什么会出现上述行为.还有一件事是,即使我不连接设备,启动功能也能够写入状态寄存器和控制寄存器并从中读取数据.我不确定正在读取和写入哪个状态寄存器.如果我假设这读写适配器寄存器,那么我也可以假设适配器硬件自动在连接的设备上读写.如果是这样,那么如果我不连接设备,怎么会出现相同的行为?

I don't know why I am getting the above behavior. And one more thing is that even if I don't connect the device the start function is able to write into and read from the status and control registers. I am not sure which status register is being read and writing into. If I assume that this writes and reads the adapter registers, then can I also assume that the adapter h/w automatically reads and writes onto the device connected. If so then how am I getting the same behavior if I don't connect the device?

请帮帮我.

推荐答案

在探测功能中,我正在获取client->irq=0.但是我在设备树中提到了IRQ.请有人能告诉我我还需要做些什么来提及gpio2-9(Linux垫)作为此i2c设备的中断线.

In probe function I am getting client->irq=0. But I have mentioned about the IRQ in the device tree. Please can someone tell me what else I need to do to mention gpio2-9 (linux pad) as an interrupt line for this i2c device.

interrupts属性的错误定义

您的interrupts定义似乎不正确:

Wrong definition of interrupts property

Your interrupts definition seems incorrect:

interrupts = <9>;

它应为两个单元格"格式(请参见

It should be in "two cells" format (see Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for details).

我运行了下一条命令:

$ find arch/arm/boot/dts/ -name '*imx6*' -exec grep -Hn interrupt {} \; | grep cell

我看到大多数imx6 SoC具有用于GPIO中断的两单元格式. 因此,您对interrupts的定义应如下所示::

and I see that most of imx6 SoCs have two-cell format for GPIO interrupts. So your definition of interrupts should look like that:

interrupts = <9 IRQ_TYPE_EDGE_FALLING>;

或者如果您的内核版本仍然没有IRQ类型的命名常量:

or if your kernel version still doesn't have named constants for IRQ types:

interrupts = <9 2>;

请参考数据表或MPU9250的驱动程序代码IRQ(下降/上升)的类型.

Refer to the datasheet or driver code for MPU9250 to figure out the type of IRQ (falling/rising).

我不确定下一个解释是造成您问题的原因的100%,但至少值得检查.

I'm not 100% sure that what explained next is the cause of your issue, but at least that's worth to be checked.

如我所见,问题是OF(设备树)匹配没有发生.要解决此问题,除了.id_table之外,您还需要在驱动程序结构中定义并分配.of_match_table.因此,现在您在驱动程序中有了下一个驱动程序定义:

As I see it, the problem is that OF (device tree) matching is not happening. To fix this, in addition to .id_table you need to define and assign .of_match_table in your driver struct. So for now you have next driver definition in your driver:

static const struct i2c_device_id inv_mpu_id[] = {
    ...
    {"mpu9250", INV_MPU9250},
    ...
    {}
};

static struct i2c_driver inv_mpu_driver = {
    ...
    .id_table   =   inv_mpu_id,
    ...
};

您需要添加以下内容:

#include <linux/of.h>

#ifdef CONFIG_OF
static const struct of_device_id inv_mpu_of_table[] = {
    ...
    { .compatible = "invensense,mpu9250" },
    ...
    { }
};
MODULE_DEVICE_TABLE(of, inv_mpu_of_table);
#endif

static struct i2c_driver inv_mpu_driver = {
    .driver = {
        .of_match_table = of_match_ptr(inv_mpu_of_table),
        ...
    },
    ...
};

请确保您兼容的字符串具有完全"vendor,product"格式(在您的情况下为"invensense,mpu9250").

Be sure that your compatible strings have exactly "vendor,product" format (which is "invensense,mpu9250" in your case).

现在,在设备树中,您可以使用"invensense,mpu9250"作为compatible属性的值来描述设备:

Now in your device tree you can describe your device using "invensense,mpu9250" as a value for compatible property:

&i2c3 {
...
    extaccelerometer: mpu9250@68 {
        compatible = "invensense,mpu9250";
        ...
    }

完成这些匹配步骤后,应该正确进行匹配,并且您应该看到为client->irq分配了适当的值(因此它不是0).

After these steps OF matching should happen correctly and you should see your client->irq assigned appropriately (so it's not 0).

运行next命令以列出所有具有设备树支持的I2C/IIO驱动程序,您将看到它们在驱动程序struct中都具有两个表:

Run next command to list all I2C/IIO drivers that has device tree support, and you'll see that they all have both tables in driver struct:

$ git grep --all-match -e of_match_table -e '\i2c_driver' -e '\.id_table\b' drivers/iio/* | sed 's/:.*//g' | sort -u

引擎盖下

查看drivers/i2c/i2c-core.ci2c_device_probe()函数以查看如何从I2C设备的设备树中读取IRQ号:

Under the hood

Look into drivers/i2c/i2c-core.c, i2c_device_probe() function to see how IRQ number is being read from device tree for I2C device:

static int i2c_device_probe(struct device *dev)
{
    ...
    if (dev->of_node) {
        ...
        irq = of_irq_get(dev->of_node, 0);
    }
    ...
    client->irq = irq;
    ...
    status = driver->probe(client, i2c_match_id(driver->id_table, client));
}

当设备/驱动程序匹配发生时,正在执行此功能.从I2C适配器探针上的设备树中读取设备信息.因此,在i2c_add_driver()调用驱动程序时,可以与设备树中的设备进行匹配(通过compatible字符串),然后调用i2c_device_probe(),填充client->irq并随后调用驱动程序探测函数.

This function is being executed when device/driver match happens. Devices information is read from device tree on your I2C adapter probe. So on i2c_add_driver() call for your driver there can be match (by compatible string) with device from device tree, and i2c_device_probe() called, populating client->irq and calling your driver probe function next.

of_irq_get()函数从设备树的interrupts属性获取IRQ编号

of_irq_get() function obtains IRQ number from device tree interrupts property

此外,还尝试摆脱.id_table并将.of_match_table专门用于设备匹配:此进一步还原提交(由于某些副作用). 因此,现在我们必须同时定义.id_table.of_match_table,I2C驱动程序才能正常工作.

Also, there was an attempt to get rid of .id_table and use .of_match_table exclusively for device matching: commit. But then it was reverted further in this commit, due to some side effects. So for now we must define both .id_table AND .of_match_table for I2C driver to work correctly.

这篇关于带MPU9250的飞思卡尔IMX6的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆