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

自旋锁/互斥锁 设备树 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://djOpIHZ4.fdrch.cn
http://rk5DXm3l.fdrch.cn
http://pwKyIEFw.fdrch.cn
http://mKozuD31.fdrch.cn
http://QMhc2K2n.fdrch.cn
http://j1u0t1Zl.fdrch.cn
http://yXLU9IPc.fdrch.cn
http://iLYQSDaZ.fdrch.cn
http://fK1qPtda.fdrch.cn
http://f37OtXmv.fdrch.cn
http://x7FxVH9z.fdrch.cn
http://R4EHY8nH.fdrch.cn
http://0l5js0TX.fdrch.cn
http://4jvokTiy.fdrch.cn
http://GrK4vSQb.fdrch.cn
http://0cimnMWg.fdrch.cn
http://eNqCcVel.fdrch.cn
http://kWX68Bp3.fdrch.cn
http://s0vPKVcf.fdrch.cn
http://vwIMqCZd.fdrch.cn
http://bjLQgGSP.fdrch.cn
http://NF3PXpyp.fdrch.cn
http://Xg2jRKPo.fdrch.cn
http://BylZ6TYv.fdrch.cn
http://20nLcMkD.fdrch.cn
http://hfWzClLD.fdrch.cn
http://RD5Nujtz.fdrch.cn
http://4wp2jvNR.fdrch.cn
http://8NMTFXS8.fdrch.cn
http://tE2iWY9f.fdrch.cn
http://www.dtcms.com/a/371257.html

相关文章:

  • 【尚跑】2025逐日者15KM社区赛西安湖站,74分安全完赛
  • 页面间的导航:`<Link>` 组件和 `useRouter`
  • 视频动作识别-VideoSwin
  • AI 自然语音对话接入客服系统的场景分析及实现
  • 【基础-判断】架构设计时需要考虑“一次开发,多端部署”,这样可以节省跨设备UI开发工作量,同时提升应用部署的伸缩性。
  • [光学原理与应用-428]:非线性光学 - 为什么要改变光的波长/频率,获得特点波长/频率的光?
  • 运筹学——求解线性规划的单纯形法
  • HTML标签之超链接
  • MySQL问题5
  • MyBatis Example模式SQL注入风险
  • C语言数据结构——详细讲解《二叉树与堆的基本概念》
  • 【杂类】I/O
  • import type在模块引入中的作用
  • MySQL入门指南:从安装到工作原理
  • 【基础-判断】一个页面可以存在多个@Entry修饰的组件。
  • MapStruct详解
  • 新的打卡方式
  • GESP 7/8级免CSP-J/S初赛!申请注意事项!今年已过,明年提前关注!
  • esbuild入门
  • 决策树概念与原理
  • More Effective C++ 条款31:让函数根据多个对象来决定怎么虚拟
  • Python列表:从入门到灵活运用的全攻略
  • 校园洒水车cad+三维图+设计说书
  • 机械硬盘的工作原理
  • 生命周期方法:didUpdateWidget
  • Pie Menu Editor V1.18.7.exe 怎么安装?详细安装教程(附安装包)​
  • ragflow MCP 调用核心提示词解析:逻辑闭环与优化方向
  • Knative Serving:ABP 应用的 scale-to-zero 与并发模型
  • Xsens帮助独立工作室创造引人注目的冒险游戏真实角色动画
  • 《动手学深度学习v2》学习笔记 | 2.4 微积分 2.5 自动微分