首页 > 代码库 > Introduction to "s3c6410 LED" driver

Introduction to "s3c6410 LED" driver

Introduction to  driver for "s3c6410  LED"



          折腾着非得写个LED driver出来~不然心里都不舒服...  


内核版本:3.0.1

环境: Ubuntu14.0 TSL



开发板上嵌有4个LED灯

 

4个LED对应的ARM芯片上的引脚




易知,这里4个LED对应的IO引脚就是GPM0~GPM3


三个寄存器控制这里的GPIO -- GPM0~GPM3

  • GPMCON
  • GPMDAT
  • GPMPUD





这里gpio-bank-m.h定义了GPM相关的寄存器地址~这是一层爽歪歪的封装~(发现这是飞凌添加的header file...)


/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
 *
 * Copyright 2008 Openmoko, Inc.
 * Copyright 2008 Simtec Electronics
 *  Ben Dooks <ben@simtec.co.uk>
 *  http://armlinux.simtec.co.uk/
 *
 * GPIO Bank M register and configuration definitions
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
*/

#define S3C64XX_GPMCON          (S3C64XX_GPM_BASE + 0x00)
#define S3C64XX_GPMDAT          (S3C64XX_GPM_BASE + 0x04)
#define S3C64XX_GPMPUD          (S3C64XX_GPM_BASE + 0x08)

#define S3C64XX_GPM_CONMASK(__gpio) (0x3 << ((__gpio) * 2))
#define S3C64XX_GPM_INPUT(__gpio)   (0x0 << ((__gpio) * 2))
#define S3C64XX_GPM_OUTPUT(__gpio)  (0x1 << ((__gpio) * 2))

#define S3C64XX_GPM0_HOSTIF_CS      (0x02 << 0)
#define S3C64XX_GPM0_EINT23      (0x03 << 0)
#define S3C64XX_GPM0_RESERVED1      (0x04 << 0)
#define S3C64XX_GPM0_DATA_CF10      (0x05 << 0)
#define S3C64XX_GPM0_CE_CF0      (0x06 << 0)
#define S3C64XX_GPM0_RESERVED2      (0x07 << 0)

#define S3C64XX_GPM1_HOSTIF_CS_M      (0x02 << 0)
#define S3C64XX_GPM1_EINT24      (0x03 << 0)
#define S3C64XX_GPM1_RESERVED1      (0x04 << 0)
#define S3C64XX_GPM1_DATA_CF11      (0x05 << 0)
#define S3C64XX_GPM1_CE_CF1      (0x06 << 0)
#define S3C64XX_GPM1_RESERVED2      (0x07 << 0)

#define S3C64XX_GPM2_HOSTIF_IF_CS_S      (0x02 << 0)
#define S3C64XX_GPM2_EINT25      (0x03 << 0)
#define S3C64XX_GPM2_HOSTIF_MDP_VSYNC      (0x04 << 0)
#define S3C64XX_GPM2_DATA_CF12      (0x05 << 0)
#define S3C64XX_GPM2_IORD_CF      (0x06 << 0)
#define S3C64XX_GPM2_RESERVED2      (0x07 << 0)

#define S3C64XX_GPM3_HOSTIF_WE      (0x02 << 0)
#define S3C64XX_GPM3_EINT26      (0x03 << 0)
#define S3C64XX_GPM3_RESERVED1      (0x04 << 0)
#define S3C64XX_GPM3_DATA_CF13      (0x05 << 0)
#define S3C64XX_GPM3_IOWR_CF      (0x06 << 0)
#define S3C64XX_GPM3_RESERVED2      (0x07 << 0)

#define S3C64XX_GPM4_HOSTIF_OE      (0x02 << 0)
#define S3C64XX_GPM4_EINT27      (0x03 << 0)
#define S3C64XX_GPM4_RESERVED1      (0x04 << 0)
#define S3C64XX_GPM4_DATA_CF14      (0x05 << 0)
#define S3C64XX_GPM4_IORDY_CF      (0x06 << 0)
#define S3C64XX_GPM4_RESERVED2      (0x07 << 0)

#define S3C64XX_GPM5_HOSTIF_INTR      (0x02 << 0)
#define S3C64XX_GPM5_CF_DATA_DIR      (0x03 << 0)
#define S3C64XX_GPM5_RESERVED1      (0x04 << 0)
#define S3C64XX_GPM5_DATA_CF15      (0x05 << 0)
#define S3C64XX_GPM5_RESERVED2      (0x06 << 0)
#define S3C64XX_GPM5_RESERVED3      (0x07 << 0)

相关的有宏定义

S3C64XX_GPM_BASE
这个在regs-gpio.h 里面

节选了部分,不全部贴出了

...

#define S3C64XX_GPL_BASE	S3C64XX_GPIOREG(0x0810)
#define S3C64XX_GPM_BASE	S3C64XX_GPIOREG(0x0820)
#define S3C64XX_GPN_BASE	S3C64XX_GPIOREG(0x0830)
...

Here my source code for my led-device driver.

/*
code writer	: EOF
code date	: 2014.08.19.com
code file	: led_by_EOF.c
e-mail		: jasonleaster@gmail.com

code purpos:

	This code is a demo for beginner how to write a
character device to drive IO port.

	If you find there is something wrong with my code
and change it into a better version , please touch me 
by e-mail. Thank you.

*/
#include <linux/init.h>
#include <linux/slab.h>

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <asm/uaccess.h> /* for 'copy_from_user' */
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <mach/gpio-bank-m.h>
#include <mach/regs-gpio.h>
#include <mach/map.h>
#include <linux/pci.h>
#include <linux/device.h>


#include <linux/delay.h> /* for 'msleep' */

MODULE_AUTHOR("EOF");
MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME	"led_by_EOF"
#define DEVICE_MAJOR_NUMBER 0 

#define USE_IMMEDIATE

static dev_t dev_number = DEVICE_MAJOR_NUMBER;
static struct class* led_class;

static struct cdev my_led_cdev;

static int led_open(struct inode* node,struct file* file)
{
	printk(KERN_ALERT "Device Opened successful!\n");
	return 0;
}

static ssize_t led_write(struct file* file,const char __user* buf,size_t count,loff_t* ppos)
{
	int kbuf;
	int ret = 0;

	kbuf = readl(S3C64XX_GPMCON);
	kbuf &= (~0xFFFF);
	kbuf |= 0x1111;

	writel(kbuf,S3C64XX_GPMCON);

	printk(KERN_ALERT "before writing...  &kbuf:%p buf:%p\n",&kbuf,buf);
	ret = __copy_from_user(&kbuf,buf,count);
	if(ret != 0)
	{
		printk(KERN_ALERT "'__copy_from_user' failed! ret:%d\n",ret);
		
		return -1;
	}


	printk(KERN_ALERT "writing...   kbuf:%x \n",kbuf);

	writel(kbuf,S3C64XX_GPMDAT);

	return 0;
}

static int led_release(struct inode* inode,struct file*file)
{

	printk(KERN_ALERT "Device released\n");
	return 0;
}

static struct file_operations led_fops =
{
	.owner	=	THIS_MODULE,
	.open	=	led_open,
	.write	=	led_write,
	.release=	led_release,
};

int led_init(void)
{

	int kbuf;

	if(alloc_chrdev_region(&dev_number,0,1,DEVICE_NAME) < 0)
	{
		printk(KERN_ALERT "Error in function '%s' : can't register device\n",__FUNCTION__);

		return -1;
	}

	led_class = class_create(THIS_MODULE,DEVICE_NAME);

	if(IS_ERR(led_class))
	{
		printk(KERN_ALERT "Bad class create\n");

		return -1;
	}

	cdev_init(&my_led_cdev,&led_fops);

	/*
	** GPM0~GPM3 pull up
	*/
	kbuf = readl(S3C64XX_GPMPUD);

	kbuf &= (~0xFF);

	kbuf |= 0xaa;//1010 1010

	writel(kbuf,S3C64XX_GPMPUD);	

	/*
	** GPM0~3 output mode
	*/

	kbuf = readl(S3C64XX_GPMCON);
	kbuf &= (~0xFFFF);
	kbuf |= 0x1111;
	writel(kbuf,S3C64XX_GPMCON);

	/*
	**	GPM0~GPM3 output 0 and light up all LED
	*/

	kbuf  = __raw_readl(S3C64XX_GPMDAT);
	kbuf |= 0x10;
	writel(kbuf,S3C64XX_GPMDAT);


	if(cdev_add(&my_led_cdev,dev_number,1))
	{
		printk(KERN_ALERT "Bad cdev add\n");

		return 1;
	}

	device_create(led_class,NULL,dev_number,NULL,DEVICE_NAME);


	return 0;
}

void led_cleanup(void)
{
	device_destroy(led_class,MKDEV(MAJOR(dev_number),0));

	class_destroy(led_class);

	unregister_chrdev_region(MAJOR(dev_number),1);

	printk(KERN_ALERT "See you! My LED\n");
}

module_init(led_init);
module_exit(led_cleanup);


Test code:

/*
code writer	: EOF
code date	: 2014.08.19.com
code file	: led_by_EOF.c
e-mail		: jasonleaster@gmail.com

code purpos:

	This code is a demo for test my led-device.

	If you find there is something wrong with my code
and change it into a better version , please touch me 
by e-mail. Thank you.

*/

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
	int fd = 0;
	int ret = 0;

	if((fd = open("/dev/led_by_EOF",O_RDWR)) < 0)
	{
		printf("line %d open failed\n",__LINE__);
		return 0;
	}

	int buf = 0;
	int time = 0;

	buf = 0x0;

	for(time = 0,buf = 0;time < 5;time++)
	{
		if((ret = write(fd,&buf,sizeof(buf))) < 0)
		{
			printf("write error!\n ret : %d\n",ret);
			
			//goto failed;
		}
		else
		{
			printf("write successful! ret %d,buf:%d &buf:%p\n",ret,buf,&buf);
		}

		buf = ~buf;

		sleep(2);
	}
	

failed:
	close(fd);
	
	return 0;
}

最后灯会闪亮






Introduction to "s3c6410 LED" driver