1 /* 2 * linux/drivers/video/n411.c -- Platform device for N411 EPD kit 3 * 4 * Copyright (C) 2008, Jaya Kumar 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive for 8 * more details. 9 * 10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. 11 * 12 * This driver is written to be used with the Hecuba display controller 13 * board, and tested with the EInk 800x600 display in 1 bit mode. 14 * The interface between Hecuba and the host is TTL based GPIO. The 15 * GPIO requirements are 8 writable data lines and 6 lines for control. 16 * Only 4 of the controls are actually used here but 6 for future use. 17 * The driver requires the IO addresses for data and control GPIO at 18 * load time. It is also possible to use this display with a standard 19 * PC parallel port. 20 * 21 * General notes: 22 * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR 23 * 24 */ 25 26 #include <linux/module.h> 27 #include <linux/kernel.h> 28 #include <linux/errno.h> 29 #include <linux/string.h> 30 #include <linux/delay.h> 31 #include <linux/interrupt.h> 32 #include <linux/fb.h> 33 #include <linux/init.h> 34 #include <linux/platform_device.h> 35 #include <linux/list.h> 36 #include <linux/uaccess.h> 37 #include <linux/irq.h> 38 39 #include <video/hecubafb.h> 40 41 static unsigned long dio_addr; 42 static unsigned long cio_addr; 43 static unsigned long c2io_addr; 44 static unsigned long splashval; 45 static unsigned int nosplash; 46 static unsigned char ctl; 47 48 static void n411_set_ctl(struct hecubafb_par *par, unsigned char bit, unsigned 49 char state) 50 { 51 switch (bit) { 52 case HCB_CD_BIT: 53 if (state) 54 ctl &= ~(HCB_CD_BIT); 55 else 56 ctl |= HCB_CD_BIT; 57 break; 58 case HCB_DS_BIT: 59 if (state) 60 ctl &= ~(HCB_DS_BIT); 61 else 62 ctl |= HCB_DS_BIT; 63 break; 64 } 65 outb(ctl, cio_addr); 66 } 67 68 static unsigned char n411_get_ctl(struct hecubafb_par *par) 69 { 70 return inb(c2io_addr); 71 } 72 73 static void n411_set_data(struct hecubafb_par *par, unsigned char value) 74 { 75 outb(value, dio_addr); 76 } 77 78 static void n411_wait_for_ack(struct hecubafb_par *par, int clear) 79 { 80 int timeout; 81 unsigned char tmp; 82 83 timeout = 500; 84 do { 85 tmp = n411_get_ctl(par); 86 if ((tmp & HCB_ACK_BIT) && (!clear)) 87 return; 88 else if (!(tmp & HCB_ACK_BIT) && (clear)) 89 return; 90 udelay(1); 91 } while (timeout--); 92 printk(KERN_ERR "timed out waiting for ack\n"); 93 } 94 95 static int n411_init_control(struct hecubafb_par *par) 96 { 97 unsigned char tmp; 98 /* for init, we want the following setup to be set: 99 WUP = lo 100 ACK = hi 101 DS = hi 102 RW = hi 103 CD = lo 104 */ 105 106 /* write WUP to lo, DS to hi, RW to hi, CD to lo */ 107 ctl = HCB_WUP_BIT | HCB_RW_BIT | HCB_CD_BIT ; 108 n411_set_ctl(par, HCB_DS_BIT, 1); 109 110 /* check ACK is not lo */ 111 tmp = n411_get_ctl(par); 112 if (tmp & HCB_ACK_BIT) { 113 printk(KERN_ERR "Fail because ACK is already low\n"); 114 return -ENXIO; 115 } 116 117 return 0; 118 } 119 120 121 static int n411_init_board(struct hecubafb_par *par) 122 { 123 int retval; 124 125 retval = n411_init_control(par); 126 if (retval) 127 return retval; 128 129 par->send_command(par, APOLLO_INIT_DISPLAY); 130 par->send_data(par, 0x81); 131 132 /* have to wait while display resets */ 133 udelay(1000); 134 135 /* if we were told to splash the screen, we just clear it */ 136 if (!nosplash) { 137 par->send_command(par, APOLLO_ERASE_DISPLAY); 138 par->send_data(par, splashval); 139 } 140 141 return 0; 142 } 143 144 static struct hecuba_board n411_board = { 145 .owner = THIS_MODULE, 146 .init = n411_init_board, 147 .set_ctl = n411_set_ctl, 148 .set_data = n411_set_data, 149 .wait_for_ack = n411_wait_for_ack, 150 }; 151 152 static struct platform_device *n411_device; 153 static int __init n411_init(void) 154 { 155 int ret; 156 if (!dio_addr || !cio_addr || !c2io_addr) { 157 printk(KERN_WARNING "no IO addresses supplied\n"); 158 return -EINVAL; 159 } 160 161 /* request our platform independent driver */ 162 request_module("hecubafb"); 163 164 n411_device = platform_device_alloc("hecubafb", -1); 165 if (!n411_device) 166 return -ENOMEM; 167 168 ret = platform_device_add_data(n411_device, &n411_board, 169 sizeof(n411_board)); 170 if (ret) 171 goto put_plat_device; 172 173 /* this _add binds hecubafb to n411. hecubafb refcounts n411 */ 174 ret = platform_device_add(n411_device); 175 176 if (ret) 177 goto put_plat_device; 178 179 return 0; 180 181 put_plat_device: 182 platform_device_put(n411_device); 183 return ret; 184 } 185 186 static void __exit n411_exit(void) 187 { 188 platform_device_unregister(n411_device); 189 } 190 191 module_init(n411_init); 192 module_exit(n411_exit); 193 194 module_param(nosplash, uint, 0); 195 MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); 196 module_param_hw(dio_addr, ulong, ioport, 0); 197 MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); 198 module_param_hw(cio_addr, ulong, ioport, 0); 199 MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); 200 module_param_hw(c2io_addr, ulong, ioport, 0); 201 MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); 202 module_param(splashval, ulong, 0); 203 MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); 204 205 MODULE_DESCRIPTION("board driver for n411 hecuba/apollo epd kit"); 206 MODULE_AUTHOR("Jaya Kumar"); 207 MODULE_LICENSE("GPL"); 208 209