aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-pxa/Kconfig3
-rw-r--r--arch/arm/mach-pxa/Makefile1
-rw-r--r--arch/arm/mach-pxa/am200epd.c374
-rw-r--r--drivers/video/Kconfig13
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/am200epd.c295
6 files changed, 378 insertions, 309 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index e8ee7ec9ff6d..2c4851a35308 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -256,6 +256,9 @@ config PCM990_DISPLAY_NONE
256 256
257endchoice 257endchoice
258 258
259config MACH_AM200EPD
260 depends on MACH_GUMSTIX_F
261 bool "Enable AM200EPD board support"
259 262
260config PXA_EZX 263config PXA_EZX
261 bool "Motorola EZX Platform" 264 bool "Motorola EZX Platform"
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 99ecbe7f8506..ccbe1b08f88e 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o
22 22
23# Specific board support 23# Specific board support
24obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o 24obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o
25obj-$(CONFIG_MACH_AM200EPD) += am200epd.o
25obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o 26obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
26obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o 27obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
27obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o 28obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
diff --git a/arch/arm/mach-pxa/am200epd.c b/arch/arm/mach-pxa/am200epd.c
new file mode 100644
index 000000000000..b965085a37b9
--- /dev/null
+++ b/arch/arm/mach-pxa/am200epd.c
@@ -0,0 +1,374 @@
1/*
2 * am200epd.c -- Platform device for AM200 EPD kit
3 *
4 * Copyright (C) 2008, Jaya Kumar
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
9 *
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
11 *
12 * This work was made possible by help and equipment support from E-Ink
13 * Corporation. http://support.eink.com/community
14 *
15 * This driver is written to be used with the Metronome display controller.
16 * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600
17 * Vizplex EPD on a Gumstix board using the Lyre interface board.
18 *
19 */
20
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/errno.h>
24#include <linux/string.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/fb.h>
28#include <linux/init.h>
29#include <linux/platform_device.h>
30#include <linux/irq.h>
31#include <linux/gpio.h>
32
33#include <mach/pxafb.h>
34
35#include <video/metronomefb.h>
36
37static unsigned int panel_type = 6;
38static struct platform_device *am200_device;
39static struct metronome_board am200_board;
40
41static struct pxafb_mode_info am200_fb_mode_9inch7 = {
42 .pixclock = 40000,
43 .xres = 1200,
44 .yres = 842,
45 .bpp = 16,
46 .hsync_len = 2,
47 .left_margin = 2,
48 .right_margin = 2,
49 .vsync_len = 1,
50 .upper_margin = 2,
51 .lower_margin = 25,
52 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
53};
54
55static struct pxafb_mode_info am200_fb_mode_8inch = {
56 .pixclock = 40000,
57 .xres = 1088,
58 .yres = 791,
59 .bpp = 16,
60 .hsync_len = 28,
61 .left_margin = 8,
62 .right_margin = 30,
63 .vsync_len = 8,
64 .upper_margin = 10,
65 .lower_margin = 8,
66 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
67};
68
69static struct pxafb_mode_info am200_fb_mode_6inch = {
70 .pixclock = 40189,
71 .xres = 832,
72 .yres = 622,
73 .bpp = 16,
74 .hsync_len = 28,
75 .left_margin = 34,
76 .right_margin = 34,
77 .vsync_len = 25,
78 .upper_margin = 0,
79 .lower_margin = 2,
80 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
81};
82
83static struct pxafb_mach_info am200_fb_info = {
84 .modes = &am200_fb_mode_6inch,
85 .num_modes = 1,
86 .lcd_conn = LCD_TYPE_COLOR_TFT | LCD_PCLK_EDGE_FALL |
87 LCD_AC_BIAS_FREQ(24),
88};
89
90/* register offsets for gpio control */
91#define LED_GPIO_PIN 51
92#define STDBY_GPIO_PIN 48
93#define RST_GPIO_PIN 49
94#define RDY_GPIO_PIN 32
95#define ERR_GPIO_PIN 17
96#define PCBPWR_GPIO_PIN 16
97static int gpios[] = { LED_GPIO_PIN , STDBY_GPIO_PIN , RST_GPIO_PIN,
98 RDY_GPIO_PIN, ERR_GPIO_PIN, PCBPWR_GPIO_PIN };
99static char *gpio_names[] = { "LED" , "STDBY" , "RST", "RDY", "ERR", "PCBPWR" };
100
101static int am200_init_gpio_regs(struct metronomefb_par *par)
102{
103 int i;
104 int err;
105
106 for (i = 0; i < ARRAY_SIZE(gpios); i++) {
107 err = gpio_request(gpios[i], gpio_names[i]);
108 if (err) {
109 dev_err(&am200_device->dev, "failed requesting "
110 "gpio %s, err=%d\n", gpio_names[i], err);
111 goto err_req_gpio;
112 }
113 }
114
115 gpio_direction_output(LED_GPIO_PIN, 0);
116 gpio_direction_output(STDBY_GPIO_PIN, 0);
117 gpio_direction_output(RST_GPIO_PIN, 0);
118
119 gpio_direction_input(RDY_GPIO_PIN);
120 gpio_direction_input(ERR_GPIO_PIN);
121
122 gpio_direction_output(PCBPWR_GPIO_PIN, 0);
123
124 return 0;
125
126err_req_gpio:
127 while (i > 0)
128 gpio_free(gpios[i--]);
129
130 return err;
131}
132
133static void am200_cleanup(struct metronomefb_par *par)
134{
135 int i;
136
137 free_irq(IRQ_GPIO(RDY_GPIO_PIN), par);
138
139 for (i = 0; i < ARRAY_SIZE(gpios); i++)
140 gpio_free(gpios[i]);
141}
142
143static int am200_share_video_mem(struct fb_info *info)
144{
145 /* rough check if this is our desired fb and not something else */
146 if ((info->var.xres != am200_fb_info.modes->xres)
147 || (info->var.yres != am200_fb_info.modes->yres))
148 return 0;
149
150 /* we've now been notified that we have our new fb */
151 am200_board.metromem = info->screen_base;
152 am200_board.host_fbinfo = info;
153
154 /* try to refcount host drv since we are the consumer after this */
155 if (!try_module_get(info->fbops->owner))
156 return -ENODEV;
157
158 return 0;
159}
160
161static int am200_unshare_video_mem(struct fb_info *info)
162{
163 dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
164
165 if (info != am200_board.host_fbinfo)
166 return 0;
167
168 module_put(am200_board.host_fbinfo->fbops->owner);
169 return 0;
170}
171
172static int am200_fb_notifier_callback(struct notifier_block *self,
173 unsigned long event, void *data)
174{
175 struct fb_event *evdata = data;
176 struct fb_info *info = evdata->info;
177
178 dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
179
180 if (event == FB_EVENT_FB_REGISTERED)
181 return am200_share_video_mem(info);
182 else if (event == FB_EVENT_FB_UNREGISTERED)
183 return am200_unshare_video_mem(info);
184
185 return 0;
186}
187
188static struct notifier_block am200_fb_notif = {
189 .notifier_call = am200_fb_notifier_callback,
190};
191
192/* this gets called as part of our init. these steps must be done now so
193 * that we can use set_pxa_fb_info */
194static void __init am200_presetup_fb(void)
195{
196 int fw;
197 int fh;
198 int padding_size;
199 int totalsize;
200
201 switch (panel_type) {
202 case 6:
203 am200_fb_info.modes = &am200_fb_mode_6inch;
204 break;
205 case 8:
206 am200_fb_info.modes = &am200_fb_mode_8inch;
207 break;
208 case 97:
209 am200_fb_info.modes = &am200_fb_mode_9inch7;
210 break;
211 default:
212 dev_err(&am200_device->dev, "invalid panel_type selection,"
213 " setting to 6\n");
214 am200_fb_info.modes = &am200_fb_mode_6inch;
215 break;
216 }
217
218 /* the frame buffer is divided as follows:
219 command | CRC | padding
220 16kb waveform data | CRC | padding
221 image data | CRC
222 */
223
224 fw = am200_fb_info.modes->xres;
225 fh = am200_fb_info.modes->yres;
226
227 /* waveform must be 16k + 2 for checksum */
228 am200_board.wfm_size = roundup(16*1024 + 2, fw);
229
230 padding_size = PAGE_SIZE + (4 * fw);
231
232 /* total is 1 cmd , 1 wfm, padding and image */
233 totalsize = fw + am200_board.wfm_size + padding_size + (fw*fh);
234
235 /* save this off because we're manipulating fw after this and
236 * we'll need it when we're ready to setup the framebuffer */
237 am200_board.fw = fw;
238 am200_board.fh = fh;
239
240 /* the reason we do this adjustment is because we want to acquire
241 * more framebuffer memory without imposing custom awareness on the
242 * underlying pxafb driver */
243 am200_fb_info.modes->yres = DIV_ROUND_UP(totalsize, fw);
244
245 /* we divide since we told the LCD controller we're 16bpp */
246 am200_fb_info.modes->xres /= 2;
247
248 set_pxa_fb_info(&am200_fb_info);
249
250}
251
252/* this gets called by metronomefb as part of its init, in our case, we
253 * have already completed initial framebuffer init in presetup_fb so we
254 * can just setup the fb access pointers */
255static int am200_setup_fb(struct metronomefb_par *par)
256{
257 int fw;
258 int fh;
259
260 fw = am200_board.fw;
261 fh = am200_board.fh;
262
263 /* metromem was set up by the notifier in share_video_mem so now
264 * we can use its value to calculate the other entries */
265 par->metromem_cmd = (struct metromem_cmd *) am200_board.metromem;
266 par->metromem_wfm = am200_board.metromem + fw;
267 par->metromem_img = par->metromem_wfm + am200_board.wfm_size;
268 par->metromem_img_csum = (u16 *) (par->metromem_img + (fw * fh));
269 par->metromem_dma = am200_board.host_fbinfo->fix.smem_start;
270
271 return 0;
272}
273
274static int am200_get_panel_type(void)
275{
276 return panel_type;
277}
278
279static irqreturn_t am200_handle_irq(int irq, void *dev_id)
280{
281 struct metronomefb_par *par = dev_id;
282
283 wake_up_interruptible(&par->waitq);
284 return IRQ_HANDLED;
285}
286
287static int am200_setup_irq(struct fb_info *info)
288{
289 int ret;
290
291 ret = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
292 IRQF_DISABLED|IRQF_TRIGGER_FALLING,
293 "AM200", info->par);
294 if (ret)
295 dev_err(&am200_device->dev, "request_irq failed: %d\n", ret);
296
297 return ret;
298}
299
300static void am200_set_rst(struct metronomefb_par *par, int state)
301{
302 gpio_set_value(RST_GPIO_PIN, state);
303}
304
305static void am200_set_stdby(struct metronomefb_par *par, int state)
306{
307 gpio_set_value(STDBY_GPIO_PIN, state);
308}
309
310static int am200_wait_event(struct metronomefb_par *par)
311{
312 return wait_event_timeout(par->waitq, gpio_get_value(RDY_GPIO_PIN), HZ);
313}
314
315static int am200_wait_event_intr(struct metronomefb_par *par)
316{
317 return wait_event_interruptible_timeout(par->waitq,
318 gpio_get_value(RDY_GPIO_PIN), HZ);
319}
320
321static struct metronome_board am200_board = {
322 .owner = THIS_MODULE,
323 .setup_irq = am200_setup_irq,
324 .setup_io = am200_init_gpio_regs,
325 .setup_fb = am200_setup_fb,
326 .set_rst = am200_set_rst,
327 .set_stdby = am200_set_stdby,
328 .met_wait_event = am200_wait_event,
329 .met_wait_event_intr = am200_wait_event_intr,
330 .get_panel_type = am200_get_panel_type,
331 .cleanup = am200_cleanup,
332};
333
334static int __init am200_init(void)
335{
336 int ret;
337
338 /* before anything else, we request notification for any fb
339 * creation events */
340 fb_register_client(&am200_fb_notif);
341
342 /* request our platform independent driver */
343 request_module("metronomefb");
344
345 am200_device = platform_device_alloc("metronomefb", -1);
346 if (!am200_device)
347 return -ENOMEM;
348
349 /* the am200_board that will be seen by metronomefb is a copy */
350 platform_device_add_data(am200_device, &am200_board,
351 sizeof(am200_board));
352
353 /* this _add binds metronomefb to am200. metronomefb refcounts am200 */
354 ret = platform_device_add(am200_device);
355
356 if (ret) {
357 platform_device_put(am200_device);
358 fb_unregister_client(&am200_fb_notif);
359 return ret;
360 }
361
362 am200_presetup_fb();
363
364 return 0;
365}
366
367module_param(panel_type, uint, 0);
368MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
369
370module_init(am200_init);
371
372MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
373MODULE_AUTHOR("Jaya Kumar");
374MODULE_LICENSE("GPL");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6fd4a2f63cf8..d85a74c64b54 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1969,19 +1969,6 @@ config FB_XILINX
1969 framebuffer. ML300 carries a 640*480 LCD display on the board, 1969 framebuffer. ML300 carries a 640*480 LCD display on the board,
1970 ML403 uses a standard DB15 VGA connector. 1970 ML403 uses a standard DB15 VGA connector.
1971 1971
1972config FB_AM200EPD
1973 tristate "AM-200 E-Ink EPD devkit support"
1974 depends on FB && ARCH_PXA && MMU
1975 select FB_SYS_FILLRECT
1976 select FB_SYS_COPYAREA
1977 select FB_SYS_IMAGEBLIT
1978 select FB_SYS_FOPS
1979 select FB_DEFERRED_IO
1980 select FB_METRONOME
1981 help
1982 This enables support for the Metronome display controller used on
1983 the E-Ink AM-200 EPD devkit.
1984
1985config FB_COBALT 1972config FB_COBALT
1986 tristate "Cobalt server LCD frame buffer support" 1973 tristate "Cobalt server LCD frame buffer support"
1987 depends on FB && MIPS_COBALT 1974 depends on FB && MIPS_COBALT
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a6b55297a7fb..ad0330bf9be3 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,7 +29,6 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
29 29
30# Hardware specific drivers go first 30# Hardware specific drivers go first
31obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o 31obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
32obj-$(CONFIG_FB_AM200EPD) += am200epd.o
33obj-$(CONFIG_FB_ARC) += arcfb.o 32obj-$(CONFIG_FB_ARC) += arcfb.o
34obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o 33obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
35obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o 34obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c
deleted file mode 100644
index 0c35b8b0160e..000000000000
--- a/drivers/video/am200epd.c
+++ /dev/null
@@ -1,295 +0,0 @@
1/*
2 * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit
3 *
4 * Copyright (C) 2008, Jaya Kumar
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
9 *
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
11 *
12 * This work was made possible by help and equipment support from E-Ink
13 * Corporation. http://support.eink.com/community
14 *
15 * This driver is written to be used with the Metronome display controller.
16 * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600
17 * Vizplex EPD on a Gumstix board using the Lyre interface board.
18 *
19 */
20
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/errno.h>
24#include <linux/string.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/fb.h>
28#include <linux/init.h>
29#include <linux/platform_device.h>
30#include <linux/list.h>
31#include <linux/uaccess.h>
32#include <linux/irq.h>
33
34#include <video/metronomefb.h>
35
36#include <mach/pxa-regs.h>
37
38/* register offsets for gpio control */
39#define LED_GPIO_PIN 51
40#define STDBY_GPIO_PIN 48
41#define RST_GPIO_PIN 49
42#define RDY_GPIO_PIN 32
43#define ERR_GPIO_PIN 17
44#define PCBPWR_GPIO_PIN 16
45
46#define AF_SEL_GPIO_N 0x3
47#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
48#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
49#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
50#define GPDR1_OFFSET(pin) (pin - 32)
51#define GPCR1_OFFSET(pin) (pin - 32)
52#define GPSR1_OFFSET(pin) (pin - 32)
53#define GPCR0_OFFSET(pin) (pin)
54#define GPSR0_OFFSET(pin) (pin)
55
56static void am200_set_gpio_output(int pin, int val)
57{
58 u8 index;
59
60 index = pin >> 4;
61
62 switch (index) {
63 case 1:
64 if (val)
65 GPSR0 |= (1 << GPSR0_OFFSET(pin));
66 else
67 GPCR0 |= (1 << GPCR0_OFFSET(pin));
68 break;
69 case 2:
70 break;
71 case 3:
72 if (val)
73 GPSR1 |= (1 << GPSR1_OFFSET(pin));
74 else
75 GPCR1 |= (1 << GPCR1_OFFSET(pin));
76 break;
77 default:
78 printk(KERN_ERR "unimplemented\n");
79 }
80}
81
82static void __devinit am200_init_gpio_pin(int pin, int dir)
83{
84 u8 index;
85 /* dir 0 is output, 1 is input
86 - do 2 things here:
87 - set gpio alternate function to standard gpio
88 - set gpio direction to input or output */
89
90 index = pin >> 4;
91 switch (index) {
92 case 1:
93 GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
94
95 if (dir)
96 GPDR0 &= ~(1 << pin);
97 else
98 GPDR0 |= (1 << pin);
99 break;
100 case 2:
101 GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
102
103 if (dir)
104 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
105 else
106 GPDR1 |= (1 << GPDR1_OFFSET(pin));
107 break;
108 case 3:
109 GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
110
111 if (dir)
112 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
113 else
114 GPDR1 |= (1 << GPDR1_OFFSET(pin));
115 break;
116 default:
117 printk(KERN_ERR "unimplemented\n");
118 }
119}
120
121static void am200_init_gpio_regs(struct metronomefb_par *par)
122{
123 am200_init_gpio_pin(LED_GPIO_PIN, 0);
124 am200_set_gpio_output(LED_GPIO_PIN, 0);
125
126 am200_init_gpio_pin(STDBY_GPIO_PIN, 0);
127 am200_set_gpio_output(STDBY_GPIO_PIN, 0);
128
129 am200_init_gpio_pin(RST_GPIO_PIN, 0);
130 am200_set_gpio_output(RST_GPIO_PIN, 0);
131
132 am200_init_gpio_pin(RDY_GPIO_PIN, 1);
133
134 am200_init_gpio_pin(ERR_GPIO_PIN, 1);
135
136 am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
137 am200_set_gpio_output(PCBPWR_GPIO_PIN, 0);
138}
139
140static void am200_disable_lcd_controller(struct metronomefb_par *par)
141{
142 LCSR = 0xffffffff; /* Clear LCD Status Register */
143 LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
144
145 /* we reset and just wait for things to settle */
146 msleep(200);
147}
148
149static void am200_enable_lcd_controller(struct metronomefb_par *par)
150{
151 LCSR = 0xffffffff;
152 FDADR0 = par->metromem_desc_dma;
153 LCCR0 |= LCCR0_ENB;
154}
155
156static void am200_init_lcdc_regs(struct metronomefb_par *par)
157{
158 /* here we do:
159 - disable the lcd controller
160 - setup lcd control registers
161 - setup dma descriptor
162 - reenable lcd controller
163 */
164
165 /* disable the lcd controller */
166 am200_disable_lcd_controller(par);
167
168 /* setup lcd control registers */
169 LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
170 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
171
172 LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */
173 | (27 << 10) /* hsync pulse width - 1 */
174 | (33 << 16) /* eol pixel count */
175 | (33 << 24); /* bol pixel count */
176
177 LCCR2 = (par->info->var.yres - 1) /* lines per panel */
178 | (24 << 10) /* vsync pulse width - 1 */
179 | (2 << 16) /* eof pixel count */
180 | (0 << 24); /* bof pixel count */
181
182 LCCR3 = 2 /* pixel clock divisor */
183 | (24 << 8) /* AC Bias pin freq */
184 | LCCR3_16BPP /* BPP */
185 | LCCR3_PCP; /* PCP falling edge */
186
187}
188
189static void am200_post_dma_setup(struct metronomefb_par *par)
190{
191 par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
192 par->metromem_desc->mFSADR0 = par->metromem_dma;
193 par->metromem_desc->mFIDR0 = 0;
194 par->metromem_desc->mLDCMD0 = par->info->var.xres
195 * par->info->var.yres;
196 am200_enable_lcd_controller(par);
197}
198
199static void am200_free_irq(struct fb_info *info)
200{
201 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
202}
203
204static irqreturn_t am200_handle_irq(int irq, void *dev_id)
205{
206 struct fb_info *info = dev_id;
207 struct metronomefb_par *par = info->par;
208
209 wake_up_interruptible(&par->waitq);
210 return IRQ_HANDLED;
211}
212
213static int am200_setup_irq(struct fb_info *info)
214{
215 int retval;
216
217 retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
218 IRQF_DISABLED, "AM200", info);
219 if (retval) {
220 printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval);
221 return retval;
222 }
223
224 return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQ_TYPE_EDGE_FALLING);
225}
226
227static void am200_set_rst(struct metronomefb_par *par, int state)
228{
229 am200_set_gpio_output(RST_GPIO_PIN, state);
230}
231
232static void am200_set_stdby(struct metronomefb_par *par, int state)
233{
234 am200_set_gpio_output(STDBY_GPIO_PIN, state);
235}
236
237static int am200_wait_event(struct metronomefb_par *par)
238{
239 return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
240}
241
242static int am200_wait_event_intr(struct metronomefb_par *par)
243{
244 return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
245}
246
247static struct metronome_board am200_board = {
248 .owner = THIS_MODULE,
249 .free_irq = am200_free_irq,
250 .setup_irq = am200_setup_irq,
251 .init_gpio_regs = am200_init_gpio_regs,
252 .init_lcdc_regs = am200_init_lcdc_regs,
253 .post_dma_setup = am200_post_dma_setup,
254 .set_rst = am200_set_rst,
255 .set_stdby = am200_set_stdby,
256 .met_wait_event = am200_wait_event,
257 .met_wait_event_intr = am200_wait_event_intr,
258};
259
260static struct platform_device *am200_device;
261
262static int __init am200_init(void)
263{
264 int ret;
265
266 /* request our platform independent driver */
267 request_module("metronomefb");
268
269 am200_device = platform_device_alloc("metronomefb", -1);
270 if (!am200_device)
271 return -ENOMEM;
272
273 platform_device_add_data(am200_device, &am200_board,
274 sizeof(am200_board));
275
276 /* this _add binds metronomefb to am200. metronomefb refcounts am200 */
277 ret = platform_device_add(am200_device);
278
279 if (ret)
280 platform_device_put(am200_device);
281
282 return ret;
283}
284
285static void __exit am200_exit(void)
286{
287 platform_device_unregister(am200_device);
288}
289
290module_init(am200_init);
291module_exit(am200_exit);
292
293MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
294MODULE_AUTHOR("Jaya Kumar");
295MODULE_LICENSE("GPL");