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 314c25c5d2SArnd Bergmann #include "gumstix.h" 324c25c5d2SArnd Bergmann #include "mfp-pxa25x.h" 33*e6acc406SArnd Bergmann #include "irqs.h" 34293b2da1SArnd Bergmann #include <linux/platform_data/video-pxafb.h> 354ce255c1SJaya Kumar 364ce255c1SJaya Kumar #include "generic.h" 374ce255c1SJaya Kumar 384ce255c1SJaya Kumar #include <video/broadsheetfb.h> 394ce255c1SJaya Kumar 404ce255c1SJaya Kumar static unsigned int panel_type = 6; 414ce255c1SJaya Kumar static struct platform_device *am300_device; 424ce255c1SJaya Kumar static struct broadsheet_board am300_board; 434ce255c1SJaya Kumar 444ce255c1SJaya Kumar static unsigned long am300_pin_config[] __initdata = { 454ce255c1SJaya Kumar GPIO16_GPIO, 464ce255c1SJaya Kumar GPIO17_GPIO, 474ce255c1SJaya Kumar GPIO32_GPIO, 484ce255c1SJaya Kumar GPIO48_GPIO, 494ce255c1SJaya Kumar GPIO49_GPIO, 504ce255c1SJaya Kumar GPIO51_GPIO, 514ce255c1SJaya Kumar GPIO74_GPIO, 524ce255c1SJaya Kumar GPIO75_GPIO, 534ce255c1SJaya Kumar GPIO76_GPIO, 544ce255c1SJaya Kumar GPIO77_GPIO, 554ce255c1SJaya Kumar 564ce255c1SJaya Kumar /* this is the 16-bit hdb bus 58-73 */ 574ce255c1SJaya Kumar GPIO58_GPIO, 584ce255c1SJaya Kumar GPIO59_GPIO, 594ce255c1SJaya Kumar GPIO60_GPIO, 604ce255c1SJaya Kumar GPIO61_GPIO, 614ce255c1SJaya Kumar 624ce255c1SJaya Kumar GPIO62_GPIO, 634ce255c1SJaya Kumar GPIO63_GPIO, 644ce255c1SJaya Kumar GPIO64_GPIO, 654ce255c1SJaya Kumar GPIO65_GPIO, 664ce255c1SJaya Kumar 674ce255c1SJaya Kumar GPIO66_GPIO, 684ce255c1SJaya Kumar GPIO67_GPIO, 694ce255c1SJaya Kumar GPIO68_GPIO, 704ce255c1SJaya Kumar GPIO69_GPIO, 714ce255c1SJaya Kumar 724ce255c1SJaya Kumar GPIO70_GPIO, 734ce255c1SJaya Kumar GPIO71_GPIO, 744ce255c1SJaya Kumar GPIO72_GPIO, 754ce255c1SJaya Kumar GPIO73_GPIO, 764ce255c1SJaya Kumar }; 774ce255c1SJaya Kumar 784ce255c1SJaya Kumar /* register offsets for gpio control */ 794ce255c1SJaya Kumar #define PWR_GPIO_PIN 16 804ce255c1SJaya Kumar #define CFG_GPIO_PIN 17 814ce255c1SJaya Kumar #define RDY_GPIO_PIN 32 824ce255c1SJaya Kumar #define DC_GPIO_PIN 48 834ce255c1SJaya Kumar #define RST_GPIO_PIN 49 844ce255c1SJaya Kumar #define LED_GPIO_PIN 51 854ce255c1SJaya Kumar #define RD_GPIO_PIN 74 864ce255c1SJaya Kumar #define WR_GPIO_PIN 75 874ce255c1SJaya Kumar #define CS_GPIO_PIN 76 884ce255c1SJaya Kumar #define IRQ_GPIO_PIN 77 894ce255c1SJaya Kumar 904ce255c1SJaya Kumar /* hdb bus */ 914ce255c1SJaya Kumar #define DB0_GPIO_PIN 58 924ce255c1SJaya Kumar #define DB15_GPIO_PIN 73 934ce255c1SJaya Kumar 944ce255c1SJaya Kumar static int gpios[] = { PWR_GPIO_PIN, CFG_GPIO_PIN, RDY_GPIO_PIN, DC_GPIO_PIN, 954ce255c1SJaya Kumar RST_GPIO_PIN, RD_GPIO_PIN, WR_GPIO_PIN, CS_GPIO_PIN, 964ce255c1SJaya Kumar IRQ_GPIO_PIN, LED_GPIO_PIN }; 974ce255c1SJaya Kumar static char *gpio_names[] = { "PWR", "CFG", "RDY", "DC", "RST", "RD", "WR", 984ce255c1SJaya Kumar "CS", "IRQ", "LED" }; 994ce255c1SJaya Kumar 1004ce255c1SJaya Kumar static int am300_wait_event(struct broadsheetfb_par *par) 1014ce255c1SJaya Kumar { 1024ce255c1SJaya Kumar /* todo: improve err recovery */ 1034ce255c1SJaya Kumar wait_event(par->waitq, gpio_get_value(RDY_GPIO_PIN)); 1044ce255c1SJaya Kumar return 0; 1054ce255c1SJaya Kumar } 1064ce255c1SJaya Kumar 1074ce255c1SJaya Kumar static int am300_init_gpio_regs(struct broadsheetfb_par *par) 1084ce255c1SJaya Kumar { 1094ce255c1SJaya Kumar int i; 1104ce255c1SJaya Kumar int err; 1114ce255c1SJaya Kumar char dbname[8]; 1124ce255c1SJaya Kumar 1134ce255c1SJaya Kumar for (i = 0; i < ARRAY_SIZE(gpios); i++) { 1144ce255c1SJaya Kumar err = gpio_request(gpios[i], gpio_names[i]); 1154ce255c1SJaya Kumar if (err) { 1164ce255c1SJaya Kumar dev_err(&am300_device->dev, "failed requesting " 1174ce255c1SJaya Kumar "gpio %s, err=%d\n", gpio_names[i], err); 1184ce255c1SJaya Kumar goto err_req_gpio; 1194ce255c1SJaya Kumar } 1204ce255c1SJaya Kumar } 1214ce255c1SJaya Kumar 1224ce255c1SJaya Kumar /* we also need to take care of the hdb bus */ 1234ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) { 1244ce255c1SJaya Kumar sprintf(dbname, "DB%d", i); 1254ce255c1SJaya Kumar err = gpio_request(i, dbname); 1264ce255c1SJaya Kumar if (err) { 1274ce255c1SJaya Kumar dev_err(&am300_device->dev, "failed requesting " 1284ce255c1SJaya Kumar "gpio %d, err=%d\n", i, err); 1295898eb79SAxel Lin goto err_req_gpio2; 1304ce255c1SJaya Kumar } 1314ce255c1SJaya Kumar } 1324ce255c1SJaya Kumar 1334ce255c1SJaya Kumar /* setup the outputs and init values */ 1344ce255c1SJaya Kumar gpio_direction_output(PWR_GPIO_PIN, 0); 1354ce255c1SJaya Kumar gpio_direction_output(CFG_GPIO_PIN, 1); 1364ce255c1SJaya Kumar gpio_direction_output(DC_GPIO_PIN, 0); 1374ce255c1SJaya Kumar gpio_direction_output(RD_GPIO_PIN, 1); 1384ce255c1SJaya Kumar gpio_direction_output(WR_GPIO_PIN, 1); 1394ce255c1SJaya Kumar gpio_direction_output(CS_GPIO_PIN, 1); 1404ce255c1SJaya Kumar gpio_direction_output(RST_GPIO_PIN, 0); 1414ce255c1SJaya Kumar 1424ce255c1SJaya Kumar /* setup the inputs */ 1434ce255c1SJaya Kumar gpio_direction_input(RDY_GPIO_PIN); 1444ce255c1SJaya Kumar gpio_direction_input(IRQ_GPIO_PIN); 1454ce255c1SJaya Kumar 1464ce255c1SJaya Kumar /* start the hdb bus as an input */ 1474ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) 1484ce255c1SJaya Kumar gpio_direction_output(i, 0); 1494ce255c1SJaya Kumar 1504ce255c1SJaya Kumar /* go into command mode */ 1514ce255c1SJaya Kumar gpio_set_value(CFG_GPIO_PIN, 1); 1524ce255c1SJaya Kumar gpio_set_value(RST_GPIO_PIN, 0); 1534ce255c1SJaya Kumar msleep(10); 1544ce255c1SJaya Kumar gpio_set_value(RST_GPIO_PIN, 1); 1554ce255c1SJaya Kumar msleep(10); 1564ce255c1SJaya Kumar am300_wait_event(par); 1574ce255c1SJaya Kumar 1584ce255c1SJaya Kumar return 0; 1594ce255c1SJaya Kumar 1605898eb79SAxel Lin err_req_gpio2: 1615898eb79SAxel Lin while (--i >= DB0_GPIO_PIN) 1625898eb79SAxel Lin gpio_free(i); 1635898eb79SAxel Lin i = ARRAY_SIZE(gpios); 1644ce255c1SJaya Kumar err_req_gpio: 1655898eb79SAxel Lin while (--i >= 0) 1665898eb79SAxel Lin gpio_free(gpios[i]); 1674ce255c1SJaya Kumar 1684ce255c1SJaya Kumar return err; 1694ce255c1SJaya Kumar } 1704ce255c1SJaya Kumar 1714ce255c1SJaya Kumar static int am300_init_board(struct broadsheetfb_par *par) 1724ce255c1SJaya Kumar { 1734ce255c1SJaya Kumar return am300_init_gpio_regs(par); 1744ce255c1SJaya Kumar } 1754ce255c1SJaya Kumar 1764ce255c1SJaya Kumar static void am300_cleanup(struct broadsheetfb_par *par) 1774ce255c1SJaya Kumar { 1784ce255c1SJaya Kumar int i; 1794ce255c1SJaya Kumar 1806384fdadSHaojian Zhuang free_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), par); 1814ce255c1SJaya Kumar 1824ce255c1SJaya Kumar for (i = 0; i < ARRAY_SIZE(gpios); i++) 1834ce255c1SJaya Kumar gpio_free(gpios[i]); 1844ce255c1SJaya Kumar 1854ce255c1SJaya Kumar for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) 1864ce255c1SJaya Kumar gpio_free(i); 1874ce255c1SJaya Kumar 1884ce255c1SJaya Kumar } 1894ce255c1SJaya Kumar 1904ce255c1SJaya Kumar static u16 am300_get_hdb(struct broadsheetfb_par *par) 1914ce255c1SJaya Kumar { 1924ce255c1SJaya Kumar u16 res = 0; 1934ce255c1SJaya Kumar int i; 1944ce255c1SJaya Kumar 1954ce255c1SJaya Kumar for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++) 1964ce255c1SJaya Kumar res |= (gpio_get_value(DB0_GPIO_PIN + i)) ? (1 << i) : 0; 1974ce255c1SJaya Kumar 1984ce255c1SJaya Kumar return res; 1994ce255c1SJaya Kumar } 2004ce255c1SJaya Kumar 2014ce255c1SJaya Kumar static void am300_set_hdb(struct broadsheetfb_par *par, u16 data) 2024ce255c1SJaya Kumar { 2034ce255c1SJaya Kumar int i; 2044ce255c1SJaya Kumar 2054ce255c1SJaya Kumar for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++) 2064ce255c1SJaya Kumar gpio_set_value(DB0_GPIO_PIN + i, (data >> i) & 0x01); 2074ce255c1SJaya Kumar } 2084ce255c1SJaya Kumar 2094ce255c1SJaya Kumar 2104ce255c1SJaya Kumar static void am300_set_ctl(struct broadsheetfb_par *par, unsigned char bit, 2114ce255c1SJaya Kumar u8 state) 2124ce255c1SJaya Kumar { 2134ce255c1SJaya Kumar switch (bit) { 2144ce255c1SJaya Kumar case BS_CS: 2154ce255c1SJaya Kumar gpio_set_value(CS_GPIO_PIN, state); 2164ce255c1SJaya Kumar break; 2174ce255c1SJaya Kumar case BS_DC: 2184ce255c1SJaya Kumar gpio_set_value(DC_GPIO_PIN, state); 2194ce255c1SJaya Kumar break; 2204ce255c1SJaya Kumar case BS_WR: 2214ce255c1SJaya Kumar gpio_set_value(WR_GPIO_PIN, state); 2224ce255c1SJaya Kumar break; 2234ce255c1SJaya Kumar } 2244ce255c1SJaya Kumar } 2254ce255c1SJaya Kumar 2264ce255c1SJaya Kumar static int am300_get_panel_type(void) 2274ce255c1SJaya Kumar { 2284ce255c1SJaya Kumar return panel_type; 2294ce255c1SJaya Kumar } 2304ce255c1SJaya Kumar 2314ce255c1SJaya Kumar static irqreturn_t am300_handle_irq(int irq, void *dev_id) 2324ce255c1SJaya Kumar { 2334ce255c1SJaya Kumar struct broadsheetfb_par *par = dev_id; 2344ce255c1SJaya Kumar 2354ce255c1SJaya Kumar wake_up(&par->waitq); 2364ce255c1SJaya Kumar return IRQ_HANDLED; 2374ce255c1SJaya Kumar } 2384ce255c1SJaya Kumar 2394ce255c1SJaya Kumar static int am300_setup_irq(struct fb_info *info) 2404ce255c1SJaya Kumar { 2414ce255c1SJaya Kumar int ret; 2424ce255c1SJaya Kumar struct broadsheetfb_par *par = info->par; 2434ce255c1SJaya Kumar 2446384fdadSHaojian Zhuang ret = request_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), am300_handle_irq, 245ed7936f9SMichael Opdenacker IRQF_TRIGGER_RISING, "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