xref: /linux/arch/arm/mach-pxa/am300epd.c (revision 4ce255c1420dd7c4b97ad4dabd13fa5d862ad700)
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