【重温经典】mini2440驱动程序之LED驱动(基于Linux-2.6.32.2)

2019-07-13 06:21发布

版权声明:本文为博主(宽简厚重,Yuesichiu)原创文章,未经博主允许不得转载。
https://blog.csdn.net/yuesichiu/article/details/81459946

一、LED资源介绍

1、LED对应的GPIO(已上拉)

LED1       nLED1    GPB5 LED2       nLED2    GPB6 LED3       nLED3    GPB7 LED4       nLED4    GPB8

2、硬件电路

 

二、驱动代码(mini2440_leds.c)

以混杂设备注册,主要实现了ioctl接口,应用程序操作时,只需要打开这个设备文件,然后发一个ioctl的命令就会进入到内核空间,接着调用该驱动的ioctl函数来设置相应的状态。

(1)、设置GPIO为输出模式

for (i = 0; i < 4; i++) { s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); //配置文件输出模式 s3c2410_gpio_setpin(led_table[i], 0); //输出低电平,点亮4个GPIO } GPIO的s3c2410_gpio_cfgpin函数中的第二个参数S3C2410_GPIO_OUTPUT(值为0xFFFFFFF1,即高31:4为1,3:1为0,最低位为1),通过查看s3c2410_gpio_cfgpin得知,设置了GPIO对应的位为01,是代表输出模式,这个可以从s3c2440芯片手册上GPIO寄存器得知: 这里贴一下s3c2410_gpio_cfgpin函数的实现: void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) { void __iomem *base = S3C24XX_GPIO_BASE(pin); unsigned long mask; unsigned long con; unsigned long flags; if (pin < S3C2410_GPIO_BANKB) { mask = 1 << S3C2410_GPIO_OFFSET(pin); } else { mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; } switch (function) { case S3C2410_GPIO_LEAVE: mask = 0; function = 0; break; case S3C2410_GPIO_INPUT: case S3C2410_GPIO_OUTPUT: case S3C2410_GPIO_SFN2: case S3C2410_GPIO_SFN3: if (pin < S3C2410_GPIO_BANKB) { function -= 1; function &= 1; function <<= S3C2410_GPIO_OFFSET(pin); } else { function &= 3; function <<= S3C2410_GPIO_OFFSET(pin)*2; } } /* modify the specified register wwith IRQs off */ local_irq_save(flags); con = __raw_readl(base + 0x00); con &= ~mask; con |= function; __raw_writel(con, base + 0x00); local_irq_restore(flags); }

(2)、编写ioctl接口

static int sbc2440_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case 0: case 1: if (arg > 4) { return -EINVAL; } s3c2410_gpio_setpin(led_table[arg], !cmd); //注意,应用程序设为on(GPIO输出高电平)状态时,即驱动程序输出低电平;应用程序设为off(GPIO输出低电平)状态时,即驱动程序输出高电平,因为该硬件电路(上拉)决定。 return 0; default: return -EINVAL; } } 另外设置和读取GPIO pin的函数为s3c2410_gpio_getpin/s3c2410_gpio_setpin。 s3c2410_gpio_getpin的函数实现为: unsigned int s3c2410_gpio_getpin(unsigned int pin) { void __iomem *base = S3C24XX_GPIO_BASE(pin); unsigned long offs = S3C2410_GPIO_OFFSET(pin); return __raw_readl(base + 0x04) & (1<< offs); } s3c2410_gpio_setpin的函数实现为: void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) { void __iomem *base = S3C24XX_GPIO_BASE(pin); unsigned long offs = S3C2410_GPIO_OFFSET(pin); unsigned long flags; unsigned long dat; local_irq_save(flags); dat = __raw_readl(base + 0x04); dat &= ~(1 << offs); dat |= to << offs; __raw_writel(dat, base + 0x04); local_irq_restore(flags); } 我们注意到访问s3c2440的GPIO寄存器使用__raw_readl/__raw_writel函数,也就是直接访问GPIO寄存器。 static inline u32 __raw_readl(const volatile void __iomem *addr) { return *(const volatile u32 __force *) addr; } static inline void __raw_writel(u32 b, volatile void __iomem *addr) { *(volatile u32 __force *) addr = b; } 版权声明:本文为博主(宽简厚重,Yuesichiu)原创文章,未经博主允许不得转载。
https://blog.csdn.net/yuesichiu/article/details/81459946