手机app设计网站建设,自助单页网站,夏邑网站建设,湖南天辰建设责任公司网站I2C基本介绍 SCL 为高电平#xff0c;SDA 出现下降沿:起始位 SCL 位高电平#xff0c;SDA出现上升沿:停止位 主机——从机地址#xff08;ack#xff09;——寄存器地址#xff08;ack#xff09;——数据#xff08;ack#xff09; 重点#xff1a;先是写#xff0c…I2C基本介绍 SCL 为高电平SDA 出现下降沿:起始位 SCL 位高电平SDA出现上升沿:停止位 主机——从机地址ack——寄存器地址ack——数据ack 重点先是写因为要写入从机让从机知道主机要读再是读 主机——从机地址写ack——寄存器地址ack——从机地址读ack 从机——发送数据主机发送no ack 1-7位放要访问的从机地址 I2c频率不能随便分只能选 I2C源码分析 I2C适配器驱动 i2c_adapter - i2c_algorithm -master_xfer : I2C适配器的传输函数可以通过此函数来完成与 IIC设备之间的通信。 I2C流程 1. 初始化i2c_adapter结构体变量 2. 设置 i2c_algorithm中的 master_xfer函数。 3. 向系统注册设置好的 i2c_adapter通过 i2c_add_numbered_adapter或 i2c_add_adapter这两个函数 I2C适配器是 platform驱动, I2C总线为别的设备提供了一种总线驱动框架 I2C在Platform虚拟总线上Platform驱动I2C 从机设备在I2C总线上I2C驱动从机 I2c注册 I2C设备驱动 I2c_client 描述设备信息主要在设备树写外设信息I2c_client注册等操作从设备树中查找写好 I2c_dirver 驱动内容 drivers/i2c/i2c-core.c 总线定义设备和驱动匹配
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{struct i2c_client *client i2c_verify_client(dev);//从i2c中获取从机名单struct i2c_driver *driver;if (!client)return 0;/* Attempt an OF style match */if (of_driver_match_device(dev, drv))return 1;/* Then ACPI style match */if (acpi_driver_match_device(dev, drv))return 1;driver to_i2c_driver(drv);/* match on an id table if there is one */if (driver-id_table)return i2c_match_id(driver-id_table, client) ! NULL;//设备树匹配return 0;
}驱动编写
1. I2C设备树设置
i2c1 {clock-frequency 100000;pinctrl-names default;pinctrl-0 pinctrl_i2c1;status okay;设备树写I2C的SCL SDA端口pinctrl_i2c1 pinctrl_i2c1: i2c1grp {fsl,pins MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0;};2. ap3216c子节点添加
i2c1 {clock-frequency 100000;pinctrl-names default;pinctrl-0 pinctrl_i2c1;status okay;ap32161e{compatible alientek,ap3216c;reg0x1e;};};3. 编译dtbs并添加
make dtbs
sudo cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /home/liu/linux/tftpboot/ -f4. 查看 cd /sys/bus/i2c/devices/
cd 0-001e/
cat name
5. ap3216c.c编写
1.ap3216c_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,
};驱动和设备树的匹配
/* 传统匹配方式ID列表 */
static const struct i2c_device_id ap3216c_id[] {{alientek,ap3216c, 0}, {}
};/* 设备树匹配列表 */
static const struct of_device_id ap3216c_of_match[] {{ .compatible alientek,ap3216c },{ /* Sentinel */ }
};ap3216c_probe驱动的执行函数
构建设备号对ap3216cdev设备号赋值注册设备cdev字符设备注册包含ap3216cdev的操作函数ops创建类class内包含dev需要的一些成员如总线设备链表还有需要的函数创建设备device_create
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{/* 1、构建设备号 */if (ap3216cdev.major) {ap3216cdev.devid MKDEV(ap3216cdev.major, 0);register_chrdev_region(ap3216cdev.devid, AP3216C_CNT, AP3216C_NAME);} else {alloc_chrdev_region(ap3216cdev.devid, 0, AP3216C_CNT, AP3216C_NAME);ap3216cdev.major MAJOR(ap3216cdev.devid);}/* 2、注册设备 */cdev_init(ap3216cdev.cdev, ap3216c_ops);cdev_add(ap3216cdev.cdev, ap3216cdev.devid, AP3216C_CNT);/* 3、创建类 */ap3216cdev.class class_create(THIS_MODULE, AP3216C_NAME);if (IS_ERR(ap3216cdev.class)) {return PTR_ERR(ap3216cdev.class);}/* 4、创建设备 */ap3216cdev.device device_create(ap3216cdev.class, NULL, ap3216cdev.devid, NULL, AP3216C_NAME);if (IS_ERR(ap3216cdev.device)) {return PTR_ERR(ap3216cdev.device);}ap3216cdev.private_data client;return 0;
}寄存器读写 读需要发送两次信息i2c_transfer可以发送多个信息 msgs[1]要发的信息排序发送msgs[0]标志位为读内含寄存器地址msgs[1]标志位为读读取数据放入缓冲区 I2C具体流程不需要写官方写好了 I2C数据传输函数内含主机从机地址根据标志位决定读还是写
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)msgs数据结构体地址发送类型信息长度信息
struct i2c_msg {__u16 addr; /* slave address */__u16 flags;
#define I2C_M_RD 0x0001 /* read data, from slave to master *//* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe *//* makes only sense in kernelspace *//* userspace buffers are copied anyway */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */__u16 len; /* msg length */__u8 *buf; /* pointer to msg data */
};/** description : 从ap3216c读取多个寄存器数据* param - dev: ap3216c设备* param - reg: 要读取的寄存器首地址* param - val: 读取到的数据* param - len: 要读取的数据长度* return : 操作结果*/
static int ap3216c_read_regs(struct ap3216c_dev *dev, u8 reg, void *val, int len)
{int ret;struct i2c_msg msg[2];struct i2c_client *client (struct i2c_client *)dev-private_data;/* msg[0]为发送要读取的首地址 */msg[0].addr client-addr; /* ap3216c地址 */msg[0].flags 0; /* 标记为发送数据 */msg[0].buf reg; /* 读取的首地址 */msg[0].len 1; /* reg长度*//* msg[1]读取数据 */msg[1].addr client-addr; /* ap3216c地址 */msg[1].flags I2C_M_RD; /* 标记为读取数据*/msg[1].buf val; /* 读取数据缓冲区 */msg[1].len len; /* 要读取的数据长度*/ret i2c_transfer(client-adapter, msg, 2);if(ret 2) {ret 0;} else {printk(i2c rd failed%d reg%06x len%d\n,ret, reg, len);ret -EREMOTEIO;}return ret;
}写msgs标志位为写输入寄存器地址告诉写入信息i2c_transfer传输其他不用管 /** description : 向ap3216c多个寄存器写入数据* param - dev: ap3216c设备* param - reg: 要写入的寄存器首地址* param - val: 要写入的数据缓冲区* param - len: 要写入的数据长度* return : 操作结果*/
static s32 ap3216c_write_regs(struct ap3216c_dev *dev, u8 reg, u8 *buf, u8 len)
{u8 b[256];struct i2c_msg msg;struct i2c_client *client (struct i2c_client *)dev-private_data;b[0] reg; /* 寄存器首地址 */memcpy(b[1],buf,len); /* 将要写入的数据拷贝到数组b里面 */msg.addr client-addr; /* ap3216c地址 */msg.flags 0; /* 标记为写数据 */msg.buf b; /* 要写入的数据缓冲区 */msg.len len 1; /* 要写入的数据长度 */return i2c_transfer(client-adapter, msg, 1);
}ap3216c初始化
#define AP3216C_ADDR 0X1E /* AP3216C器件地址 *//* AP3316C寄存器 */
#define AP3216C_SYSTEMCONG 0x00 /* 配置寄存器 */
#define AP3216C_INTSTATUS 0X01 /* 中断状态寄存器 */
#define AP3216C_INTCLEAR 0X02 /* 中断清除寄存器 */
#define AP3216C_IRDATALOW 0x0A /* IR数据低字节 */
#define AP3216C_IRDATAHIGH 0x0B /* IR数据高字节 */
#define AP3216C_ALSDATALOW 0x0C /* ALS数据低字节 */
#define AP3216C_ALSDATAHIGH 0X0D /* ALS数据高字节 */
#define AP3216C_PSDATALOW 0X0E /* PS数据低字节 */
#define AP3216C_PSDATAHIGH 0X0F /* PS数据高字节 */#endif
static int ap3216c_open(struct inode *inode, struct file *filp)
{filp-private_data ap3216cdev;/* 初始化AP3216C */ap3216c_write_reg(ap3216cdev, AP3216C_SYSTEMCONG, 0x04); /* 复位AP3216C */mdelay(50); /* AP3216C复位最少10ms */ap3216c_write_reg(ap3216cdev, AP3216C_SYSTEMCONG, 0X03); /* 开启ALS、PSIR */return 0;
}