1 /* 2 * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller 3 * 4 * Copyright (C) 2006, Jaya Kumar 5 * This work was sponsored by CIS(M) Sdn Bhd 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file COPYING in the main directory of this archive for 9 * more details. 10 * 11 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. 12 * This work was possible because of apollo display code from E-Ink's website 13 * http://support.eink.com/community 14 * All information used to write this code is from public material made 15 * available by E-Ink on its support site. Some commands such as 0xA4 16 * were found by looping through cmd=0x00 thru 0xFF and supplying random 17 * values. There are other commands that the display is capable of, 18 * beyond the 5 used here but they are more complex. 19 * 20 * This driver is written to be used with the Hecuba display architecture. 21 * The actual display chip is called Apollo and the interface electronics 22 * it needs is called Hecuba. 23 * 24 * It is intended to be architecture independent. A board specific driver 25 * must be used to perform all the physical IO interactions. An example 26 * is provided as n411.c 27 * 28 */ 29 30 #include <linux/module.h> 31 #include <linux/kernel.h> 32 #include <linux/errno.h> 33 #include <linux/string.h> 34 #include <linux/mm.h> 35 #include <linux/vmalloc.h> 36 #include <linux/delay.h> 37 #include <linux/interrupt.h> 38 #include <linux/fb.h> 39 #include <linux/init.h> 40 #include <linux/platform_device.h> 41 #include <linux/list.h> 42 #include <linux/uaccess.h> 43 44 #include <video/hecubafb.h> 45 46 /* Display specific information */ 47 #define DPY_W 600 48 #define DPY_H 800 49 50 static const struct fb_fix_screeninfo hecubafb_fix = { 51 .id = "hecubafb", 52 .type = FB_TYPE_PACKED_PIXELS, 53 .visual = FB_VISUAL_MONO01, 54 .xpanstep = 0, 55 .ypanstep = 0, 56 .ywrapstep = 0, 57 .line_length = DPY_W, 58 .accel = FB_ACCEL_NONE, 59 }; 60 61 static const struct fb_var_screeninfo hecubafb_var = { 62 .xres = DPY_W, 63 .yres = DPY_H, 64 .xres_virtual = DPY_W, 65 .yres_virtual = DPY_H, 66 .bits_per_pixel = 1, 67 .nonstd = 1, 68 }; 69 70 /* main hecubafb functions */ 71 72 static void apollo_send_data(struct hecubafb_par *par, unsigned char data) 73 { 74 /* set data */ 75 par->board->set_data(par, data); 76 77 /* set DS low */ 78 par->board->set_ctl(par, HCB_DS_BIT, 0); 79 80 /* wait for ack */ 81 par->board->wait_for_ack(par, 0); 82 83 /* set DS hi */ 84 par->board->set_ctl(par, HCB_DS_BIT, 1); 85 86 /* wait for ack to clear */ 87 par->board->wait_for_ack(par, 1); 88 } 89 90 static void apollo_send_command(struct hecubafb_par *par, unsigned char data) 91 { 92 /* command so set CD to high */ 93 par->board->set_ctl(par, HCB_CD_BIT, 1); 94 95 /* actually strobe with command */ 96 apollo_send_data(par, data); 97 98 /* clear CD back to low */ 99 par->board->set_ctl(par, HCB_CD_BIT, 0); 100 } 101 102 static void hecubafb_dpy_update(struct hecubafb_par *par) 103 { 104 int i; 105 unsigned char *buf = par->info->screen_buffer; 106 107 apollo_send_command(par, APOLLO_START_NEW_IMG); 108 109 for (i=0; i < (DPY_W*DPY_H/8); i++) { 110 apollo_send_data(par, *(buf++)); 111 } 112 113 apollo_send_command(par, APOLLO_STOP_IMG_DATA); 114 apollo_send_command(par, APOLLO_DISPLAY_IMG); 115 } 116 117 /* this is called back from the deferred io workqueue */ 118 static void hecubafb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) 119 { 120 hecubafb_dpy_update(info->par); 121 } 122 123 static void hecubafb_defio_damage_range(struct fb_info *info, off_t off, size_t len) 124 { 125 struct hecubafb_par *par = info->par; 126 127 hecubafb_dpy_update(par); 128 } 129 130 static void hecubafb_defio_damage_area(struct fb_info *info, u32 x, u32 y, 131 u32 width, u32 height) 132 { 133 struct hecubafb_par *par = info->par; 134 135 hecubafb_dpy_update(par); 136 } 137 138 FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(hecubafb, 139 hecubafb_defio_damage_range, 140 hecubafb_defio_damage_area) 141 142 static const struct fb_ops hecubafb_ops = { 143 .owner = THIS_MODULE, 144 FB_DEFAULT_DEFERRED_OPS(hecubafb), 145 }; 146 147 static struct fb_deferred_io hecubafb_defio = { 148 .delay = HZ, 149 .deferred_io = hecubafb_dpy_deferred_io, 150 }; 151 152 static int hecubafb_probe(struct platform_device *dev) 153 { 154 struct fb_info *info; 155 struct hecuba_board *board; 156 int retval = -ENOMEM; 157 int videomemorysize; 158 unsigned char *videomemory; 159 struct hecubafb_par *par; 160 161 /* pick up board specific routines */ 162 board = dev->dev.platform_data; 163 if (!board) 164 return -EINVAL; 165 166 /* try to count device specific driver, if can't, platform recalls */ 167 if (!try_module_get(board->owner)) 168 return -ENODEV; 169 170 videomemorysize = (DPY_W*DPY_H)/8; 171 172 videomemory = vzalloc(videomemorysize); 173 if (!videomemory) 174 goto err_videomem_alloc; 175 176 info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); 177 if (!info) 178 goto err_fballoc; 179 180 info->screen_buffer = videomemory; 181 info->fbops = &hecubafb_ops; 182 183 info->var = hecubafb_var; 184 info->fix = hecubafb_fix; 185 info->fix.smem_len = videomemorysize; 186 par = info->par; 187 par->info = info; 188 par->board = board; 189 par->send_command = apollo_send_command; 190 par->send_data = apollo_send_data; 191 192 info->flags = FBINFO_VIRTFB; 193 194 info->fbdefio = &hecubafb_defio; 195 fb_deferred_io_init(info); 196 197 retval = register_framebuffer(info); 198 if (retval < 0) 199 goto err_fbreg; 200 platform_set_drvdata(dev, info); 201 202 fb_info(info, "Hecuba frame buffer device, using %dK of video memory\n", 203 videomemorysize >> 10); 204 205 /* this inits the dpy */ 206 retval = par->board->init(par); 207 if (retval < 0) 208 goto err_fbreg; 209 210 return 0; 211 err_fbreg: 212 framebuffer_release(info); 213 err_fballoc: 214 vfree(videomemory); 215 err_videomem_alloc: 216 module_put(board->owner); 217 return retval; 218 } 219 220 static void hecubafb_remove(struct platform_device *dev) 221 { 222 struct fb_info *info = platform_get_drvdata(dev); 223 224 if (info) { 225 struct hecubafb_par *par = info->par; 226 fb_deferred_io_cleanup(info); 227 unregister_framebuffer(info); 228 vfree(info->screen_buffer); 229 if (par->board->remove) 230 par->board->remove(par); 231 module_put(par->board->owner); 232 framebuffer_release(info); 233 } 234 } 235 236 static struct platform_driver hecubafb_driver = { 237 .probe = hecubafb_probe, 238 .remove_new = hecubafb_remove, 239 .driver = { 240 .name = "hecubafb", 241 }, 242 }; 243 module_platform_driver(hecubafb_driver); 244 245 MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller"); 246 MODULE_AUTHOR("Jaya Kumar"); 247 MODULE_LICENSE("GPL"); 248