一、硬件原理图阅读


二、GPIO相关寄存器介绍
1.管脚功能模式

2.管脚输入输出

3.管脚高低电平

三、寄存器操作
1.物理地址映射成虚拟地址
void __iomem *ioremap(phys_addr_t addr, size_t size);
参数:
@addr 物理地址
@size 物理地址大小
返回值:
成功返回虚拟地址,失败返回NULL
2.寄存器读写函数
#include <linux/io.h>
unsigned int readl (volatile void __iomem *addr ) //读4字节
void writel (unsigned int data,volatile void __iomem *addr) //写4字节
四、驱动源码
cpp
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <asm/io.h>
//LED 灯的寄存器设置
#define LED_MUXIO_REGPHY_ADDR 0x20E00B0
#define LED_MUXIO_REG_SIZE 0x4
#define LED_GPIO_BASE_ADDR 0x209C000
#define LED_GPIO_ADDR_SIZE 0x8
#define GPIO_DATREG_OFFSET 0x0
#define GPIO_DIRREG_OFFSET 0x4
#define LED_DEVICE_MAJOR 240
#define LED_DEVICE_MINOR 0
#define LED_DEVICE_ON _IO('L',0x01)
#define LED_DEVICE_OFF _IO('L',0x02)
MODULE_LICENSE("GPL v2");
struct led_device
{
dev_t devid;
void *gpio_muxio_reg;
void *gpio_con_reg;
struct device *dev;
struct class *class;
struct cdev led_cdev;
};
struct led_device *pled;
void led_init(void)
{
int regval = readl(pled->gpio_muxio_reg);
regval &= ~(0xf << 0);
regval |= (0x5 << 0);
writel(regval,pled->gpio_muxio_reg );
regval = readl(pled->gpio_con_reg + GPIO_DIRREG_OFFSET);
regval |= (1 << 27);//第27位设1
writel(regval,pled->gpio_con_reg + GPIO_DIRREG_OFFSET);
return;
}
void led_on(void)
{
int regval = readl(pled->gpio_con_reg + GPIO_DATREG_OFFSET);
regval |= (1 << 27);
writel(regval,pled->gpio_con_reg + GPIO_DATREG_OFFSET);
return;
}
void led_off(void)
{
int regval = readl(pled->gpio_con_reg + GPIO_DATREG_OFFSET);
regval &= ~(1 << 27);
writel(regval,pled->gpio_con_reg + GPIO_DATREG_OFFSET);
return;
}
static int led_device_open(struct inode *inode,struct file *file)
{
printk("led device open\n");
pled->gpio_muxio_reg = ioremap(LED_MUXIO_REGPHY_ADDR,LED_MUXIO_REG_SIZE);
if(!pled->gpio_muxio_reg)
{
printk("Fail to ioremap LED_MUXIO_REGPHY_ADDR\n");
return -ENOMEM;
}
pled->gpio_con_reg = ioremap(LED_GPIO_BASE_ADDR,LED_GPIO_ADDR_SIZE);
if(!pled->gpio_con_reg)
{
printk("Fail to ioremap LED_GPIO_BASE_ADDR\n");
return -ENOMEM;
}
led_init();
return 0;
}
static int led_device_release(struct inode *inode,struct file *file)
{
printk("led device release\n");
led_off();
iounmap(pled->gpio_muxio_reg);
iounmap(pled->gpio_con_reg);
return 0;
}
static long led_device_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
switch (cmd)
{
case LED_DEVICE_ON:
printk("led device on\n");
led_on();
break;
case LED_DEVICE_OFF:
printk("led device off\n");
led_off();
break;
}
return 0;
}
struct file_operations led_device_ops = {
.owner = THIS_MODULE,
.open = led_device_open,
.release = led_device_release,
.unlocked_ioctl = led_device_ioctl,
};
static int __init led_driver_init(void)
{
int err;
pled = kmalloc(sizeof(*pled),GFP_KERNEL);
if(pled == NULL)
{
printk("Fail to kmalloc\n");
err = -ENOMEM;
goto err_kmalloc;
}
//pled->led_cdev.ops = &led_device_ops;
cdev_init(&pled->led_cdev,&led_device_ops);
#if 0
pled->devid = MKDEV(LED_DEVICE_MAJOR,LED_DEVICE_MINOR);
err = register_chrdev_region(pled->devid,1,"led-device");
if(err)
{
printk("Fail to register_chrdev_region\n");
kfree(pled);
}
#endif
err = alloc_chrdev_region(&pled->devid,0,1,"led-device");
if(err)
{
printk("Fail to alloc_chrdev_region\n");
goto err_alloc_chrdev_region;
}
printk("led device MAJOR:%d MINOR:%d\n",MAJOR(pled->devid),MINOR(pled->devid));
err = cdev_add(&pled->led_cdev,pled->devid,1);
if(err)
{
printk("Fail to cdev_add\n");
goto err_cdev_add;
}
pled->class = class_create(THIS_MODULE,"imx6ull-leds");
if (IS_ERR(pled->class))
{
err = PTR_ERR(pled->class);
printk("Fail to class_create\n");
goto err_class_create;
}
//
pled->dev = device_create(pled->class,NULL,pled->devid,NULL,"led-device");
if(IS_ERR(pled->dev))
{
printk("Fail to device_create\n");
err = PTR_ERR(pled->dev);
goto err_device_create;
}
return 0;
err_device_create:
class_destroy(pled->class);
err_class_create:
cdev_del(&pled->led_cdev);
err_cdev_add:
unregister_chrdev_region(pled->devid,1);
err_alloc_chrdev_region:
kfree(pled);
err_kmalloc:
return err;
}
static void __exit led_driver_exit(void)
{
device_destroy(pled->class,pled->devid);
class_destroy(pled->class);
cdev_del(&pled->led_cdev);
unregister_chrdev_region(pled->devid,1);
kfree(pled);
}
module_init(led_driver_init);
module_exit(led_driver_exit);
五、应用程序源码
cpp
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define LED_DEVICE_ON _IO('L',0x01)
#define LED_DEVICE_OFF _IO('L',0x02)
int main(int argc,const char *argv[])
{
int ret;
int fd;
fd = open("/dev/led-device",O_RDWR);
if(fd < 0)
{
perror("Fail to open");
return -1;
}
printf("open /dev/led-device success,fd:%d\n",fd);
while (1)
{
ret = ioctl(fd,LED_DEVICE_ON);
if(ret < 0)
{
perror("Fail to ioctl LED_DEVICE_ON\n");
return -1;
}
sleep(1);
ret = ioctl(fd,LED_DEVICE_OFF);
if(ret < 0)
{
perror("Fail to ioctl LED_DEVICE_OFF\n");
return -1;
}
sleep(1);
}
close(fd);
return 0;
}