1aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar/* 20e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller 3aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * 4aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * Copyright (C) 2006, Jaya Kumar 5aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * This work was sponsored by CIS(M) Sdn Bhd 6aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * 7aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * This file is subject to the terms and conditions of the GNU General Public 8aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * License. See the file COPYING in the main directory of this archive for 9aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * more details. 10aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * 11aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. 12aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * This work was possible because of apollo display code from E-Ink's website 13aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * http://support.eink.com/community 14aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * All information used to write this code is from public material made 15aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * available by E-Ink on its support site. Some commands such as 0xA4 16aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * were found by looping through cmd=0x00 thru 0xFF and supplying random 17aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * values. There are other commands that the display is capable of, 18aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * beyond the 5 used here but they are more complex. 19aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * 200e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * This driver is written to be used with the Hecuba display architecture. 210e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * The actual display chip is called Apollo and the interface electronics 220e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * it needs is called Hecuba. 23aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * 240e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * It is intended to be architecture independent. A board specific driver 250e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * must be used to perform all the physical IO interactions. An example 260e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar * is provided as n411.c 27aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * 28aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar */ 29aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 30aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/module.h> 31aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/kernel.h> 32aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/errno.h> 33aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/string.h> 34aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/mm.h> 35aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/vmalloc.h> 36aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/delay.h> 37aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/interrupt.h> 38aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/fb.h> 39aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/init.h> 40aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/platform_device.h> 41aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#include <linux/list.h> 4284902b7af642c86a518c17629c0dbe705a4b6d14Krzysztof Helt#include <linux/uaccess.h> 43aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 440e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar#include <video/hecubafb.h> 45aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 46aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar/* Display specific information */ 47aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#define DPY_W 600 48aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar#define DPY_H 800 49aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 50aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic struct fb_fix_screeninfo hecubafb_fix __devinitdata = { 51aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .id = "hecubafb", 52aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .type = FB_TYPE_PACKED_PIXELS, 53aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .visual = FB_VISUAL_MONO01, 54aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .xpanstep = 0, 55aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .ypanstep = 0, 56aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .ywrapstep = 0, 570e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar .line_length = DPY_W, 58aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .accel = FB_ACCEL_NONE, 59aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar}; 60aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 61aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic struct fb_var_screeninfo hecubafb_var __devinitdata = { 62aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .xres = DPY_W, 63aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .yres = DPY_H, 64aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .xres_virtual = DPY_W, 65aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .yres_virtual = DPY_H, 66aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .bits_per_pixel = 1, 67aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .nonstd = 1, 68aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar}; 69aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 700e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar/* main hecubafb functions */ 71aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 729a268a629be4c15ed85c88a61d712d92aa943847Adrian Bunkstatic void apollo_send_data(struct hecubafb_par *par, unsigned char data) 73aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 74aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* set data */ 750e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->set_data(par, data); 76aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 77aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* set DS low */ 780e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->set_ctl(par, HCB_DS_BIT, 0); 79aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 800e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar /* wait for ack */ 810e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->wait_for_ack(par, 0); 82aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 83aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* set DS hi */ 840e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->set_ctl(par, HCB_DS_BIT, 1); 85aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 860e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar /* wait for ack to clear */ 870e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->wait_for_ack(par, 1); 88aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 89aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 909a268a629be4c15ed85c88a61d712d92aa943847Adrian Bunkstatic void apollo_send_command(struct hecubafb_par *par, unsigned char data) 91aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 92aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* command so set CD to high */ 930e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->set_ctl(par, HCB_CD_BIT, 1); 94aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 95aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* actually strobe with command */ 96aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar apollo_send_data(par, data); 97aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 98aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* clear CD back to low */ 990e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->set_ctl(par, HCB_CD_BIT, 0); 100aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 101aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 102aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic void hecubafb_dpy_update(struct hecubafb_par *par) 103aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 104aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar int i; 10528cdf76bf0bce757428f84161e3aa510028d47b4Antonino A. Daplas unsigned char *buf = (unsigned char __force *)par->info->screen_base; 106aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 1070e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar apollo_send_command(par, APOLLO_START_NEW_IMG); 108aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 109aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar for (i=0; i < (DPY_W*DPY_H/8); i++) { 110aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar apollo_send_data(par, *(buf++)); 111aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar } 112aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 1130e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar apollo_send_command(par, APOLLO_STOP_IMG_DATA); 1140e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar apollo_send_command(par, APOLLO_DISPLAY_IMG); 115aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 116aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 117aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar/* this is called back from the deferred io workqueue */ 118aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic void hecubafb_dpy_deferred_io(struct fb_info *info, 119aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct list_head *pagelist) 120aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 121aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar hecubafb_dpy_update(info->par); 122aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 123aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 124aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic void hecubafb_fillrect(struct fb_info *info, 125aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar const struct fb_fillrect *rect) 126aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 127aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct hecubafb_par *par = info->par; 128aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 129d6774935b61f99024121107d4ebb9d11b58052e6Antonino A. Daplas sys_fillrect(info, rect); 130aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 131aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar hecubafb_dpy_update(par); 132aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 133aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 134aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic void hecubafb_copyarea(struct fb_info *info, 135aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar const struct fb_copyarea *area) 136aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 137aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct hecubafb_par *par = info->par; 138aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 139d6774935b61f99024121107d4ebb9d11b58052e6Antonino A. Daplas sys_copyarea(info, area); 140aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 141aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar hecubafb_dpy_update(par); 142aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 143aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 144aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic void hecubafb_imageblit(struct fb_info *info, 145aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar const struct fb_image *image) 146aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 147aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct hecubafb_par *par = info->par; 148aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 149d6774935b61f99024121107d4ebb9d11b58052e6Antonino A. Daplas sys_imageblit(info, image); 150aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 151aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar hecubafb_dpy_update(par); 152aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 153aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 154aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar/* 155aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * this is the slow path from userspace. they can seek and write to 156aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar * the fb. it's inefficient to do anything less than a full screen draw 157aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar */ 1583f9b0880e4a96b02bc0131451f2f6231cd90bd94Antonino A. Daplasstatic ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, 159aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar size_t count, loff_t *ppos) 160aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 161963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar struct hecubafb_par *par = info->par; 162963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar unsigned long p = *ppos; 163963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar void *dst; 164963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar int err = 0; 165963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar unsigned long total_size; 166963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar 167963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (info->state != FBINFO_STATE_RUNNING) 168963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar return -EPERM; 169aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 170963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar total_size = info->fix.smem_len; 171aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 172963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (p > total_size) 173963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar return -EFBIG; 174aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 175963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (count > total_size) { 176963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar err = -EFBIG; 177963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar count = total_size; 178aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar } 179aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 180963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (count + p > total_size) { 181963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (!err) 182963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar err = -ENOSPC; 183aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 184963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar count = total_size - p; 185aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar } 186aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 187963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar dst = (void __force *) (info->screen_base + p); 188aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 189963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (copy_from_user(dst, buf, count)) 190963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar err = -EFAULT; 191963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar 192963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar if (!err) 193963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar *ppos += count; 194963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar 195963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar hecubafb_dpy_update(par); 196aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 197963654a9c919d18f8b9137f8ffd9d2d30a139269Jaya Kumar return (err) ? err : count; 198aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 199aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 200aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic struct fb_ops hecubafb_ops = { 201aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .owner = THIS_MODULE, 20228d4564bfd28e9fc9fe33695c431e3c3601faeb4Antonino A. Daplas .fb_read = fb_sys_read, 203aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .fb_write = hecubafb_write, 204aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .fb_fillrect = hecubafb_fillrect, 205aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .fb_copyarea = hecubafb_copyarea, 206aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .fb_imageblit = hecubafb_imageblit, 207aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar}; 208aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 209aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic struct fb_deferred_io hecubafb_defio = { 210aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .delay = HZ, 211aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .deferred_io = hecubafb_dpy_deferred_io, 212aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar}; 213aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 214aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic int __devinit hecubafb_probe(struct platform_device *dev) 215aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 216aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct fb_info *info; 2170e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar struct hecuba_board *board; 218aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar int retval = -ENOMEM; 219aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar int videomemorysize; 220aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar unsigned char *videomemory; 221aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct hecubafb_par *par; 222aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 2230e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar /* pick up board specific routines */ 2240e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar board = dev->dev.platform_data; 2250e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar if (!board) 2260e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar return -EINVAL; 2270e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar 2280e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar /* try to count device specific driver, if can't, platform recalls */ 2290e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar if (!try_module_get(board->owner)) 2300e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar return -ENODEV; 2310e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar 232aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar videomemorysize = (DPY_W*DPY_H)/8; 233aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 2341b86d775dd4c13967e1895df09d0cef198956e81Joe Perches videomemory = vzalloc(videomemorysize); 2351b86d775dd4c13967e1895df09d0cef198956e81Joe Perches if (!videomemory) 236291600193e5c0c3f0a9af1f23a8076dd7417c02aPavel Shved goto err_videomem_alloc; 237aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 238aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); 239aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar if (!info) 2400e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar goto err_fballoc; 241aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 2420e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar info->screen_base = (char __force __iomem *)videomemory; 243aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info->fbops = &hecubafb_ops; 244aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 245aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info->var = hecubafb_var; 246aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info->fix = hecubafb_fix; 247aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info->fix.smem_len = videomemorysize; 248aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar par = info->par; 249aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar par->info = info; 2500e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board = board; 2510e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->send_command = apollo_send_command; 2520e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->send_data = apollo_send_data; 253aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 254a9b5ff99c34e3f6ca7ad7fa01deba2df1108465eKonrad Rzeszutek Wilk info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; 255aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 256aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info->fbdefio = &hecubafb_defio; 257aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar fb_deferred_io_init(info); 258aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 259aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar retval = register_framebuffer(info); 260aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar if (retval < 0) 2610e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar goto err_fbreg; 262aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar platform_set_drvdata(dev, info); 263aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 264aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar printk(KERN_INFO 265aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar "fb%d: Hecuba frame buffer device, using %dK of video memory\n", 266aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar info->node, videomemorysize >> 10); 267aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 268aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar /* this inits the dpy */ 2690e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar retval = par->board->init(par); 2700e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar if (retval < 0) 2710e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar goto err_fbreg; 272aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 273aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar return 0; 2740e27aa3dabb541edee9f23b37114856a528de01eJaya Kumarerr_fbreg: 275aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar framebuffer_release(info); 2760e27aa3dabb541edee9f23b37114856a528de01eJaya Kumarerr_fballoc: 277aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar vfree(videomemory); 278291600193e5c0c3f0a9af1f23a8076dd7417c02aPavel Shvederr_videomem_alloc: 2790e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar module_put(board->owner); 280aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar return retval; 281aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 282aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 283aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic int __devexit hecubafb_remove(struct platform_device *dev) 284aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 285aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar struct fb_info *info = platform_get_drvdata(dev); 286aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 287aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar if (info) { 2880e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar struct hecubafb_par *par = info->par; 289aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar fb_deferred_io_cleanup(info); 290aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar unregister_framebuffer(info); 29128cdf76bf0bce757428f84161e3aa510028d47b4Antonino A. Daplas vfree((void __force *)info->screen_base); 2920e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar if (par->board->remove) 2930e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar par->board->remove(par); 2940e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar module_put(par->board->owner); 295aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar framebuffer_release(info); 296aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar } 297aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar return 0; 298aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 299aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 300aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic struct platform_driver hecubafb_driver = { 301aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .probe = hecubafb_probe, 30279ac33ec845c1872a23169644c5867528ff05590Axel Lin .remove = __devexit_p(hecubafb_remove), 303aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .driver = { 3040e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar .owner = THIS_MODULE, 305aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar .name = "hecubafb", 306aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar }, 307aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar}; 308aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 309aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic int __init hecubafb_init(void) 310aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 3110e27aa3dabb541edee9f23b37114856a528de01eJaya Kumar return platform_driver_register(&hecubafb_driver); 312aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 313aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 314aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarstatic void __exit hecubafb_exit(void) 315aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar{ 316aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar platform_driver_unregister(&hecubafb_driver); 317aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar} 318aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 319aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarmodule_init(hecubafb_init); 320aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumarmodule_exit(hecubafb_exit); 321aad09e51eeb6ec68029271642a7528ffc08fee81Jaya Kumar 3220e27aa3dabb541edee9f23b37114856a528de01eJaya KumarMODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller"); 323aad09e51eeb6ec68029271642a7528ffc08fee81Jaya KumarMODULE_AUTHOR("Jaya Kumar"); 324aad09e51eeb6ec68029271642a7528ffc08fee81Jaya KumarMODULE_LICENSE("GPL"); 325