/* Kernel SPI driver for WRT54G */ #define MODULE #define LINUX #define __KERNEL__ #include #include #include #include #include /* -------- GPIO DEFINES ---------- */ #define GPIO_DOUT (1<<1) #define GPIO_CLK (1<<2) #define GPIO_CS (1<<3) #define GPIO_DC (1<<7) #define IOMASK (GPIO_DOUT | GPIO_CLK | GPIO_CS | GPIO_DC) typedef unsigned int uint32; static volatile uint32 *gpioaddr_input = (uint32 *)0xb8000060; static volatile uint32 *gpioaddr_output = (uint32 *)0xb8000064; static volatile uint32 *gpioaddr_enable = (uint32 *)0xb8000068; static volatile uint32 *gpioaddr_control = (uint32 *)0xb800006c; /* ---------- PROTOTYPES -------- */ int init_module(void); void cleanup_module(void); static int device_open(struct inode *, struct file *); static int device_release(struct inode *, struct file *); static ssize_t device_write(struct file *, const char *, size_t, loff_t *); static int device_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static inline void spi_wait(void); static inline void spi_end(void); static inline void spi_writebyte(unsigned char byte, int dc); /* --------- GLOBAL VARIABLES ---------- */ static int device_open_count = 0; /* ---------- INITIALIZATION AND CLEANUP --------- */ static struct file_operations fops = { .write = device_write, .open = device_open, .release = device_release, .ioctl = device_ioctl }; #define DEVICE_NAME "3310lcd" #define MY_MAJOR 240 #define IOCTL_SPI_COMMAND 0x600 int init_module(void) { *gpioaddr_enable |= IOMASK; *gpioaddr_output |= IOMASK; int ret = register_chrdev(MY_MAJOR, DEVICE_NAME, &fops); if (ret < 0) { printk("Error in register_chrdev: %d\n", ret); return ret; } else { return 0; } } void cleanup_module(void) { int ret = unregister_chrdev(MY_MAJOR, DEVICE_NAME); if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret); } /* ---------- DEVICE ACCESS -------- */ static int device_open(struct inode *inode, struct file *file) { if (device_open_count) return -EBUSY; device_open_count++; MOD_INC_USE_COUNT; return 0; } static int device_release(struct inode *inode, struct file *file) { device_open_count--; MOD_DEC_USE_COUNT; return 0; } static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t *off) { size_t i; const char *p = buff; for (i = 0; i < len; i++) { spi_writebyte(*p, 1); p++; } spi_end(); return len; } static int device_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { if (ioctl_num == IOCTL_SPI_COMMAND) { unsigned char *param = (unsigned char *) ioctl_param; spi_writebyte(*param, 0); spi_end(); } return 0; } /* ----------- SPI ACCESS --------- */ static inline void spi_wait() { udelay(1); } static inline void spi_end() { *gpioaddr_output |= GPIO_CS; *gpioaddr_output |= IOMASK; } static inline void spi_writebyte(unsigned char byte, int dc) { uint32 reg; reg = *gpioaddr_output; if (dc) reg |= GPIO_DC; else reg &= ~GPIO_DC; reg &= ~GPIO_CS; reg &= ~GPIO_CLK; *gpioaddr_output = reg; spi_wait(); int i; for (i = 7; i >= 0; i--) { if (byte & (1 << i)) *gpioaddr_output |= GPIO_DOUT; else *gpioaddr_output &= ~GPIO_DOUT; spi_wait(); *gpioaddr_output |= GPIO_CLK; spi_wait(); *gpioaddr_output &= ~GPIO_CLK; } } MODULE_LICENSE("GPL");