版权声明:本文为博主(
宽简厚重,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