kobox :gpio drv ok --gpio drv v2

TQ2440 GPIO驱动及测试代码,v2:将策略和机制分开,驱动只实现机制,应用层实现策略

下一步需要做的优化:

a. 打印优化

b. 错误处理--资源释放


driver src:

#include "gpio.h"
// ref arch/arm/mach-s3c24xx/mach-mini2440.c how to set gpio 
MODULE_LICENSE("GPL");
/*
datasheet: page274
— Port A(GPA): 25-output port
— Port B(GPB): 11-input/out port
— Port C(GPC): 16-input/output por
— Port D(GPD): 16-input/output por
— Port E(GPE): 16-input/output por
— Port F(GPF): 8-input/output port
— Port G(GPG): 16-input/output po
— Port H(GPH): 9-input/output port
— Port J(GPJ): 13-input/output port
*/

#define S3C_ADDR_BASE	0xF6000000
#define S3C_ADDR(x)	(S3C_ADDR_BASE + (x))
#define S3C2410_PA_UART		(0x50000000)
#define S3C2410_PA_GPIO		(0x56000000)
#define S3C_VA_UART	S3C_ADDR(0x01000000)	/* UART */
#define S3C24XX_PA_UART		S3C2410_PA_UART
#define S3C24XX_VA_UART		S3C_VA_UART
#define S3C24XX_PA_GPIO		S3C2410_PA_GPIO
#define S3C24XX_VA_GPIO		((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)

#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)

#define S3C2410_GPBCON	   S3C2410_GPIOREG(0x10)
#define S3C2410_GPBDAT	   S3C2410_GPIOREG(0x14)
#define S3C2410_GPBUP	   S3C2410_GPIOREG(0x18)

typedef struct
{
	unsigned port;
	unsigned pin;
	unsigned val;
}kobox_ioctl_st;

#define KOBOX_GPIO_IOCTL_MAIGC 'g'
#define KOBOX_GPIO_IOCTL_WRITE _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 0, kobox_ioctl_st)
#define KOBOX_GPIO_IOCTL_READ _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 1, kobox_ioctl_st)

static int kobox_gpio_open(struct inode *inode, struct file *file)
{
	return 0;
}

static int kobox_gpio_release(struct inode *inode, struct file *file)
{
	return 0;
}

static ssize_t kobox_gpio_read(struct file *file, __user char *buf, size_t count,
			     loff_t *offp)
{
	return 0;
}
static ssize_t kobox_gpio_write(struct file *file, const char __user *buf,
			      size_t count, loff_t *offp)
{
	return 0;
}

//set mux, set GPB_0 as gpio and output
/*
PORT CONFIGURATION REGISTER (GPACON-GPJCON)
In S3C2440A, most of the pins are multiplexed pins. So, It is determined which function is selected for each pins.
The PnCON(port control register) determines which function is used for each pin.
GPBCON 0x56000010 R/W Configures the pins of port B 0x0
GPB0 [1:0] 00 = Input  01 = Output	10 = TOUT0 11 = reserved
GPB1 [3:2] 00 = Input  01 = Output	10 = TOUT1 11 = reserved
GPB2 [5:4] 00 = Input  01 = Output	10 = TOUT2 11 = reserved
GPB3 [7:6] 00 = Input 01 = Output	10 = TOUT3 11 = reserved
GPB4 [9:8] 00 = Input  01 = Output	10 = TCLK [0] 11 = reserved
GPB5 [11:10] 00 = Input 01 = Output 10 = nXBACK 11 = reserved
GPB6 [13:12] 00 = Input  01 = Output 10 = nXBREQ 11 = reserved
GPB7 [15:14] 00 = Input  01 = Output 10 = nXDACK1 11 = Reserved
GPB8 [17:16] 00 = Input  01 = Output 10 = nXDREQ1 11 = Reserved
GPB9 [19:18] 00 = Input  01 = Output 10 = nXDACK0 11 = reserved
GPB10 [21:20] 00 = Input  01 = Output 10 = nXDREQ0 11 = reserved
*/
static int gpio_portb_set_init(unsigned pin)
{
	unsigned uiVal = 0;

	uiVal = readl(S3C2410_GPBCON);
	uiVal |= (0x01<<(2*pin)); 
	uiVal &= ~(0x01 <<((2*pin)+1)) ; 
	writel(uiVal, S3C2410_GPBCON);
	
	return 0;
}

/*
	GPB[10:0] [10:0] When the port is configured as input port, the corresponding bit is the pin
state. When the port is configured as output port, the pin state is the same
as the corresponding bit. When the port is configured as functional pin, the
undefined value will be read.
*/
static int gpio_portb_set_val(unsigned pin, unsigned val)
{
	unsigned uiVal = 0;

	printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__);
	printk("####[pin:%d][val:%d]\n", pin, val);

	if(0 == val)
	{
		uiVal = readl(S3C2410_GPBDAT);
		uiVal &= ~(0x01 << pin) ; 
		writel(uiVal, S3C2410_GPBDAT);
	}
	else if(1 == val)
	{
		uiVal = readl(S3C2410_GPBDAT);
		uiVal |= (0x01 << pin); 
		writel(uiVal, S3C2410_GPBDAT);
	}

	printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__);

	return 0;
}

static int set_gpio_portb_val(unsigned pin, unsigned val)
{
	printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__);
	printk("####[pin:%d][val:%d]\n", pin, val);

	gpio_portb_set_init(pin);
	gpio_portb_set_val(pin, val);

	printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__);

	return 0;
}

/*
	GPA: port = 0
	GPB: port = 1
	GPC: port = 2
	...
*/
static int set_gpio_val(unsigned port, unsigned pin, unsigned val)
{
	int ret;

	printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__);
	
	if(port == 1)
	{
		ret = set_gpio_portb_val(pin, val);
		if(ret < 0)
		{
			printk("set_gpio_portb_val failed!\n");			
		}
	}
	else
	{
		printk("not support other gpio ports now!\n");
		return -1;
	}

	printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__);	

	return ret;
}

static long kobox_gpio_ioctl(struct file *file, unsigned int cmd,
			   unsigned long arg)
{
	kobox_ioctl_st stGpioArg;
	unsigned port;
	unsigned pin;
	unsigned val;

	switch(cmd)
	{
		case KOBOX_GPIO_IOCTL_WRITE:
			printk("case KOBOX_GPIO_IOCTL_WRITE\n");
			copy_from_user((void*)&stGpioArg, (const void*)arg, sizeof(kobox_ioctl_st));
			port = stGpioArg.port;
			pin  = stGpioArg.pin;
			val  = stGpioArg.val;
			set_gpio_val(port, pin, val);
			break;

		case KOBOX_GPIO_IOCTL_READ:
			printk("case KOBOX_GPIO_IOCTL_READ\n");
			break;
		default:
			printk("Invalid cmd:%x\n", cmd);
			return -1;
	}
	
	return 0;
}

struct file_operations kobox_gpio_operations = {
	.owner          = THIS_MODULE,
	.open           = kobox_gpio_open,
	.release        = kobox_gpio_release,
	.read           = kobox_gpio_read,
	.write          = kobox_gpio_write,
	.unlocked_ioctl = kobox_gpio_ioctl,
};

//GPB0
int __init gpio_drv_init(void)
{
	int error;
	dev_t dev;
	int major;
	int minor;
	struct cdev cdev;
	struct class *kobox_gpio_class;

	printk("#####enter gpio_drv_init!\n");	

	major = register_chrdev(0, "kobox_gpio", &kobox_gpio_operations);
	if (major < 0)
	{
		printk(" can't register major number\n");
		return major;
	}

	/* create class */
	kobox_gpio_class = class_create(THIS_MODULE, "kobox_gpio");
	if(IS_ERR(kobox_gpio_class))
	{
		printk("class_create failed!\n");
		goto fail;
	}

	/* create /dev/kobox_gpio */
	device_create(kobox_gpio_class, NULL, MKDEV(major, 0), NULL, "kobox_gpio");

	printk("#####gpio_drv_init ok!\n");
	
	return 0;
	
fail:
	unregister_chrdev_region(cdev.dev, 1);
	return -1;
}

void __exit gpio_drv_exit(void)
{
	printk("exit gpio drv!\n");	

//	if(dev)
//		unregister_chrdev_region(cdev.dev, 1);

	return;
}

module_init(gpio_drv_init);
module_exit(gpio_drv_exit);


test src:


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define GPIO_NAME "/dev/kobox_gpio"

typedef struct
{
	unsigned port;
	unsigned pin;
	unsigned val;
}kobox_ioctl_st;

#define KOBOX_GPIO_IOCTL_MAIGC 'g'
#define KOBOX_GPIO_IOCTL_WRITE _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 0, kobox_ioctl_st)
#define KOBOX_GPIO_IOCTL_READ _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 1, kobox_ioctl_st)

int main(int argc, char *argv[])
{
	int i = 0;
	int fd = -1;
	int ret = 0;
	kobox_ioctl_st stGpioArg;

	fd = open(GPIO_NAME, O_RDWR);
	if(fd < 0)
	{
		printf("open /dev/kobox_gpio failed!\n");
		return -1;
	}

	printf("fd=%d\n", fd);

	stGpioArg.port = 1;//GPB:port = 1
	stGpioArg.pin = 0;

	for(i=0; i<=10;i++)
	{
		stGpioArg.val = i%2;

		printf("###port:%u, pin:%u, val:%u\n", stGpioArg.port, stGpioArg.pin, stGpioArg.val);
		
		ret = ioctl(fd, KOBOX_GPIO_IOCTL_WRITE, &stGpioArg);
		if(ret < 0)
		{
			printf("ioctl failed!\n");
			return -1;
		}
		sleep(1);
	}
	
	close(fd);

	return 0;
}

测试结果:

(1)蜂鸣器会每秒叫一次

(2)输出:

[\u@\h \W]# chmod 777 gpiotest 
[\u@\h \W]# ./gpiotest 
fd=3
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:0
###port:1, pin:0, val:1
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:0
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:1
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:0
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:1
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:0
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:1
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:0
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:1
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:1]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]
###port:1, pin:0, val:0
case KOBOX_GPIO_IOCTL_WRITE
####[func:set_gpio_val][line:200]
####[func:set_gpio_portb_val][line:179]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:156]
####[pin:0][val:0]
####[func:gpio_portb_set_val][line:172]
####[func:set_gpio_portb_val][line:185]
####[func:set_gpio_val][line:216]

(3)下一步需要做的优化:

a. 打印优化

b. 错误处理--资源释放


你可能感兴趣的:(学习计划,驱动包,TQ2440)