led_dd.c 3.21 KB
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>


#define DRIVER_AUTHOR	"KHU"
#define DRIVER_DESC		"Led Driver"
#define DEVICE_NAME		"led_dd"
#define MAJOR_NUMBER	222

#define GPIO_BASE		0x3F200000
#define GPIO_SIZE		0xC0

#define INPUT			0
#define OUTPUT			1
#define LOW				0
#define HIGH			1

void __iomem *gpioAddr;
static unsigned long led_color[4] = {3, 7, 11, 15};
static unsigned long cur = 0;
volatile unsigned int gpioToGPFSEL[] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
};
volatile unsigned int gpioToShift[] = {
	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
};
volatile unsigned int gpioToGPSET = 0x1C;
volatile unsigned int gpioToGPCLR = 0x28;

const int Led[16] = {
	4, 17, 18, 27, 22, 23, 24, 25,
	6, 12, 13, 16, 19, 20, 26, 21
};

static volatile void initGpioAddr(void) {
	if(gpioAddr == NULL) {
		gpioAddr = ioremap(GPIO_BASE, GPIO_SIZE);
	}
}

static void pinMode(int pin, int mode) {
	volatile unsigned int *gpio = (volatile unsigned int *)gpioAddr;

	unsigned int fsel = gpioToGPFSEL[pin]/sizeof(unsigned int);
	unsigned int shift = gpioToShift[pin];

	if(mode) {
		gpio[fsel] |= (1 << shift);
	}
	else {
		gpio[fsel] |= (0 << shift);
	}
}

static void digitalWrite(int pin, int value) {
	volatile unsigned int *gpio = (volatile unsigned int *)gpioAddr;

	unsigned int set = gpioToGPSET/sizeof(unsigned int);
	unsigned int clr = gpioToGPCLR/sizeof(unsigned int);

	if(value) {
		gpio[set] = (1 << pin);
	}
	else {
		gpio[clr] = (1 << pin);
	}
}

static int led_open(struct inode *inode, struct file *filp) {
	int i;

	initGpioAddr();

	for(i = 0; i < 16; i++) {
		pinMode(Led[i], OUTPUT);
		digitalWrite(Led[i], LOW);
	}

	printk("[led_dd] led_open\n");

	return 0;
}

static int led_release(struct inode *inode, struct file *filp) {
	iounmap(gpioAddr);

	printk("[led_dd] led_realse\n");

	return 0;
}

static int led_write(struct file *filp, const char *buf,
					 size_t len, loff_t *f_pos) {
	int i;
	char state;
	
	printk("color is %lu\n",cur);
	for(i = 0; i < len; i++) {
		copy_from_user(&state, &buf[i], 1);

		if(state == '0') {
			digitalWrite(Led[led_color[cur]-i], LOW);
		}
		else {
			digitalWrite(Led[led_color[cur]-i], HIGH);
		}
	}

	printk("[led_dd] led_write\n");

	return len;
}

static int led_ioctl(struct file *filep, unsigned int cmd, unsigned long arg){
	printk("set cmd %ld\n",cmd);
	printk("set arg %ld\n",arg);
	if(copy_from_user(&cur, &arg ,sizeof(unsigned long))<1){
		printk("copy failed\n");
	}

	cur = arg;

	printk("set color %lu\n",cur);
	printk("[led_dd] led_ioctl\n");

	return 0;
}

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

static int led_init(void) {
	printk("[led_dd] led_init()\n");
	register_chrdev(MAJOR_NUMBER, DEVICE_NAME, &fops);

	return 0;
}

static void led_exit(void) {
	printk("[led_dd] led_exit()\n");
	unregister_chrdev(MAJOR_NUMBER, DEVICE_NAME);
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("Dual BSD/GPL");