Linux i2c和spi(十二)

一、i2c

添加子节点

在设备树对应的i2c下添加子节点

&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    status = "okay";

    ap3216c@1e {
        compatible = "ap3216c";		//
        reg = <0x1e>;		// ap3216c的寄存器地址
    };
};

构建 i2c_driver

static struct i2c_driver ap3216c_driver = {
    .probe = ap3216c_probe,
    .remove = ap3216c_remove,
    .driver = {
            .owner = THIS_MODULE,
            .name = "ap3216c",
            .of_match_table = ap3216c_of_match, 
           },
    .id_table = ap3216c_id,
};    

构建 i2c_msg

发送和接收均用到

int i2c_transfer(struct i2c_adapter *adap,struct i2c_msg *msgs,int num)

发送数据之前要先构建好 i2c_msg

struct i2c_msg {
    __u16 addr; /* 从机地址 */
    __u16 flags; /* 标志 */
    #define I2C_M_TEN 0x0010
    #define I2C_M_RD 0x0001
    #define I2C_M_STOP 0x8000
    #define I2C_M_NOSTART 0x4000
    #define I2C_M_REV_DIR_ADDR 0x2000
    #define I2C_M_IGNORE_NAK 0x1000
    #define I2C_M_NO_RD_ACK 0x0800
    #define I2C_M_RECV_LEN 0x0400
    __u16 len; /* 消息(本 msg)长度 */
    __u8 *buf; /* 消息数据 */
};

发送数据

msg[0].addr = client->addr; /* I2C 器件地址 */
msg[0].flags = 0; /* 标记为发送数据 */
msg[0].buf = &reg; /* 读取的首地址 */
msg[0].len = 1; /* reg 长度 */

读取寄存器数据

msg[1].addr = client->addr; /* I2C 器件地址 */
msg[1].flags = I2C_M_RD; /* 标记为读取数据 */
msg[1].buf = val; /* 读取数据缓冲区 */
msg[1].len = len; /* 要读取的数据长度 */

最后用i2c_transfer(client->adapter, msg, 2);函数发送。

二、spi

添加节点

iomuxc 节点中添加一个新的子节点来描述 ICM20608 所使用的 SPI 引脚

pinctrl_ecspi3: ecspi3grp {
        fsl,pins = <
                MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO        0x100b1  /* MISO*/
                MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI        0x100b1  /* MOSI*/
                MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK      0x100b1  /* CLK*/
                MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20       0x100b0  /* CS*/
        >;
};

ecspi3 节点追加 icm20608 子节点

&ecspi3 {
        fsl,spi-num-chipselects = <1>;	//设置当前片选数量为 1,因为就只接了一个 ICM20608。
        cs-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>; //来描述片选引脚
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ecspi3>;
        status = "okay";

        spidev: icm20608@0 {
        compatible = "alientek,icm20608";
            spi-max-frequency = <8000000>;
            reg = <0>;	//连接到0通道
        };
};

构建 spi_driver

/* SPI驱动结构体 */  
static struct spi_driver icm20608_driver = {
    .probe = icm20608_probe,
    .remove = icm20608_remove,
    .driver = {
            .owner = THIS_MODULE,
            .name = "icm20608",
            .of_match_table = icm20608_of_match, 
           },
    .id_table = icm20608_id,
};

数据构造

spi_transfer 需要组织成 spi_messagespi_transfer描述 SPI 传输信息:tx_bufrx_buflen 是要进行传输的数据长度。

读取数据(全双工传输)

  1. spi_message之前需要对其进行初始化
  2. spi_message 初始化完成以后需要将spi_transfer 添加到 spi_message 队列中
  3. 开始发送同步传输函数为 spi_sync()异步传输spi_async()异步传输需要设置 spi_message 中的 complete成员变量
 struct spi_message m;
    struct spi_transfer *t;
struct spi_device *spi = (struct spi_device *)dev->private_data;
    /* 一共发送len+1个字节的数据,第一个字节为
    寄存器首地址,一共要读取len个字节长度的数据,*/
    txdata[0] = reg | 0x80;         /* 写数据的时候首寄存器地址bit8要置1 */           
    t->tx_buf = txdata;             /* 要发送的数据 */
    t->rx_buf = rxdata;             /* 要读取的数据 */
    t->len = len+1;                 /* t->len=发送的长度+读取的长度 */
    spi_message_init(&m);           /* 初始化spi_message */
    spi_message_add_tail(t, &m);    /* 将spi_transfer添加到spi_message队列 */
    ret = spi_sync(spi, &m);        /* 同步发送 */

 发送数据和接收一样
发送数据没有(t->rx_buf = rxdata;  /* 要读取的数据 */)

  struct spi_message m;
    struct spi_transfer *t;
struct spi_device *spi = (struct spi_device *)dev->private_data;
    /* 一共发送len+1个字节的数据,第一个字节为
    寄存器首地址,len为要写入的寄存器的集合,*/
    *txdata = reg & ~0x80;  /* 写数据的时候首寄存器地址bit8要清零 */
    memcpy(txdata+1, buf, len); /* 把len个寄存器拷贝到txdata里,等待发送 */
    t->tx_buf = txdata;         /* 要发送的数据 */
    t->len = len+1;             /* t->len=发送的长度+读取的长度 */
    spi_message_init(&m);       /* 初始化spi_message */
    spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
    ret = spi_sync(spi, &m);    /* 同步发送 */

注册框架

i2c

/* i2c 驱动的 probe 函数 */
static int xxx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
    /* 函数具体程序 */
    return 0;
}

/* i2c 驱动的 remove 函数 */
static int xxx_remove(struct i2c_client *client)
{
    /* 函数具体程序 */
    return 0;
}
/* 传统匹配方式 ID 列表 */
static const struct i2c_device_id xxx_id[] = {
    {"xxx", 0},
    {}
};
/* 设备树匹配列表 */
static const struct of_device_id xxx_of_match[] = {
    { .compatible = "xxx" },
    { /* Sentinel */ }
};
/* i2c 驱动结构体 */
static struct i2c_driver xxx_driver = {
    .probe = xxx_probe,
    .remove = xxx_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "xxx",
        .of_match_table = xxx_of_match,
    },
    .id_table = xxx_id,
};
/* 驱动入口函数 */
static int __init xxx_init(void)
{
i    nt ret = 0;
    ret = i2c_add_driver(&xxx_driver);
    return ret;
}
/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
    i2c_del_driver(&xxx_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);

spi

/* probe 函数 */
static int xxx_probe(struct spi_device *spi)
{
/* 具体函数内容 */
return 0;
}
/* remove 函数 */
static int xxx_remove(struct spi_device *spi)
{
    /* 具体函数内容 */
    return 0;
}
/* 传统匹配方式 ID 列表 */
static const struct spi_device_id xxx_id[] = {
    {"xxx", 0},
    {}
};
/* 设备树匹配列表 */
static const struct of_device_id xxx_of_match[] = {
    { .compatible = "xxx" },
    { /* Sentinel */ }
};
/* SPI 驱动结构体 */
static struct spi_driver xxx_driver = {
    .probe = xxx_probe,
    .remove = xxx_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "xxx",
        .of_match_table = xxx_of_match,
    },
    .id_table = xxx_id,
};
/* 驱动入口函数 */
static int __init xxx_init(void)
{
    return spi_register_driver(&xxx_driver);
}
/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
    spi_unregister_driver(&xxx_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值