1*4ce255c1SJaya Kumar /* 2*4ce255c1SJaya Kumar * am300epd.c -- Platform device for AM300 EPD kit 3*4ce255c1SJaya Kumar * 4*4ce255c1SJaya Kumar * Copyright (C) 2008, Jaya Kumar 5*4ce255c1SJaya Kumar * 6*4ce255c1SJaya Kumar * This file is subject to the terms and conditions of the GNU General Public 7*4ce255c1SJaya Kumar * License. See the file COPYING in the main directory of this archive for 8*4ce255c1SJaya Kumar * more details. 9*4ce255c1SJaya Kumar * 10*4ce255c1SJaya Kumar * This work was made possible by help and equipment support from E-Ink 11*4ce255c1SJaya Kumar * Corporation. http://support.eink.com/community 12*4ce255c1SJaya Kumar * 13*4ce255c1SJaya Kumar * This driver is written to be used with the Broadsheet display controller. 14*4ce255c1SJaya Kumar * on the AM300 EPD prototype kit/development kit with an E-Ink 800x600 15*4ce255c1SJaya Kumar * Vizplex EPD on a Gumstix board using the Broadsheet interface board. 16*4ce255c1SJaya Kumar * 17*4ce255c1SJaya Kumar */ 18*4ce255c1SJaya Kumar 19*4ce255c1SJaya Kumar #include <linux/module.h> 20*4ce255c1SJaya Kumar #include <linux/kernel.h> 21*4ce255c1SJaya Kumar #include <linux/errno.h> 22*4ce255c1SJaya Kumar #include <linux/string.h> 23*4ce255c1SJaya Kumar #include <linux/delay.h> 24*4ce255c1SJaya Kumar #include <linux/interrupt.h> 25*4ce255c1SJaya Kumar #include <linux/fb.h> 26*4ce255c1SJaya Kumar #include <linux/init.h> 27*4ce255c1SJaya Kumar #include <linux/platform_device.h> 28*4ce255c1SJaya Kumar #include <linux/irq.h> 29*4ce255c1SJaya Kumar #include <linux/gpio.h> 30*4ce255c1SJaya Kumar 31*4ce255c1SJaya Kumar #include <mach/gumstix.h> 32*4ce255c1SJaya Kumar #include <mach/mfp-pxa25x.h> 33*4ce255c1SJaya Kumar #include <mach/pxafb.h> 34*4ce255c1SJaya Kumar 35*4ce255c1SJaya Kumar #include "generic.h" 36*4ce255c1SJaya Kumar 37*4ce255c1SJaya Kumar #include <video/broadsheetfb.h> 38*4ce255c1SJaya Kumar 39*4ce255c1SJaya Kumar static unsigned int panel_type = 6; 40*4ce255c1SJaya Kumar static struct platform_device *am300_device; 41*4ce255c1SJaya Kumar static struct broadsheet_board am300_board; 42*4ce255c1SJaya Kumar 43*4ce255c1SJaya Kumar static unsigned long am300_pin_config[] __initdata = { 44*4ce255c1SJaya Kumar GPIO16_GPIO, 45*4ce255c1SJaya Kumar GPIO17_GPIO, 46*4ce255c1SJaya Kumar GPIO32_GPIO, 47*4ce255c1SJaya Kumar GPIO48_GPIO, 48*4ce255c1SJaya Kumar GPIO49_GPIO, 49*4ce255c1SJaya Kumar GPIO51_GPIO, 50*4ce255c1SJaya Kumar GPIO74_GPIO, 51*4ce255c1SJaya Kumar GPIO75_GPIO, 52*4ce255c1SJaya Kumar GPIO76_GPIO, 53*4ce255c1SJaya Kumar GPIO77_GPIO, 54*4ce255c1SJaya Kumar 55*4ce255c1SJaya Kumar /* this is the 16-bit hdb bus 58-73 */ 56*4ce255c1SJaya Kumar GPIO58_GPIO, 57*4ce255c1SJaya Kumar GPIO59_GPIO, 58*4ce255c1SJaya Kumar GPIO60_GPIO, 59*4ce255c1SJaya Kumar GPIO61_GPIO, 60*4ce255c1SJaya Kumar 61*4ce255c1SJaya Kumar GPIO62_GPIO, 62*4ce255c1SJaya Kumar GPIO63_GPIO, 63*4ce255c1SJaya Kumar GPIO64_GPIO, 64*4ce255c1SJaya Kumar GPIO65_GPIO, 65*4ce255c1SJaya Kumar 66*4ce255c1SJaya Kumar GPIO66_GPIO, 67*4ce255c1SJaya Kumar GPIO67_GPIO, 68*4ce255c1SJaya Kumar GPIO68_GPIO, 69*4ce255c1SJaya Kumar GPIO69_GPIO, 70*4ce255c1SJaya Kumar 71*4ce255c1SJaya Kumar GPIO70_GPIO, 72*4ce255c1SJaya Kumar GPIO71_GPIO, 73*4ce255c1SJaya Kumar GPIO72_GPIO, 74*4ce255c1SJaya Kumar GPIO73_GPIO, 75*4ce255c1SJaya Kumar }; 76*4ce255c1SJaya Kumar 77*4ce255c1SJaya Kumar /* register offsets for gpio control */ 78*4ce255c1SJaya Kumar #define PWR_GPIO_PIN 16 79*4ce255c1SJaya Kumar #define CFG_GPIO_PIN 17 80*4ce255c1SJaya Kumar #define RDY_GPIO_PIN 32 81*4ce255c1SJaya Kumar #define DC_GPIO_PIN 48 82*4ce255c1SJaya Kumar #define RST_GPIO_PIN 49 83*4ce255c1SJaya Kumar #define LED_GPIO_PIN 51 84*4ce255c1SJaya Kumar #define RD_GPIO_PIN 74 85*4ce255c1SJaya Kumar #define WR_GPIO_PIN 75 86*4ce255c1SJaya Kumar #define CS_GPIO_PIN 76 87*4ce255c1SJaya Kumar #define IRQ_GPIO_PIN 77 88*4ce255c1SJaya Kumar 89*4ce255c1SJaya Kumar /* hdb bus */ 90*4ce255c1SJaya Kumar #define DB0_GPIO_PIN 58 91*4ce255c1SJaya Kumar #define DB15_GPIO_PIN 73 92*4ce255c1SJaya Kumar 93*4ce255c1SJaya Kumar static int gpios[] = { PWR_GPIO_PIN, CFG_GPIO_PIN, RDY_GPIO_PIN, DC_GPIO_PIN, 94*4ce255c1SJaya Kumar RST_GPIO_PIN, RD_GPIO_PIN, WR_GPIO_PIN, CS_GPIO_PIN, 95*4ce255c1SJaya Kumar IRQ_GPIO_PIN, LED_GPIO_PIN }; 96*4ce255c1SJaya Kumar static char *gpio_names[] = { "PWR", "CFG", "RDY", "DC", "RST", "RD", "WR", 97*4ce255c1SJaya Kumar "CS", "IRQ", "LED" }; 98*4ce255c1SJaya Kumar 99*4ce255c1SJaya Kumar static int am300_wait_event(struct broadsheetfb_par *par) 100*4ce255c1SJaya Kumar { 101*4ce255c1SJaya Kumar /* todo: improve err recovery */ 102*4ce255c1SJaya Kumar wait_event(par->waitq, gpio_get_value(RDY_GPIO_PIN)); 103*4ce255c1SJaya Kumar return 0; 104*4ce255c1SJaya Kumar } 105*4ce255c1SJaya Kumar 106*4ce255c1SJaya Kumar static int am300_init_gpio_regs(struct broadsheetfb_par *par) 107*4ce255c1SJaya Kumar { 108*4ce255c1SJaya Kumar int i; 109*4ce255c1SJaya Kumar int err; 110*4ce255c1SJaya Kumar char dbname[8]; 111*4ce255c1SJaya Kumar 112*4ce255c1SJaya Kumar for (i = 0; i < ARRAY_SIZE(gpios); i++) { 113*4ce255c1SJaya Kumar err = gpio_request(gpios[i], gpio_names[i]); 114*4ce255c1SJaya Kumar if (err) { 115*4ce255c1SJaya Kumar dev_err(&am300_device->dev, "failed requesting " 116*4ce255c1SJaya Kumar "gpio %s, err=%d\n", gpio_names[i], err); 117*4ce255c1SJaya Kumar goto err_req_gpio; 118*4ce255c1SJaya Kumar } 119*4ce255c1SJaya Kumar } 120*4ce255c1SJaya Kumar 121*4ce255c1SJaya Kumar /* we also need to take care of the hdb bus */ 122*4ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) { 123*4ce255c1SJaya Kumar sprintf(dbname, "DB%d", i); 124*4ce255c1SJaya Kumar err = gpio_request(i, dbname); 125*4ce255c1SJaya Kumar if (err) { 126*4ce255c1SJaya Kumar dev_err(&am300_device->dev, "failed requesting " 127*4ce255c1SJaya Kumar "gpio %d, err=%d\n", i, err); 128*4ce255c1SJaya Kumar while (i >= DB0_GPIO_PIN) 129*4ce255c1SJaya Kumar gpio_free(i--); 130*4ce255c1SJaya Kumar i = ARRAY_SIZE(gpios) - 1; 131*4ce255c1SJaya Kumar goto err_req_gpio; 132*4ce255c1SJaya Kumar } 133*4ce255c1SJaya Kumar } 134*4ce255c1SJaya Kumar 135*4ce255c1SJaya Kumar /* setup the outputs and init values */ 136*4ce255c1SJaya Kumar gpio_direction_output(PWR_GPIO_PIN, 0); 137*4ce255c1SJaya Kumar gpio_direction_output(CFG_GPIO_PIN, 1); 138*4ce255c1SJaya Kumar gpio_direction_output(DC_GPIO_PIN, 0); 139*4ce255c1SJaya Kumar gpio_direction_output(RD_GPIO_PIN, 1); 140*4ce255c1SJaya Kumar gpio_direction_output(WR_GPIO_PIN, 1); 141*4ce255c1SJaya Kumar gpio_direction_output(CS_GPIO_PIN, 1); 142*4ce255c1SJaya Kumar gpio_direction_output(RST_GPIO_PIN, 0); 143*4ce255c1SJaya Kumar 144*4ce255c1SJaya Kumar /* setup the inputs */ 145*4ce255c1SJaya Kumar gpio_direction_input(RDY_GPIO_PIN); 146*4ce255c1SJaya Kumar gpio_direction_input(IRQ_GPIO_PIN); 147*4ce255c1SJaya Kumar 148*4ce255c1SJaya Kumar /* start the hdb bus as an input */ 149*4ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) 150*4ce255c1SJaya Kumar gpio_direction_output(i, 0); 151*4ce255c1SJaya Kumar 152*4ce255c1SJaya Kumar /* go into command mode */ 153*4ce255c1SJaya Kumar gpio_set_value(CFG_GPIO_PIN, 1); 154*4ce255c1SJaya Kumar gpio_set_value(RST_GPIO_PIN, 0); 155*4ce255c1SJaya Kumar msleep(10); 156*4ce255c1SJaya Kumar gpio_set_value(RST_GPIO_PIN, 1); 157*4ce255c1SJaya Kumar msleep(10); 158*4ce255c1SJaya Kumar am300_wait_event(par); 159*4ce255c1SJaya Kumar 160*4ce255c1SJaya Kumar return 0; 161*4ce255c1SJaya Kumar 162*4ce255c1SJaya Kumar err_req_gpio: 163*4ce255c1SJaya Kumar while (i > 0) 164*4ce255c1SJaya Kumar gpio_free(gpios[i--]); 165*4ce255c1SJaya Kumar 166*4ce255c1SJaya Kumar return err; 167*4ce255c1SJaya Kumar } 168*4ce255c1SJaya Kumar 169*4ce255c1SJaya Kumar static int am300_init_board(struct broadsheetfb_par *par) 170*4ce255c1SJaya Kumar { 171*4ce255c1SJaya Kumar return am300_init_gpio_regs(par); 172*4ce255c1SJaya Kumar } 173*4ce255c1SJaya Kumar 174*4ce255c1SJaya Kumar static void am300_cleanup(struct broadsheetfb_par *par) 175*4ce255c1SJaya Kumar { 176*4ce255c1SJaya Kumar int i; 177*4ce255c1SJaya Kumar 178*4ce255c1SJaya Kumar free_irq(IRQ_GPIO(RDY_GPIO_PIN), par); 179*4ce255c1SJaya Kumar 180*4ce255c1SJaya Kumar for (i = 0; i < ARRAY_SIZE(gpios); i++) 181*4ce255c1SJaya Kumar gpio_free(gpios[i]); 182*4ce255c1SJaya Kumar 183*4ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) 184*4ce255c1SJaya Kumar gpio_free(i); 185*4ce255c1SJaya Kumar 186*4ce255c1SJaya Kumar } 187*4ce255c1SJaya Kumar 188*4ce255c1SJaya Kumar static u16 am300_get_hdb(struct broadsheetfb_par *par) 189*4ce255c1SJaya Kumar { 190*4ce255c1SJaya Kumar u16 res = 0; 191*4ce255c1SJaya Kumar int i; 192*4ce255c1SJaya Kumar 193*4ce255c1SJaya Kumar for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++) 194*4ce255c1SJaya Kumar res |= (gpio_get_value(DB0_GPIO_PIN + i)) ? (1 << i) : 0; 195*4ce255c1SJaya Kumar 196*4ce255c1SJaya Kumar return res; 197*4ce255c1SJaya Kumar } 198*4ce255c1SJaya Kumar 199*4ce255c1SJaya Kumar static void am300_set_hdb(struct broadsheetfb_par *par, u16 data) 200*4ce255c1SJaya Kumar { 201*4ce255c1SJaya Kumar int i; 202*4ce255c1SJaya Kumar 203*4ce255c1SJaya Kumar for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++) 204*4ce255c1SJaya Kumar gpio_set_value(DB0_GPIO_PIN + i, (data >> i) & 0x01); 205*4ce255c1SJaya Kumar } 206*4ce255c1SJaya Kumar 207*4ce255c1SJaya Kumar 208*4ce255c1SJaya Kumar static void am300_set_ctl(struct broadsheetfb_par *par, unsigned char bit, 209*4ce255c1SJaya Kumar u8 state) 210*4ce255c1SJaya Kumar { 211*4ce255c1SJaya Kumar switch (bit) { 212*4ce255c1SJaya Kumar case BS_CS: 213*4ce255c1SJaya Kumar gpio_set_value(CS_GPIO_PIN, state); 214*4ce255c1SJaya Kumar break; 215*4ce255c1SJaya Kumar case BS_DC: 216*4ce255c1SJaya Kumar gpio_set_value(DC_GPIO_PIN, state); 217*4ce255c1SJaya Kumar break; 218*4ce255c1SJaya Kumar case BS_WR: 219*4ce255c1SJaya Kumar gpio_set_value(WR_GPIO_PIN, state); 220*4ce255c1SJaya Kumar break; 221*4ce255c1SJaya Kumar } 222*4ce255c1SJaya Kumar } 223*4ce255c1SJaya Kumar 224*4ce255c1SJaya Kumar static int am300_get_panel_type(void) 225*4ce255c1SJaya Kumar { 226*4ce255c1SJaya Kumar return panel_type; 227*4ce255c1SJaya Kumar } 228*4ce255c1SJaya Kumar 229*4ce255c1SJaya Kumar static irqreturn_t am300_handle_irq(int irq, void *dev_id) 230*4ce255c1SJaya Kumar { 231*4ce255c1SJaya Kumar struct broadsheetfb_par *par = dev_id; 232*4ce255c1SJaya Kumar 233*4ce255c1SJaya Kumar wake_up(&par->waitq); 234*4ce255c1SJaya Kumar return IRQ_HANDLED; 235*4ce255c1SJaya Kumar } 236*4ce255c1SJaya Kumar 237*4ce255c1SJaya Kumar static int am300_setup_irq(struct fb_info *info) 238*4ce255c1SJaya Kumar { 239*4ce255c1SJaya Kumar int ret; 240*4ce255c1SJaya Kumar struct broadsheetfb_par *par = info->par; 241*4ce255c1SJaya Kumar 242*4ce255c1SJaya Kumar ret = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am300_handle_irq, 243*4ce255c1SJaya Kumar IRQF_DISABLED|IRQF_TRIGGER_RISING, 244*4ce255c1SJaya Kumar "AM300", par); 245*4ce255c1SJaya Kumar if (ret) 246*4ce255c1SJaya Kumar dev_err(&am300_device->dev, "request_irq failed: %d\n", ret); 247*4ce255c1SJaya Kumar 248*4ce255c1SJaya Kumar return ret; 249*4ce255c1SJaya Kumar } 250*4ce255c1SJaya Kumar 251*4ce255c1SJaya Kumar static struct broadsheet_board am300_board = { 252*4ce255c1SJaya Kumar .owner = THIS_MODULE, 253*4ce255c1SJaya Kumar .init = am300_init_board, 254*4ce255c1SJaya Kumar .cleanup = am300_cleanup, 255*4ce255c1SJaya Kumar .set_hdb = am300_set_hdb, 256*4ce255c1SJaya Kumar .get_hdb = am300_get_hdb, 257*4ce255c1SJaya Kumar .set_ctl = am300_set_ctl, 258*4ce255c1SJaya Kumar .wait_for_rdy = am300_wait_event, 259*4ce255c1SJaya Kumar .get_panel_type = am300_get_panel_type, 260*4ce255c1SJaya Kumar .setup_irq = am300_setup_irq, 261*4ce255c1SJaya Kumar }; 262*4ce255c1SJaya Kumar 263*4ce255c1SJaya Kumar int __init am300_init(void) 264*4ce255c1SJaya Kumar { 265*4ce255c1SJaya Kumar int ret; 266*4ce255c1SJaya Kumar 267*4ce255c1SJaya Kumar pxa2xx_mfp_config(ARRAY_AND_SIZE(am300_pin_config)); 268*4ce255c1SJaya Kumar 269*4ce255c1SJaya Kumar /* request our platform independent driver */ 270*4ce255c1SJaya Kumar request_module("broadsheetfb"); 271*4ce255c1SJaya Kumar 272*4ce255c1SJaya Kumar am300_device = platform_device_alloc("broadsheetfb", -1); 273*4ce255c1SJaya Kumar if (!am300_device) 274*4ce255c1SJaya Kumar return -ENOMEM; 275*4ce255c1SJaya Kumar 276*4ce255c1SJaya Kumar /* the am300_board that will be seen by broadsheetfb is a copy */ 277*4ce255c1SJaya Kumar platform_device_add_data(am300_device, &am300_board, 278*4ce255c1SJaya Kumar sizeof(am300_board)); 279*4ce255c1SJaya Kumar 280*4ce255c1SJaya Kumar ret = platform_device_add(am300_device); 281*4ce255c1SJaya Kumar 282*4ce255c1SJaya Kumar if (ret) { 283*4ce255c1SJaya Kumar platform_device_put(am300_device); 284*4ce255c1SJaya Kumar return ret; 285*4ce255c1SJaya Kumar } 286*4ce255c1SJaya Kumar 287*4ce255c1SJaya Kumar return 0; 288*4ce255c1SJaya Kumar } 289*4ce255c1SJaya Kumar 290*4ce255c1SJaya Kumar module_param(panel_type, uint, 0); 291*4ce255c1SJaya Kumar MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97"); 292*4ce255c1SJaya Kumar 293*4ce255c1SJaya Kumar MODULE_DESCRIPTION("board driver for am300 epd kit"); 294*4ce255c1SJaya Kumar MODULE_AUTHOR("Jaya Kumar"); 295*4ce255c1SJaya Kumar MODULE_LICENSE("GPL"); 296