当前位置: 首页 > backend >正文

自旋锁/互斥锁 设备树 iic驱动总线 day66 67 68

十二:锁/互斥/信号量/自旋

锁持有时间

长-------互斥锁

短-------自旋锁

自旋锁不会使线程状态发生切换
一直处于用户态,即线程—直都是运行的;
不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。

1.自旋锁

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio.h>
#include <linux/miscdevice.h>
#include <asm/ioctl.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>#define DEV_NAME "adc4"
static wait_queue_head_t wq;
static int condition;
static struct tasklet_struct task;
spinlock_t lock;static void task_func(unsigned long arg)
{spin_lock(&lock);condition = 1;spin_unlock(&lock);wake_up_interruptible(&wq);printk("task_fun arg = %ld\n",arg);
}static irqreturn_t eint8_handler(int irq_num,void * dev)
{unsigned int arg = *(unsigned int *)dev;if(100 != arg){return IRQ_NONE;}spin_lock(&lock);condition = 1;spin_unlock(&lock);tasklet_schedule(&task);printk("irq_num = %d	dev = %d\n",irq_num,arg);return IRQ_HANDLED;
}static void key2_init(void)
{
}static void key2_deinit(void)
{
}static int open(struct inode * node, struct file * file)
{spin_lock_init(&lock);key2_init();printk("key4  open ...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{//copy_to_user();printk("key4 read start\n");spin_lock(&lock);condition = 0;spin_unlock(&lock);wait_event_interruptible(wq,condition);printk("key4 read end...\n");return 0;
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("key4 write ...\n");return 0;
}static int close(struct inode * node, struct file * file)
{key2_deinit();printk("key4 close ...\n");return 0;
}static struct file_operations fops = 
{.owner = THIS_MODULE,.open = open,.read = read,.write = write,.release = close
};static struct miscdevice misc = 
{.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &fops
};static unsigned int arg = 100;static int __init key1_init(void)
{int ret = misc_register(&misc);if(ret < 0)goto err_misc_register;ret = request_irq(IRQ_EINT8, eint8_handler, IRQF_TRIGGER_FALLING, "irq_eint8", &arg);if(ret <0)goto err_request_irq;init_waitqueue_head(&wq);tasklet_init(&task,task_func,200);printk("key4_init   ....\n");return ret;err_request_irq:disable_irq(IRQ_EINT8);free_irq(IRQ_EINT8,&arg);printk("request_irq failed\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register  faikey\n");return ret;	
}static void __exit key1_exit(void)
{disable_irq(IRQ_EINT8);free_irq(IRQ_EINT8,&arg);misc_deregister(&misc);printk("key4_exit   ....\n");
}module_init(key1_init);
module_exit(key1_exit);
MODULE_LICENSE("GPL");

2.互斥锁

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio.h>
#include <linux/miscdevice.h>
#include <asm/ioctl.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/lockdep.h>
#include <linux/mutex.h>#define DEV_NAME "adc4"
static wait_queue_head_t wq;
static int condition = 0;
static struct work_struct work;
static struct mutex lock;static void work_func(struct work_struct *work)
{ssleep(1);mutex_lock(&lock);condition = 1;mutex_unlock(&lock);wake_up_interruptible(&wq);printk("task_func ....\n");
}static irqreturn_t eint8_handler(int irq_num, void * dev)
{unsigned int arg = *(unsigned int *)dev;if(100 != arg)return IRQ_NONE;mutex_lock(&lock);schedule_work(&work);mutex_unlock(&lock);printk("irq_num  = %d  dev = %d\n", irq_num, arg);return IRQ_HANDLED;
}static int open(struct inode * node, struct file * file)
{mutex_init(&lock);printk("adc4  open ...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{//copy_to_user();printk("adc4 read start...\n");mutex_lock(&lock);condition = 0;mutex_unlock(&lock);wait_event_interruptible(wq, condition);printk("adc4 read end...\n");return 0;
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("adc4 write ...\n");return 0;
}static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{return 0;
}static int close(struct inode * node, struct file * file)
{printk("adc4 close ...\n");return 0;
}static struct file_operations fops = 
{.owner = THIS_MODULE,.open = open,.read = read,.write = write,.unlocked_ioctl = ioctl,.release = close
};static struct miscdevice misc = 
{.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &fops
};static unsigned int arg = 100;
static int __init adc1_init(void)
{int ret = misc_register(&misc);if(ret < 0)goto err_misc_register;ret = request_irq(IRQ_EINT8, eint8_handler, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "irq_eint8", &arg);if(ret < 0)goto err_request_irq;init_waitqueue_head(&wq);INIT_WORK(&work, work_func);printk("adc4_init   ....\n");return ret;
err_request_irq:disable_irq(IRQ_EINT8);free_irq(IRQ_EINT8, &arg);printk("request_irq failed\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register  faiadc\n");return ret;	
}static void __exit adc_exit(void)
{disable_irq(IRQ_EINT8);free_irq(IRQ_EINT8, &arg);misc_deregister(&misc);printk("adc4_exit   ....\n");
}module_init(adc1_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

3.信号量

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio.h>
#include <linux/miscdevice.h>
#include <asm/ioctl.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/lockdep.h>
#include <linux/mutex.h>
#include <linux/semaphore.h>#define DEV_NAME "adc4"
static wait_queue_head_t wq;
static int condition = 0;
static struct work_struct work;
static struct semaphore sem;static void work_func(struct work_struct *work)
{ssleep(1);down(&sem);condition = 1;up(&sem);wake_up_interruptible(&wq);printk("task_func ....\n");
}static irqreturn_t eint8_handler(int irq_num, void * dev)
{unsigned int arg = *(unsigned int *)dev;if(100 != arg)return IRQ_NONE;down(&sem);schedule_work(&work);up(&sem);printk("irq_num  = %d  dev = %d\n", irq_num, arg);return IRQ_HANDLED;
}static int open(struct inode * node, struct file * file)
{sema_init(&sem,1);printk("adc4  open ...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{//copy_to_user();printk("adc4 read start...\n");down(&sem);condition = 0;up(&sem);wait_event_interruptible(wq, condition);printk("adc4 read end...\n");return 0;
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("adc4 write ...\n");return 0;
}static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{return 0;
}static int close(struct inode * node, struct file * file)
{printk("adc4 close ...\n");return 0;
}static struct file_operations fops = 
{.owner = THIS_MODULE,.open = open,.read = read,.write = write,.unlocked_ioctl = ioctl,.release = close
};static struct miscdevice misc = 
{.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &fops
};static unsigned int arg = 100;
static int __init adc1_init(void)
{int ret = misc_register(&misc);if(ret < 0)goto err_misc_register;ret = request_irq(IRQ_EINT8, eint8_handler, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "irq_eint8", &arg);if(ret < 0)goto err_request_irq;init_waitqueue_head(&wq);INIT_WORK(&work, work_func);printk("adc4_init   ....\n");return ret;
err_request_irq:disable_irq(IRQ_EINT8);free_irq(IRQ_EINT8, &arg);printk("request_irq failed\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register  faiadc\n");return ret;	
}static void __exit adc_exit(void)
{disable_irq(IRQ_EINT8);free_irq(IRQ_EINT8, &arg);misc_deregister(&misc);printk("adc4_exit   ....\n");
}module_init(adc1_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

十三:设备树 I.MX6U-MINI------imx6ull

1.一些基础概念

根文件系统制作:

​ busybox: 能生成系统需要的核心文件

​ 还需做以下操作才能生成可以使用的根文件系统:

​ 手动添加库文件 其他文件及修改相关配置文件

​ buildroot: 编译完即可生成可以直接使用的根文件系统

​ ---- 添加各种服务 eg: tftp nfs

​ ---- 一定要在连接互联网的环境下才能做,因为要下载使用的资源 任意写一个应用程序 `

先配置双网卡

2.设备树

//vi arch/arm/boot/dts/imx6ull-alientek-emmc.dtsputeleds {#address-cells = <1>;#size-cells = <1>;compatible = "pute-driver-leds";status = "okay";reg = < 0X020C406C 0X04    0X020E0068 0X04    0X020E02F4 0X04    0X0209C004 0X04    0X0209C000 0X04>;  };
make imx6ull-alientek-emmc.dtb	//make 制定的设备树,加后缀就行cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb ~/tftpboot/	//更新tftpboot
    //查找设备树节点pdtsdevice = of_find_node_by_path("/puteleds");if (!pdtsdevice)pr_info("of_find_node_by_path");//读取属性中的compatible字符串ret = of_property_read_string(pdtsdevice, "compatible", &pcompatible);if (ret)pr_info("of_property_read_string failed");pr_info("compatible = %s\n", pcompatible);ret = of_property_read_u32_array(pdtsdevice, "reg", regaddr, 10);if (ret)pr_info("of_property_read_u32_array");for (i = 0; i < 10; i+=2){pr_info("addr: %#x size:%d\n", regaddr[i], regaddr[i+1]);}//虚拟地址向物理地址映射pccgr1 = devm_ioremap(pdevice, regaddr[0], regaddr[1]);if (!pccgr1) {pr_info("fail to ioremap");goto err_device_create;}  imuxrcsw = devm_ioremap(pdevice, regaddr[2], regaddr[3]); if (!imuxrcsw) {pr_info("fail to ioremap");goto err_device_create;}  imuxrcpad = devm_ioremap(pdevice, regaddr[4], regaddr[5]); if (!imuxrcpad) {pr_info("fail to ioremap");goto err_device_create;}  gpiodir = devm_ioremap(pdevice, regaddr[6], regaddr[7]); if (!gpiodir) {pr_info("fail to ioremap");goto err_device_create;}  gpiodat = devm_ioremap(pdevice, regaddr[8], regaddr[9]); if (!gpiodat) {pr_info("fail to ioremap");goto err_device_create;}  

3.完整代码

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm-generic/io.h>
#include <asm/uaccess.h>
#include <linux/of.h>static ssize_t led_read(struct file *fp, char __user *puser, size_t n, loff_t *off);
static ssize_t led_write(struct file *fp, const char __user *puser, size_t n, loff_t *off);
static int led_open(struct inode *node, struct file *fp);
static int led_release(struct inode *node, struct file *fp);
extern void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, resource_size_t size);
ssize_t led_show(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t led_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);static int ledstat;
static struct device *pdevice;
static struct class *pclass;
static struct cdev *pcdev;
static dev_t devno;
static void __iomem *pccgr1;
static void __iomem *imuxrcsw;
static void __iomem *imuxrcpad;
static void __iomem *gpiodir;
static void __iomem *gpiodat;
static struct device_attribute led_attr = __ATTR(ledbright, 0664, led_show, led_store);
static struct file_operations fops = {.owner = THIS_MODULE,.read = led_read,.write = led_write,.open = led_open,.release = led_release,
};static ssize_t led_read(struct file *fp, char __user *puser, size_t n, loff_t *off)
{   unsigned long ret = 0;ret = copy_to_user(puser, &ledstat, sizeof(ledstat));if (ret) pr_info("copy_to_user failed\n");pr_info("led read success!\n");return 0;
}static ssize_t led_write(struct file *fp, const char __user *puser, size_t n, loff_t *off)
{unsigned int tmpvalue = 0;unsigned long len = 0;len = copy_from_user(&ledstat, puser, sizeof(ledstat));if (len) {pr_info("copy_from_user failed");}if (1 == ledstat){//置0开灯tmpvalue = readl(gpiodat);tmpvalue &= ~(0x1 << 3);writel(tmpvalue, gpiodat);ledstat = 0;}else if (0 == ledstat){//置1关灯tmpvalue = readl(gpiodat);tmpvalue |= 0x1 << 3;writel(tmpvalue, gpiodat);ledstat = 0;}pr_info("led write success!\n");return 0;
}static int led_open(struct inode *node, struct file *fp)
{pr_info("led open success!\n");return 0;
}static int led_release(struct inode *node, struct file *fp)
{pr_info("led release success!\n");return 0;
}ssize_t led_show(struct device *dev, struct device_attribute *attr, char *buf)
{ssize_t len = 0;if (1 == ledstat){len = sprintf(buf, "LED_ON\n");}else if (0 == ledstat){len = sprintf(buf, "LED_OFF\n");}return len;
}ssize_t led_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{unsigned int tmpvalue = 0;char tmpbuff[32] = {0};sscanf(buf, "%s", tmpbuff);if (!strcmp(tmpbuff, "LED_ON")){//置0开灯tmpvalue = readl(gpiodat);tmpvalue &= ~(0x1 << 3);writel(tmpvalue, gpiodat);ledstat = 1;}else if (!strcmp(tmpbuff, "LED_OFF")){//置1关灯tmpvalue = readl(gpiodat);tmpvalue |= 0x1 << 3;writel(tmpvalue, gpiodat);ledstat = 0;}return count;
}static int __init led_init(void)
{   int ret = 0;unsigned int tmpvalue = 0;struct device_node *pdtsdevice = NULL;const char *pcompatible = NULL;unsigned int regaddr[10] = {0};int i = 0;//注册设备号ret = alloc_chrdev_region(&devno, 0, 1, "myled");if (ret) {pr_info("alloc_chrdev_region failed\n");goto err_alloc_chrdev_region;}pr_info("major:%d minor:%d\n", MAJOR(devno), MINOR(devno));//创建cdev并初始化pcdev = cdev_alloc();if (!pcdev) {pr_info("cdev_alloc failed\n");goto err_cdev_alloc;}//将cdev加入字符设备结构中pcdev->ops = &fops;ret = cdev_add(pcdev, devno, 1);if (ret) {pr_info("cdev_alloc failed\n");goto err_cdev_add;}//创建设备类pclass = class_create(THIS_MODULE, "led_class");if (!pclass) {pr_info("class_create failed\n");goto err_class_create;}  //创建具体设备pdevice = device_create(pclass, NULL, devno, NULL, "led%d", 0);if (!pclass) {pr_info("device_create failed\n");goto err_device_create;}  //查找设备树节点pdtsdevice = of_find_node_by_path("/puteleds");if (!pdtsdevice)pr_info("of_find_node_by_path");//读取属性中的compatible字符串ret = of_property_read_string(pdtsdevice, "compatible", &pcompatible);if (ret)pr_info("of_property_read_string failed");pr_info("compatible = %s\n", pcompatible);ret = of_property_read_u32_array(pdtsdevice, "reg", regaddr, 10);if (ret)pr_info("of_property_read_u32_array");for (i = 0; i < 10; i+=2){pr_info("addr: %#x size:%d\n", regaddr[i], regaddr[i+1]);}//虚拟地址向物理地址映射pccgr1 = devm_ioremap(pdevice, regaddr[0], regaddr[1]);if (!pccgr1) {pr_info("fail to ioremap");goto err_device_create;}  imuxrcsw = devm_ioremap(pdevice, regaddr[2], regaddr[3]); if (!imuxrcsw) {pr_info("fail to ioremap");goto err_device_create;}  imuxrcpad = devm_ioremap(pdevice, regaddr[4], regaddr[5]); if (!imuxrcpad) {pr_info("fail to ioremap");goto err_device_create;}  gpiodir = devm_ioremap(pdevice, regaddr[6], regaddr[7]); if (!gpiodir) {pr_info("fail to ioremap");goto err_device_create;}  gpiodat = devm_ioremap(pdevice, regaddr[8], regaddr[9]); if (!gpiodat) {pr_info("fail to ioremap");goto err_device_create;}  //时钟tmpvalue = readl(pccgr1);tmpvalue &= ~(0x3 << 26);tmpvalue |= (0x3 << 26);writel(tmpvalue, pccgr1);//设置为GPIOwritel(0x5, imuxrcsw);//设置电器属性writel(0x10B0, imuxrcpad);//GPIO方向tmpvalue = readl(gpiodir);tmpvalue |= 0x1 << 3;writel(tmpvalue, gpiodir);//关灯//置1关灯tmpvalue = readl(gpiodat);tmpvalue |= (0x1 << 3);writel(tmpvalue, gpiodat);//增加sysfs文件系统中的调试节点ret = device_create_file(pdevice, &led_attr);if (ret) pr_info("device_create_file failed");pr_info("led init success\n");return 0;
err_device_create:class_destroy(pclass); 
err_class_create:cdev_del(pcdev);
err_cdev_add:
err_cdev_alloc:unregister_chrdev_region(devno, 1);
err_alloc_chrdev_region:return -1;
}static void __exit led_exit(void)
{device_destroy(pclass, devno);class_destroy(pclass);cdev_del(pcdev);unregister_chrdev_region(devno, 1);pr_info("led exit success\n");return;
}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("haiersen");

4.关于设备树一个Makefile搞定

make -f Makefile1
//vi Makefile1modulename=ledall:make -C $(modulename)_app_96make -C $(modulename)_drv_96
//vi led_drv_96/Makefile#模块名
modulename=led_drv#内核路径
kerdir=/home/linux/ARM/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek#当前路径
curpath=$(shell pwd)#将代码加入模块编译选项中
obj-m+=$(modulename).o all:make -C $(kerdir) modules M=$(curpath)cp $(modulename).ko ~/nfs/rootfs_os/
.PHONY:
clean:rm $(modulename).ko
// vi led_app_96/Makefile#模块名称
appname=led_app1#编译器
CC=arm-linux-gnueabihf-gcc$(appname):$(CC) main.c -o $@cp $(appname) ~/nfs/rootfs_os/ 
.PHONY:
clean:rm $(appname)
1.关于设备树文件
static int __init led_init(void)
{int ret = 0;ret = misc_register(&misc_device);if (ret)pr_info("misc register led failed\n");pdtsnode = of_find_node_by_path("/puteleds");	//找对应位置if (!pdtsnode)pr_info("of_find_node_by_path failed\n");ledgpionum = of_get_named_gpio(pdtsnode, "led-gpio", 0);	//匹配led-gpio = <&gpio1 3 0>;if (ledgpionum < 0)pr_info("of_get_named_gpio failed\n");ret = gpio_request(ledgpionum, "puteled");		//if (ret)pr_info("gpio_request failed\n");ret = gpio_direction_output(ledgpionum, 1);if (ret)pr_info("gpio_request failed\n");return 0;
}
//vi arch/arm/boot/dts/imx6ull-alientek-emmc.dtsputeleds {#address-cells = <1>;#size-cells = <1>;compatible = "pute-driver-leds";pinctrl-names = "default";pinctrl-0 = <&pinctrl_puteled>;led-gpio = <&gpio1 3 0>;status = "okay";};
2.完整代码
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/of_gpio.h>static ssize_t led_read(struct file *fp, char __user *puser, size_t n, loff_t *off);
static ssize_t led_write(struct file *fp, const char __user *puser, size_t n, loff_t *off);static int ledstat = 0;
static struct device_node *pdtsnode;
static int ledgpionum;
static struct file_operations fops = {.owner = THIS_MODULE,.read = led_read,.write = led_write,
};static struct miscdevice misc_device = {.minor = MISC_DYNAMIC_MINOR,.name = "misc_led",.fops = &fops,
};static ssize_t led_read(struct file *fp, char __user *puser, size_t n, loff_t *off)
{unsigned long ret = 0;ret = copy_to_user(puser, &ledstat, sizeof(ledstat));if (ret)pr_info("copy_to_user failed");return 0;
}            static ssize_t led_write(struct file *fp, const char __user *puser, size_t n, loff_t *off)
{unsigned long value = 0;unsigned long ret = 0;ret = copy_from_user(&value, puser, sizeof(value));if (ret)pr_info("copy_from_user failed");if (1 == value){gpio_set_value(ledgpionum, 0);ledstat = 1;}else if (0 == value){gpio_set_value(ledgpionum, 1);ledstat = 0;}return 0;
}static int __init led_init(void)
{int ret = 0;ret = misc_register(&misc_device);if (ret)pr_info("misc register led failed\n");pdtsnode = of_find_node_by_path("/puteleds");if (!pdtsnode)pr_info("of_find_node_by_path failed\n");ledgpionum = of_get_named_gpio(pdtsnode, "led-gpio", 0);if (ledgpionum < 0)pr_info("of_get_named_gpio failed\n");ret = gpio_request(ledgpionum, "puteled");if (ret)pr_info("gpio_request failed\n");ret = gpio_direction_output(ledgpionum, 1);if (ret)pr_info("gpio_request failed\n");return 0;
}static void __exit led_exit(void)
{int ret = 0;gpio_free(ledgpionum);ret = misc_deregister(&misc_device);if (ret)pr_info("misc deregister led failed\n");return;
}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("haiersen");

十四:iic子系统—2440

1. iIC总线驱动

IIC总线驱动: (主要实现与设备无关的IIC读写时序并提供操作读写的方法)

在这里插入图片描述

2440 只有一个iic接口 dev/iic/0 0接口

2. adapter

i2c_adapter:总线控制器,读写都在这里控制算法algorithm,有读写函数

  • 代表一条 I²C 总线控制器(比如 SoC 上的 I²C0、I²C1 控制器)。
  • 每个 adapter 都对应一条总线(编号从 0 开始)。
  • 里面包含了访问硬件的函数指针(master_xfersmbus_xfer),用来实现具体的读写。
  • 对应物理层面上“谁来发时钟、发起 start/stop 信号”。

关键结构体(简化版):

struct i2c_adapter {struct module *owner;struct i2c_algorithm *algo;  // 算法实现,比如如何发起I²C传输struct device dev;           // 代表一个总线设备int nr;                      // 总线编号,比如 i2c-0, i2c-1
};

3.应用层直接调用iic驱动总线

//linux@ubuntu:~/nfs/rootfs$ vi lm75.c
//linux@ubuntu:~/nfs/rootfs$ arm-linux-gcc lm75.c -o lm75#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/stat.h>
#include <sys/ioctl.h>int main(int argc, const char *argv[])
{unsigned char lm75_addr = 0x48;unsigned char reg_addr = 0;unsigned char data[2] = {0};int fd = open("/dev/i2c/0",O_RDWR);if(fd < 0){perror("open /dev/i2c/0 failed\n");return -1;}ioctl(fd,I2C_SLAVE,lm75_addr);while(1){write(fd,&reg_addr,sizeof reg_addr);read(fd,data,sizeof data);float temp = 0.5 * (((data[0] << 8) | data[1]) >> 7);//0在高位MSB,1在低位LSB    >>7 把没用的位置去掉printf("temp = %.1f\n",temp);sleep(2);}close(fd);return 0;
}

4.通过 core 核心层调用iic总线驱动

在这里插入图片描述

1. client
struct i2c_adapter* i2c_get_adapter(int id)  //只要id就行
{struct i2c_adapter *adapter;mutex_lock(&core_lock);adapter = idr_find(&i2c_adapter_idr, id);if (adapter && !try_module_get(adapter->owner))adapter = NULL;mutex_unlock(&core_lock);return adapter;
}

在这里插入图片描述

#define I2C_BOARD_INFO(dev_type, dev_addr) 
//.type = dev_type, .addr = (dev_addr)struct i2c_board_info {char		type[I2C_NAME_SIZE];	//nameunsigned short	flags;			unsigned short	addr;				//地址void		*platform_data;struct dev_archdata	*archdata;int		irq;
};
//其他按需
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/i2c.h>#define DEV_NAME "lm75"
#define LM75_ADDR 0x48
#define I2C_ADAPTER_NUM 0static struct i2c_board_info info = 
{I2C_BOARD_INFO(DEV_NAME, LM75_ADDR)	//就要地址和name
};struct i2c_client * pclient;static int __init lm75_client_init(void)
{static struct i2c_adapter * padapter = NULL;	//创建adapter,然后之后匹配对应的一组padapter =  i2c_get_adapter(I2C_ADAPTER_NUM);	//只要对应idif(NULL == padapter)goto err_get_adatper;pclient = i2c_new_device(padapter, &info);	//pclient 拿到对应从机的地址,id,nameif(NULL == pclient)goto err_new_device;printk("lm75_client_init  ...\n");return 0;err_new_device:
err_get_adatper:printk("lm75_client_init  failed...\n");return -1;
}static void __exit lm75_client_exit(void)
{i2c_unregister_device(pclient);		//注销
}module_init(lm75_client_init);
module_exit(lm75_client_exit);
MODULE_LICENSE("GPL");
2. driver
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/i2c.h>#define DEV_NAME "lm75"
static struct i2c_client * lm75_client;	//保存lm75_client,因为static int open(struct inode * node, struct file * file)
{return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{//  write reg_addr to lm75		//0x48//  read  2 bytes data from lm75		//0x48unsigned char lm75_reg_addr = 0;unsigned char data[2] = {0};struct i2c_msg msg;msg.addr = 0x48;msg.flags = 0;  //iic writemsg.buf = &lm75_reg_addr;msg.len = sizeof(lm75_reg_addr);lm75_client->adapter->algo->master_xfer(lm75_client->adapter, &msg, 1);	msg.addr = 0x48;msg.flags = I2C_M_RD;  //iic readmsg.buf = data;msg.len = sizeof(data);lm75_client->adapter->algo->master_xfer(lm75_client->adapter, &msg, 1);	copy_to_user(buf, data, sizeof(data));return sizeof(data);
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{return 0;
}static int close(struct inode * node, struct file * file)
{return 0;
}static struct file_operations fops = 
{.owner = THIS_MODULE,.open = open,.read = read,.write = write,.release = close
};static struct miscdevice misc = 
{.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &fops
};static int probe(struct i2c_client * pclient, const struct i2c_device_id * dev_id)	//client拿到probe
{int ret = misc_register(&misc);if(ret < 0)goto err_misc_register;lm75_client = pclient;	//匹配printk("lm75  probe ...\n");return 0;err_misc_register:misc_deregister(&misc);printk("lm75_register  failed\n");return ret;	return 0;
}static int remove(struct i2c_client * pclient)
{misc_deregister(&misc);printk("lm75 remove   ....\n");return 0;
}----------------------------------------------------------------//拿id
static struct i2c_device_id lm75_id_table[] = 
{[0] = {.name = DEV_NAME}
};//类似于platform
static struct i2c_driver lm75_driver = 
{.probe = probe,		//匹配对应.remove = remove,.driver = {.name = "lm75_driver"	//匹配用的表示字符串,在设备中匹配,设备树匹配?},.id_table = lm75_id_table	//拿id
};static int __init lm75_driver_init(void)
{int ret = i2c_add_driver(&lm75_driver); //注册对应名字if(ret < 0)return ret;	//搞一下报错处理  goto xxxprintk("lm75_driver_init  ...\n");return 0;
}static void __exit lm75_driver_exit(void)
{i2c_del_driver(&lm75_driver);	//注销printk("lm75_driver_exit  ...\n");
}module_init(lm75_driver_init);
module_exit(lm75_driver_exit);
MODULE_LICENSE("GPL");
3. 关于 i2c_driver
// 定义支持的 I2C 设备 ID 列表,
// 当内核扫描到 i2c_client->name 与这里的 name 匹配时,
// 就会把匹配到的 id_table 元素传给 probe()
static struct i2c_device_id lm75_id_table[] = 
{[0] = {.name = DEV_NAME}
};// 定义 I2C 驱动
static struct i2c_driver lm75_driver = 
{.probe  = probe,     // 设备和驱动匹配成功后调用.remove = remove,    // 设备移除或驱动卸载时调用.driver = {.name = "lm75_driver"   // 驱动名字(匹配用):// ① 和 i2c_device_id[].name 匹配// ② 或和设备树(dts)中 compatible 匹配},.id_table = lm75_id_table   // 指向支持的设备 ID 表,内核用来做匹配
};
4.关于adapter实现读写的流程
lm75_client->adapter->algo->master_xfer(lm75_client->adapter, &msg, 1);//lm75_client的adapter的算法algorithm的master_xfer函数,这个函数才是实现iic驱动的读写操作//感恩😰

在这里插入图片描述

4. msg
struct i2c_msg {__u16 addr;	/* slave address			*/__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */__u16 len;		/* msg length				*/__u8 *buf;		/* pointer to msg data			*/
};//关于I2C_M_RD本质上是if else     所以write是0
if(I2C_M_RD) 
{//read
}else
{//write
}
5. 全部*
//ls
/*
lm754_client.c      lm754_client.o      lm754_driver.mod.o
lm754_client.ko     lm754_driver.c      lm754_driver.o
lm754_client.mod.c  lm754_driver.ko     
lm754_client.mod.o  lm754_driver.mod.c  
*/
linux@ubuntu:~/ARM/linux-2.6.32.2$ cp drivers/char/lm754_*.ko ~/nfs/rootfs

5. 用户程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>int main(int argc, const char *argv[])
{
#if 0		//应用层直接操作iic总线驱动unsigned char lm75_addr = 0x48; unsigned char reg_addr = 0;unsigned char data[2] = {0};int fd = open("/dev/i2c/0", O_RDWR);if(fd < 0){perror("open i2c/0 failed\n");return -1;}ioctl(fd, I2C_SLAVE, lm75_addr);while(1){write(fd, &reg_addr, sizeof(reg_addr));read(fd, data, sizeof(data));float temp =  0.5 * (((data[0] << 8) | data[1]) >> 7);printf("temp = %.1f\n", temp);sleep(2);}close(fd);
#endif////应用层通过adapter,核心层操作iic总线驱动int fd = open("/dev/lm75", O_RDWR);if(fd < 0){perror("open lm75")	;return -1;}while(1){unsigned char data[2] = {0};read(fd, data, sizeof(data));float temp =  0.5 * (((data[0] << 8) | data[1]) >> 7);printf("temp = %.1f\n", temp);sleep(2);}close(fd);return 0;
}

6.流程

[root@FriendlyARM /]# insmod lm754_client.ko 
lm75_client_init  ...
[root@FriendlyARM /]# insmod lm754_driver.ko 
lm75  probe ...
lm75_driver_init  ...

7.如果用设备树的话

clien就不用了,本质上就是device — 都是设备信息

http://www.xdnf.cn/news/20291.html

相关文章:

  • 输入2.2V~16V 最高输出20V2.5A DCDC升压芯片MT3608L
  • 计算机网络:网络设备在OSI七层模型中的工作层次和传输协议
  • 鸿蒙 BLE 蓝牙智能设备固件升级之DFU升级方式(Nordic芯片)
  • macbook intel 打开cursor会闪退
  • MySQL集群高可用架构(MHA高可用架构)
  • Process Explorer进阶(第三章3.3):深入理解进程详情
  • [Windows] AdGuard.v7.21.5089.0 中文直装电脑版
  • cds序列转换为pepperl脚本详细解读及使用
  • Python多线程编程全面指南
  • web自动化测试
  • Elasticsearch优化从入门到精通
  • 线代:排列与逆序
  • 从机器学习的角度实现 excel 中趋势线:揭秘梯度下降过程
  • PageHelper的使用及底层原理
  • WordPress如何绑定多个域名 WordPress实现多域名访问
  • 新的打卡方式
  • GPIO介绍
  • java接口和抽象类有何区别
  • ICPC 2023 Nanjing R L 题 Elevator
  • 用Android studio运行海外极光推送engagelab安卓的SDK打apk安装包
  • Ribbon和LoadBalance-负载均衡
  • 从Java全栈到前端框架:一次真实面试的深度复盘
  • 验证平台中所有的组件应该派生自UVM中的类
  • 设计艺术~缓存结构设计
  • 【Go项目基建】GORM框架实现SQL校验拦截器(完整源码+详解)
  • C++和OpenGL实现3D游戏编程【连载30】——文字的多行显示
  • MySQL集群——主从复制进阶
  • 2025年上海市星光计划第十一届职业院校技能大赛高职组“信息安全管理与评估”赛项交换部分前6题详解(仅供参考)
  • FlashAttention:突破Transformer内存瓶颈的IO感知革命
  • Web漏洞挖掘篇(二)—信息收集