xref: /linux/arch/arm/mach-pxa/am300epd.c (revision 4c25c5d2985c1db482cfe59ed9b3a07829a60ba9)
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 
31*4c25c5d2SArnd Bergmann #include "gumstix.h"
32*4c25c5d2SArnd Bergmann #include "mfp-pxa25x.h"
3329ffa48fSLinus Walleij #include <mach/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