14ce255c1SJaya Kumar /* 24ce255c1SJaya Kumar * am300epd.c -- Platform device for AM300 EPD kit 34ce255c1SJaya Kumar * 44ce255c1SJaya Kumar * Copyright (C) 2008, Jaya Kumar 54ce255c1SJaya Kumar * 64ce255c1SJaya Kumar * This file is subject to the terms and conditions of the GNU General Public 74ce255c1SJaya Kumar * License. See the file COPYING in the main directory of this archive for 84ce255c1SJaya Kumar * more details. 94ce255c1SJaya Kumar * 104ce255c1SJaya Kumar * This work was made possible by help and equipment support from E-Ink 114ce255c1SJaya Kumar * Corporation. http://support.eink.com/community 124ce255c1SJaya Kumar * 134ce255c1SJaya Kumar * This driver is written to be used with the Broadsheet display controller. 144ce255c1SJaya Kumar * on the AM300 EPD prototype kit/development kit with an E-Ink 800x600 154ce255c1SJaya Kumar * Vizplex EPD on a Gumstix board using the Broadsheet interface board. 164ce255c1SJaya Kumar * 174ce255c1SJaya Kumar */ 184ce255c1SJaya Kumar 194ce255c1SJaya Kumar #include <linux/module.h> 204ce255c1SJaya Kumar #include <linux/kernel.h> 214ce255c1SJaya Kumar #include <linux/errno.h> 224ce255c1SJaya Kumar #include <linux/string.h> 234ce255c1SJaya Kumar #include <linux/delay.h> 244ce255c1SJaya Kumar #include <linux/interrupt.h> 254ce255c1SJaya Kumar #include <linux/fb.h> 264ce255c1SJaya Kumar #include <linux/init.h> 274ce255c1SJaya Kumar #include <linux/platform_device.h> 284ce255c1SJaya Kumar #include <linux/irq.h> 294ce255c1SJaya Kumar #include <linux/gpio.h> 304ce255c1SJaya Kumar 314ce255c1SJaya Kumar #include <mach/gumstix.h> 324ce255c1SJaya Kumar #include <mach/mfp-pxa25x.h> 334ce255c1SJaya Kumar #include <mach/pxafb.h> 344ce255c1SJaya Kumar 354ce255c1SJaya Kumar #include "generic.h" 364ce255c1SJaya Kumar 374ce255c1SJaya Kumar #include <video/broadsheetfb.h> 384ce255c1SJaya Kumar 394ce255c1SJaya Kumar static unsigned int panel_type = 6; 404ce255c1SJaya Kumar static struct platform_device *am300_device; 414ce255c1SJaya Kumar static struct broadsheet_board am300_board; 424ce255c1SJaya Kumar 434ce255c1SJaya Kumar static unsigned long am300_pin_config[] __initdata = { 444ce255c1SJaya Kumar GPIO16_GPIO, 454ce255c1SJaya Kumar GPIO17_GPIO, 464ce255c1SJaya Kumar GPIO32_GPIO, 474ce255c1SJaya Kumar GPIO48_GPIO, 484ce255c1SJaya Kumar GPIO49_GPIO, 494ce255c1SJaya Kumar GPIO51_GPIO, 504ce255c1SJaya Kumar GPIO74_GPIO, 514ce255c1SJaya Kumar GPIO75_GPIO, 524ce255c1SJaya Kumar GPIO76_GPIO, 534ce255c1SJaya Kumar GPIO77_GPIO, 544ce255c1SJaya Kumar 554ce255c1SJaya Kumar /* this is the 16-bit hdb bus 58-73 */ 564ce255c1SJaya Kumar GPIO58_GPIO, 574ce255c1SJaya Kumar GPIO59_GPIO, 584ce255c1SJaya Kumar GPIO60_GPIO, 594ce255c1SJaya Kumar GPIO61_GPIO, 604ce255c1SJaya Kumar 614ce255c1SJaya Kumar GPIO62_GPIO, 624ce255c1SJaya Kumar GPIO63_GPIO, 634ce255c1SJaya Kumar GPIO64_GPIO, 644ce255c1SJaya Kumar GPIO65_GPIO, 654ce255c1SJaya Kumar 664ce255c1SJaya Kumar GPIO66_GPIO, 674ce255c1SJaya Kumar GPIO67_GPIO, 684ce255c1SJaya Kumar GPIO68_GPIO, 694ce255c1SJaya Kumar GPIO69_GPIO, 704ce255c1SJaya Kumar 714ce255c1SJaya Kumar GPIO70_GPIO, 724ce255c1SJaya Kumar GPIO71_GPIO, 734ce255c1SJaya Kumar GPIO72_GPIO, 744ce255c1SJaya Kumar GPIO73_GPIO, 754ce255c1SJaya Kumar }; 764ce255c1SJaya Kumar 774ce255c1SJaya Kumar /* register offsets for gpio control */ 784ce255c1SJaya Kumar #define PWR_GPIO_PIN 16 794ce255c1SJaya Kumar #define CFG_GPIO_PIN 17 804ce255c1SJaya Kumar #define RDY_GPIO_PIN 32 814ce255c1SJaya Kumar #define DC_GPIO_PIN 48 824ce255c1SJaya Kumar #define RST_GPIO_PIN 49 834ce255c1SJaya Kumar #define LED_GPIO_PIN 51 844ce255c1SJaya Kumar #define RD_GPIO_PIN 74 854ce255c1SJaya Kumar #define WR_GPIO_PIN 75 864ce255c1SJaya Kumar #define CS_GPIO_PIN 76 874ce255c1SJaya Kumar #define IRQ_GPIO_PIN 77 884ce255c1SJaya Kumar 894ce255c1SJaya Kumar /* hdb bus */ 904ce255c1SJaya Kumar #define DB0_GPIO_PIN 58 914ce255c1SJaya Kumar #define DB15_GPIO_PIN 73 924ce255c1SJaya Kumar 934ce255c1SJaya Kumar static int gpios[] = { PWR_GPIO_PIN, CFG_GPIO_PIN, RDY_GPIO_PIN, DC_GPIO_PIN, 944ce255c1SJaya Kumar RST_GPIO_PIN, RD_GPIO_PIN, WR_GPIO_PIN, CS_GPIO_PIN, 954ce255c1SJaya Kumar IRQ_GPIO_PIN, LED_GPIO_PIN }; 964ce255c1SJaya Kumar static char *gpio_names[] = { "PWR", "CFG", "RDY", "DC", "RST", "RD", "WR", 974ce255c1SJaya Kumar "CS", "IRQ", "LED" }; 984ce255c1SJaya Kumar 994ce255c1SJaya Kumar static int am300_wait_event(struct broadsheetfb_par *par) 1004ce255c1SJaya Kumar { 1014ce255c1SJaya Kumar /* todo: improve err recovery */ 1024ce255c1SJaya Kumar wait_event(par->waitq, gpio_get_value(RDY_GPIO_PIN)); 1034ce255c1SJaya Kumar return 0; 1044ce255c1SJaya Kumar } 1054ce255c1SJaya Kumar 1064ce255c1SJaya Kumar static int am300_init_gpio_regs(struct broadsheetfb_par *par) 1074ce255c1SJaya Kumar { 1084ce255c1SJaya Kumar int i; 1094ce255c1SJaya Kumar int err; 1104ce255c1SJaya Kumar char dbname[8]; 1114ce255c1SJaya Kumar 1124ce255c1SJaya Kumar for (i = 0; i < ARRAY_SIZE(gpios); i++) { 1134ce255c1SJaya Kumar err = gpio_request(gpios[i], gpio_names[i]); 1144ce255c1SJaya Kumar if (err) { 1154ce255c1SJaya Kumar dev_err(&am300_device->dev, "failed requesting " 1164ce255c1SJaya Kumar "gpio %s, err=%d\n", gpio_names[i], err); 1174ce255c1SJaya Kumar goto err_req_gpio; 1184ce255c1SJaya Kumar } 1194ce255c1SJaya Kumar } 1204ce255c1SJaya Kumar 1214ce255c1SJaya Kumar /* we also need to take care of the hdb bus */ 1224ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) { 1234ce255c1SJaya Kumar sprintf(dbname, "DB%d", i); 1244ce255c1SJaya Kumar err = gpio_request(i, dbname); 1254ce255c1SJaya Kumar if (err) { 1264ce255c1SJaya Kumar dev_err(&am300_device->dev, "failed requesting " 1274ce255c1SJaya Kumar "gpio %d, err=%d\n", i, err); 128*5898eb79SAxel Lin goto err_req_gpio2; 1294ce255c1SJaya Kumar } 1304ce255c1SJaya Kumar } 1314ce255c1SJaya Kumar 1324ce255c1SJaya Kumar /* setup the outputs and init values */ 1334ce255c1SJaya Kumar gpio_direction_output(PWR_GPIO_PIN, 0); 1344ce255c1SJaya Kumar gpio_direction_output(CFG_GPIO_PIN, 1); 1354ce255c1SJaya Kumar gpio_direction_output(DC_GPIO_PIN, 0); 1364ce255c1SJaya Kumar gpio_direction_output(RD_GPIO_PIN, 1); 1374ce255c1SJaya Kumar gpio_direction_output(WR_GPIO_PIN, 1); 1384ce255c1SJaya Kumar gpio_direction_output(CS_GPIO_PIN, 1); 1394ce255c1SJaya Kumar gpio_direction_output(RST_GPIO_PIN, 0); 1404ce255c1SJaya Kumar 1414ce255c1SJaya Kumar /* setup the inputs */ 1424ce255c1SJaya Kumar gpio_direction_input(RDY_GPIO_PIN); 1434ce255c1SJaya Kumar gpio_direction_input(IRQ_GPIO_PIN); 1444ce255c1SJaya Kumar 1454ce255c1SJaya Kumar /* start the hdb bus as an input */ 1464ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) 1474ce255c1SJaya Kumar gpio_direction_output(i, 0); 1484ce255c1SJaya Kumar 1494ce255c1SJaya Kumar /* go into command mode */ 1504ce255c1SJaya Kumar gpio_set_value(CFG_GPIO_PIN, 1); 1514ce255c1SJaya Kumar gpio_set_value(RST_GPIO_PIN, 0); 1524ce255c1SJaya Kumar msleep(10); 1534ce255c1SJaya Kumar gpio_set_value(RST_GPIO_PIN, 1); 1544ce255c1SJaya Kumar msleep(10); 1554ce255c1SJaya Kumar am300_wait_event(par); 1564ce255c1SJaya Kumar 1574ce255c1SJaya Kumar return 0; 1584ce255c1SJaya Kumar 159*5898eb79SAxel Lin err_req_gpio2: 160*5898eb79SAxel Lin while (--i >= DB0_GPIO_PIN) 161*5898eb79SAxel Lin gpio_free(i); 162*5898eb79SAxel Lin i = ARRAY_SIZE(gpios); 1634ce255c1SJaya Kumar err_req_gpio: 164*5898eb79SAxel Lin while (--i >= 0) 165*5898eb79SAxel Lin gpio_free(gpios[i]); 1664ce255c1SJaya Kumar 1674ce255c1SJaya Kumar return err; 1684ce255c1SJaya Kumar } 1694ce255c1SJaya Kumar 1704ce255c1SJaya Kumar static int am300_init_board(struct broadsheetfb_par *par) 1714ce255c1SJaya Kumar { 1724ce255c1SJaya Kumar return am300_init_gpio_regs(par); 1734ce255c1SJaya Kumar } 1744ce255c1SJaya Kumar 1754ce255c1SJaya Kumar static void am300_cleanup(struct broadsheetfb_par *par) 1764ce255c1SJaya Kumar { 1774ce255c1SJaya Kumar int i; 1784ce255c1SJaya Kumar 1794ce255c1SJaya Kumar free_irq(IRQ_GPIO(RDY_GPIO_PIN), par); 1804ce255c1SJaya Kumar 1814ce255c1SJaya Kumar for (i = 0; i < ARRAY_SIZE(gpios); i++) 1824ce255c1SJaya Kumar gpio_free(gpios[i]); 1834ce255c1SJaya Kumar 1844ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) 1854ce255c1SJaya Kumar gpio_free(i); 1864ce255c1SJaya Kumar 1874ce255c1SJaya Kumar } 1884ce255c1SJaya Kumar 1894ce255c1SJaya Kumar static u16 am300_get_hdb(struct broadsheetfb_par *par) 1904ce255c1SJaya Kumar { 1914ce255c1SJaya Kumar u16 res = 0; 1924ce255c1SJaya Kumar int i; 1934ce255c1SJaya Kumar 1944ce255c1SJaya Kumar for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++) 1954ce255c1SJaya Kumar res |= (gpio_get_value(DB0_GPIO_PIN + i)) ? (1 << i) : 0; 1964ce255c1SJaya Kumar 1974ce255c1SJaya Kumar return res; 1984ce255c1SJaya Kumar } 1994ce255c1SJaya Kumar 2004ce255c1SJaya Kumar static void am300_set_hdb(struct broadsheetfb_par *par, u16 data) 2014ce255c1SJaya Kumar { 2024ce255c1SJaya Kumar int i; 2034ce255c1SJaya Kumar 2044ce255c1SJaya Kumar for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++) 2054ce255c1SJaya Kumar gpio_set_value(DB0_GPIO_PIN + i, (data >> i) & 0x01); 2064ce255c1SJaya Kumar } 2074ce255c1SJaya Kumar 2084ce255c1SJaya Kumar 2094ce255c1SJaya Kumar static void am300_set_ctl(struct broadsheetfb_par *par, unsigned char bit, 2104ce255c1SJaya Kumar u8 state) 2114ce255c1SJaya Kumar { 2124ce255c1SJaya Kumar switch (bit) { 2134ce255c1SJaya Kumar case BS_CS: 2144ce255c1SJaya Kumar gpio_set_value(CS_GPIO_PIN, state); 2154ce255c1SJaya Kumar break; 2164ce255c1SJaya Kumar case BS_DC: 2174ce255c1SJaya Kumar gpio_set_value(DC_GPIO_PIN, state); 2184ce255c1SJaya Kumar break; 2194ce255c1SJaya Kumar case BS_WR: 2204ce255c1SJaya Kumar gpio_set_value(WR_GPIO_PIN, state); 2214ce255c1SJaya Kumar break; 2224ce255c1SJaya Kumar } 2234ce255c1SJaya Kumar } 2244ce255c1SJaya Kumar 2254ce255c1SJaya Kumar static int am300_get_panel_type(void) 2264ce255c1SJaya Kumar { 2274ce255c1SJaya Kumar return panel_type; 2284ce255c1SJaya Kumar } 2294ce255c1SJaya Kumar 2304ce255c1SJaya Kumar static irqreturn_t am300_handle_irq(int irq, void *dev_id) 2314ce255c1SJaya Kumar { 2324ce255c1SJaya Kumar struct broadsheetfb_par *par = dev_id; 2334ce255c1SJaya Kumar 2344ce255c1SJaya Kumar wake_up(&par->waitq); 2354ce255c1SJaya Kumar return IRQ_HANDLED; 2364ce255c1SJaya Kumar } 2374ce255c1SJaya Kumar 2384ce255c1SJaya Kumar static int am300_setup_irq(struct fb_info *info) 2394ce255c1SJaya Kumar { 2404ce255c1SJaya Kumar int ret; 2414ce255c1SJaya Kumar struct broadsheetfb_par *par = info->par; 2424ce255c1SJaya Kumar 2434ce255c1SJaya Kumar ret = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am300_handle_irq, 2444ce255c1SJaya Kumar IRQF_DISABLED|IRQF_TRIGGER_RISING, 2454ce255c1SJaya Kumar "AM300", par); 2464ce255c1SJaya Kumar if (ret) 2474ce255c1SJaya Kumar dev_err(&am300_device->dev, "request_irq failed: %d\n", ret); 2484ce255c1SJaya Kumar 2494ce255c1SJaya Kumar return ret; 2504ce255c1SJaya Kumar } 2514ce255c1SJaya Kumar 2524ce255c1SJaya Kumar static struct broadsheet_board am300_board = { 2534ce255c1SJaya Kumar .owner = THIS_MODULE, 2544ce255c1SJaya Kumar .init = am300_init_board, 2554ce255c1SJaya Kumar .cleanup = am300_cleanup, 2564ce255c1SJaya Kumar .set_hdb = am300_set_hdb, 2574ce255c1SJaya Kumar .get_hdb = am300_get_hdb, 2584ce255c1SJaya Kumar .set_ctl = am300_set_ctl, 2594ce255c1SJaya Kumar .wait_for_rdy = am300_wait_event, 2604ce255c1SJaya Kumar .get_panel_type = am300_get_panel_type, 2614ce255c1SJaya Kumar .setup_irq = am300_setup_irq, 2624ce255c1SJaya Kumar }; 2634ce255c1SJaya Kumar 2644ce255c1SJaya Kumar int __init am300_init(void) 2654ce255c1SJaya Kumar { 2664ce255c1SJaya Kumar int ret; 2674ce255c1SJaya Kumar 2684ce255c1SJaya Kumar pxa2xx_mfp_config(ARRAY_AND_SIZE(am300_pin_config)); 2694ce255c1SJaya Kumar 2704ce255c1SJaya Kumar /* request our platform independent driver */ 2714ce255c1SJaya Kumar request_module("broadsheetfb"); 2724ce255c1SJaya Kumar 2734ce255c1SJaya Kumar am300_device = platform_device_alloc("broadsheetfb", -1); 2744ce255c1SJaya Kumar if (!am300_device) 2754ce255c1SJaya Kumar return -ENOMEM; 2764ce255c1SJaya Kumar 2774ce255c1SJaya Kumar /* the am300_board that will be seen by broadsheetfb is a copy */ 2784ce255c1SJaya Kumar platform_device_add_data(am300_device, &am300_board, 2794ce255c1SJaya Kumar sizeof(am300_board)); 2804ce255c1SJaya Kumar 2814ce255c1SJaya Kumar ret = platform_device_add(am300_device); 2824ce255c1SJaya Kumar 2834ce255c1SJaya Kumar if (ret) { 2844ce255c1SJaya Kumar platform_device_put(am300_device); 2854ce255c1SJaya Kumar return ret; 2864ce255c1SJaya Kumar } 2874ce255c1SJaya Kumar 2884ce255c1SJaya Kumar return 0; 2894ce255c1SJaya Kumar } 2904ce255c1SJaya Kumar 2914ce255c1SJaya Kumar module_param(panel_type, uint, 0); 292c1c341a0SJaya Kumar MODULE_PARM_DESC(panel_type, "Select the panel type: 37, 6, 97"); 2934ce255c1SJaya Kumar 2944ce255c1SJaya Kumar MODULE_DESCRIPTION("board driver for am300 epd kit"); 2954ce255c1SJaya Kumar MODULE_AUTHOR("Jaya Kumar"); 2964ce255c1SJaya Kumar MODULE_LICENSE("GPL"); 297