分类: 嵌入式
2014-09-23 21:49:09
原文地址:GPIO驱动之LED灯 作者:yanhongkang928
GPIO驱动之LED灯
参考网页:http://blog.chinaunix.net/u3/102836/showart_2065945.html
先从底层硬件看起,4个LED灯接着GPF0~GPF3, 高电平时灭,低电平时亮
然后查看相关控制寄存器和数据寄存器
rGPFCON = (rGPFCON | 0xFFFF) & 0xFFFFFF55; //GPF0--GPF3设置为output
rGPFUP = rGPFUP & 0xFFF0; //使能GPF上拉电阻
rGPFDAT = 0x0F; //GPF低4位初始化为1
1.在 linux-2.6.31\arch\arm\plat-s3c24xx\gpio.c中定义了内核直接对GPIO的控制函数:
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
/* s3c2410_gpio_cfgpin
*
* set the configuration of the given pin to the value passed.
*
* eg:
* s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0);
* s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
*/
unsigned int s3c2410_gpio_getcfg(unsigned int pin)
/* s3c2410_gpio_getirq
*
* turn the given pin number into the corresponding IRQ number
*
* returns:
* < 0 = no interrupt for this pin
* >=0 = interrupt number for the pin
*/
void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
/* s3c2410_gpio_pullup
*
* configure the pull-up control on the given pin
*
* to 1 => disable the pull-up
* 0 => enable the pull-up
*
* eg;
*
* s3c2410_gpio_pullup(S3C2410_GPB(0), 0);
* s3c2410_gpio_pullup(S3C2410_GPE(8), 0);
*/
int s3c2410_gpio_getpull(unsigned int pin)
/* s3c2410_gpio_getpull
*
* Read the state of the pull-up on a given pin
*
* return:
* < 0 => error code
* 0 => enabled
* 1 => disabled
*/
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
unsigned int s3c2410_gpio_getpin(unsigned int pin)
unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
int s3c2410_gpio_getirq(unsigned int pin)
/* s3c2410_gpio_irqfilter
*
* set the irq filtering on the given pin
*
* on = 0 => disable filtering
* 1 => enable filtering
*
* config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with
* width of filter (0 through 63)
*
*
*/
2.在linux-2.6.31\arch\arm\mach-s3c2410\include\mach\gpio-nrs.h中定义了GPIO中A~H的地址位:
#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
#define S3C2410_GPIO_NEXT(__gpio) \
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
enum s3c_gpio_number {
S3C2410_GPIO_A_START = 0,
S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
};
#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr))
3.在linux-2.6.31\arch\arm\mach-s3c2410\include\mach\regs-gpio.h中详细定义了GPIO A~H的所有寄存器并定义了各位的置一时的代理,还有最重要的映射地址:
#define S3C2410_GPFCON S3C2410_GPIOREG(0x50)
#define S3C2410_GPFDAT S3C2410_GPIOREG(0x54)
#define S3C2410_GPFUP S3C2410_GPIOREG(0x58)
#define S3C2410_GPF0_EINT0 (0x02 << 0)
#define S3C2410_GPF1_EINT1 (0x02 << 2)
#define S3C2410_GPF2_EINT2 (0x02 << 4)
#define S3C2410_GPF3_EINT3 (0x02 << 6)
#define S3C2410_GPF4_EINT4 (0x02 << 8)
#define S3C2410_GPF5_EINT5 (0x02 << 10)
#define S3C2410_GPF6_EINT6 (0x02 << 12)
#define S3C2410_GPF7_EINT7 (0x02 << 14)
#define S3C2410_GPF_PUPDIS(x) (1<<(x))
#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)
#define S3C24XX_MISCCR S3C24XX_GPIOREG2(0x80)
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
/* general configuration options */
#define S3C2410_GPIO_LEAVE (0xFFFFFFFF)
#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */
#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)
#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */
#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */
#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */
/* register address for the GPIO registers.
* S3C24XX_GPIOREG2 is for the second set of registers in the
* GPIO which move between s3c2410 and s3c2412 type systems */
#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2)
/************************************************
LED的驱动,在TX2440A开发板上做测试
linux内核:2.6.31
硬件接法:
LED1 --> GPF0
LED2 --> GPF1
LED3 --> GPF2
LED4 --> GPF3
低电平点亮
驱动用法:
设备名称:TX2440-led
点亮一个灯:LED_ON
熄灭一个灯:LED_OFF
点亮所有灯:ALL_LED_ON
熄灭所有灯:ALL_LED_OFF
说明:
内核源码里已经有LED的驱动,将它们注释掉
在arch/arm/plat-s3c24xx/common-smdk.c中
将GPF0-GPF3设为输出,全部输出低电平
*************************************************/
#include
#include
#include
#include
#include
#include
//#include
#include
//#include
#include
#include
#include
#define DEVICE_NAME "TX2440-led" /* 设备名称 */
static int LED_Major = 0; /* 主设备号 */
#define LED_OFF 0
#define LED_ON 1
#define ALL_LED_OFF 3
#define ALL_LED_ON 4
/* 用来指定LED所用的GPIO引脚 */
static unsigned long led_table [] =
{
S3C2410_GPF(0),
S3C2410_GPF(1),
S3C2410_GPF(2),
S3C2410_GPF(3),
};
/*分别定义open ,release , ioctl 执行命令*/
static int TX2440_led_open(struct inode *inode, struct file *file)
{
// MOD_INC_USE_COUNT;
printk("TX2440-LED Driver Open Called!\n");
return 0;
}
static int TX2440_led_release(struct inode *inode, struct file *file)
{
// MOD_DEC_USE_COUNT;
printk("TX2440-LED Driver Release Called!\n");
return 0;
}
static int TX2440_led_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int i;
if (arg > 4)
{
return -EINVAL;
}
switch(cmd)
{
case LED_ON: //set the pin
s3c2410_gpio_setpin(led_table[arg], 0);
break;
case LED_OFF: //clr the pin
s3c2410_gpio_setpin(led_table[arg], 1);
break;
case ALL_LED_ON: //set all pin
for (i = 0; i < 4; i++)
s3c2410_gpio_setpin(led_table[i], 0);
break;
case ALL_LED_OFF: //clr all pin
for (i = 0; i < 4; i++)
s3c2410_gpio_setpin(led_table[i], 1);
break;
default:
return -EINVAL;
}
}
static struct file_operations TX2440_led_fops =
{
.owner = THIS_MODULE,
.open = TX2440_led_open,
.release = TX2440_led_release,
.ioctl = TX2440_led_ioctl,
};
static struct class *led_class;
static int __init TX2440_led_init(void)
{
printk("TX2440 LED DRIVER MODULE INIT\n");
LED_Major = register_chrdev(0, DEVICE_NAME, &TX2440_led_fops);
/*向内核注册一个设备,内核返回一个主设备号*/
if (LED_Major < 0)
{
printk(DEVICE_NAME " can't register major number\n");
return LED_Major;
}
printk("register TX2440-LED Driver OK! Major = %d\n", LED_Major);
led_class = class_create(THIS_MODULE, DEVICE_NAME);
/*在/sysfs目录下创建这个设备的类*/
if(IS_ERR(led_class))
{
printk("Err: failed in TX2440-LED class. \n");
return -1;
}
device_create(led_class, NULL, MKDEV(LED_Major, 0), NULL, DEVICE_NAME);
/*在/sysfs目录下注册这个设备,并创建设备节点*/
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit TX2440_led_exit(void)
{
printk("TX2440 LED DRIVER MODULE EXIT\n");
unregister_chrdev(LED_Major, DEVICE_NAME);
device_destroy(led_class, MKDEV(LED_Major, 0));
class_destroy(led_class);
}
module_init(TX2440_led_init);
module_exit(TX2440_led_exit);