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

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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值