20150223 IMX257 LED驱动程序实现
2015-02-23 李海沿
由于昨天对IMX257的地址分配不了解,所以前面只能用s3c24xx的驱动程序来了解ioremap等对IO端口的工作原理。
但是经过昨晚对IMX257芯片的细细梳理,今天早上起来又把IMX257的芯片资料看了一遍,终于成功看懂了,下面意义给大家道来。
我们此处使用ERR_LED 也就是GPIO3_23引脚
一、IMX257 芯片资料分析
1.确定相关寄存器基址
确定IOMUX地址
2.确定相关寄存器的偏移地址
IOMUX的相关的模式配置寄存器,配置为ALT5模式
偏移地址:
寄存器描述:
接下来就是配置GPIO的相关信息,上拉,CMOS输入输出,等信息
偏移地址:
寄存器描述:
GPIO寄存器的偏移地址
因为每个GPIO上最大只有32位,刚刚好上面的DR寄存器每一位就是表示单独一个引脚的电平
二、IMX257 代码分析
1.定义一些寄存器
//寄存器基址; static unsigned long mem_iomux; static unsigned long mem_gpio3; static unsigned long base_iomux; //iomux基址 0X 43FA C000 - 0X 43FA FFFF static unsigned long base_gpio3; //gpio3 0X 53FA 4000 - 0X 53FA 7FFF // MUX_CTL模式选择 配置寄存器 #define MUX_CTL (*(volatile unsigned long *)(base_iomux + 0x0060)) // PAD_CTL GPIO常用功能设置 #define PAD_CTL (*(volatile unsigned long *)(base_iomux + 0x0270)) // GPIO DR 数据寄存器 DR #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000)) // GPIO GDIR 方向控制寄存器 GDIR #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004)) |
如图所示:
2.在init函数中初始化寄存器,及做相应的配置
IO端口申请:
配置引脚为ALT5 GPIO模式
配置引脚的电平,1.8v, CMOS输出,都是配置为0
配置为端口引脚为输出模式,并且初始化电平
打印各个寄存器的地址信息
将LED灯1秒间隔闪烁
3.在exit函数中释放IO端口
4.编译测试
硬件:
如图所示ERR_LED灯点亮
ERR_LED等熄灭
好了,大功告成:
附上驱动程序代码:
1 #include<linux/cdev.h> 2 #include<linux/module.h> 3 #include<linux/types.h> 4 #include<linux/fs.h> 5 #include<linux/errno.h> 6 #include<linux/mm.h> 7 #include<linux/sched.h> 8 #include<linux/init.h> 9 #include<asm/io.h> 10 #include<asm/system.h> 11 #include<asm/uaccess.h> 12 #include<linux/device.h> 13 #include <linux/delay.h> 14 15 #define Driver_NAME "err_led_dev" 16 #define DEVICE_NAME "err_led_dev" 17 18 static int major = 0; 19 20 //auto to create device node 21 static struct class *drv_class = NULL; 22 static struct class_device *drv_class_dev = NULL; 23 24 //寄存器基址; 25 static unsigned long mem_iomux; 26 static unsigned long mem_gpio3; 27 static unsigned long base_iomux; //iomux基址 0X 43FA C000 - 0X 43FA FFFF 28 static unsigned long base_gpio3; //gpio3 0X 53FA 4000 - 0X 53FA 7FFF 29 // MUX_CTL模式选择 配置寄存器 30 #define MUX_CTL (*(volatile unsigned long *)(base_iomux + 0x0060)) 31 // PAD_CTL GPIO常用功能设置 32 #define PAD_CTL (*(volatile unsigned long *)(base_iomux + 0x0270)) 33 // GPIO DR 数据寄存器 DR 34 #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000)) 35 // GPIO GDIR 方向控制寄存器 GDIR 36 #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004)) 37 38 39 static int key_open(struct inode *inode, struct file *file) 40 { 41 printk("<0>function open!\n\n"); 42 return 0; 43 } 44 45 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 46 { 47 return 0; 48 } 49 50 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 51 { 52 printk("<0>function write!\n\n"); 53 return 1; 54 } 55 56 static int key_release(struct inode *inode, struct file *filp) 57 { 58 printk("<0>function write!\n\n"); 59 return 0; 60 } 61 62 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 63 { 64 printk("<0>function ioctl!\n\n"); 65 return 0; 66 } 67 static struct file_operations key_fops = { 68 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 69 .open = key_open, 70 .read = key_read, 71 .write = key_write, 72 .release= key_release, 73 .ioctl = key_ioctl, 74 }; 75 76 void gpio_addr(void){ 77 printk("<0>addr base_iomux : %x \n",base_iomux); 78 printk("<0>addr base_gpio3 : %x \n",base_gpio3); 79 printk("<0>addr MUX_CTL : %x \n",&MUX_CTL); 80 printk("<0>addr PAD_CTL : %x \n",&PAD_CTL); 81 printk("<0>addr GDIR_GPIO3 : %x \n",&GDIR_GPIO3); 82 printk("<0>addr DR_GPIO3 : %x \n",&DR_GPIO3); 83 } 84 85 void led_on_off(void){ 86 ssleep(1); 87 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 88 ssleep(1); 89 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 90 ssleep(1); 91 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 92 ssleep(1); 93 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 94 ssleep(1); 95 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 96 ssleep(1); 97 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 98 ssleep(1); 99 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 100 ssleep(1); 101 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 102 ssleep(1); 103 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 104 } 105 106 static int __init key_irq_init(void) 107 { 108 printk("<0>\nHello,this is %s module!\n\n",Driver_NAME); 109 //register and mknod 110 major = register_chrdev(0,Driver_NAME,&key_fops); 111 drv_class = class_create(THIS_MODULE,Driver_NAME); 112 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 113 114 //IO端口申请 ioremap 可以直接通过指针来访问这些地址 115 base_iomux = ioremap(0x43FAC000,0xFFF); 116 base_gpio3 = ioremap(0x53FA4000,0xFFF); 117 118 //MUX_CTL 119 MUX_CTL &= ~(0x07 << 0); 120 MUX_CTL |= (0X05 << 0); //设置为ALT5 GPIO3_23 ERR_LED 121 //PAD_CTL 122 PAD_CTL &= ~(0x01<<13 | 0x01<<3 | 0x03<<1 | 0x01<<0); //1.8v 不需要上拉下拉 CMOS输出 slew rate 123 //GDIR_GPIO3 配置为输出模式 124 GDIR_GPIO3 &= ~(0x01 << 23); 125 GDIR_GPIO3 |= (0x01 << 23); //配置为输出模式 126 127 //DR_GPIO3 配置为输出0 点亮ERR_LED 128 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 129 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 130 gpio_addr(); 131 led_on_off(); 132 return 0; 133 } 134 135 static void __exit key_irq_exit(void) 136 { 137 gpio_addr(); 138 printk("<0>\nGoodbye,%s!\n\n",Driver_NAME); 139 led_on_off(); 140 141 unregister_chrdev(major,Driver_NAME); 142 device_unregister(drv_class_dev); 143 class_destroy(drv_class); 144 145 //释放IO端口 146 iounmap(base_iomux); 147 iounmap(base_gpio3); 148 } 149 150 151 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 152 module_init(key_irq_init); 153 module_exit(key_irq_exit); 154 155 /* 描述驱动程序的一些信息,不是必须的 */ 156 MODULE_AUTHOR("Lover雪儿"); 157 MODULE_VERSION("0.1.0"); 158 MODULE_DESCRIPTION("IMX257 key Driver"); 159 MODULE_LICENSE("GPL");