aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaya Kumar <jayakumar.lkml@gmail.com>2008-04-28 05:15:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:41 -0400
commit03c33a4f002b2521debf1efc269cade983b6e86a (patch)
treee4ed669161ba7d029497fe6917854bea0ae83aec
parent963654a9c919d18f8b9137f8ffd9d2d30a139269 (diff)
fbdev: platforming metronomefb and am200epd
This patch splits metronomefb into the platform independent metronomefb and the platform dependent am200epd. Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com> Cc: "Antonino A. Daplas" <adaplas@pol.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/fb/metronomefb.txt16
-rw-r--r--drivers/video/Kconfig16
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/am200epd.c295
-rw-r--r--drivers/video/metronomefb.c314
-rw-r--r--include/video/metronomefb.h62
6 files changed, 422 insertions, 282 deletions
diff --git a/Documentation/fb/metronomefb.txt b/Documentation/fb/metronomefb.txt
index b9a2e7b7e838..237ca412582d 100644
--- a/Documentation/fb/metronomefb.txt
+++ b/Documentation/fb/metronomefb.txt
@@ -1,7 +1,7 @@
1 Metronomefb 1 Metronomefb
2 ----------- 2 -----------
3Maintained by Jaya Kumar <jayakumar.lkml.gmail.com> 3Maintained by Jaya Kumar <jayakumar.lkml.gmail.com>
4Last revised: Nov 20, 2007 4Last revised: Mar 10, 2008
5 5
6Metronomefb is a driver for the Metronome display controller. The controller 6Metronomefb is a driver for the Metronome display controller. The controller
7is from E-Ink Corporation. It is intended to be used to drive the E-Ink 7is from E-Ink Corporation. It is intended to be used to drive the E-Ink
@@ -11,20 +11,18 @@ display media here http://www.e-ink.com/products/matrix/metronome.html .
11Metronome is interfaced to the host CPU through the AMLCD interface. The 11Metronome is interfaced to the host CPU through the AMLCD interface. The
12host CPU generates the control information and the image in a framebuffer 12host CPU generates the control information and the image in a framebuffer
13which is then delivered to the AMLCD interface by a host specific method. 13which is then delivered to the AMLCD interface by a host specific method.
14Currently, that's implemented for the PXA's LCDC controller. The display and 14The display and error status are each pulled through individual GPIOs.
15error status are each pulled through individual GPIOs.
16 15
17Metronomefb was written for the PXA255/gumstix/lyre combination and 16Metronomefb is platform independent and depends on a board specific driver
18therefore currently has board set specific code in it. If other boards based on 17to do all physical IO work. Currently, an example is implemented for the
19other architectures are available, then the host specific code can be separated 18PXA board used in the AM-200 EPD devkit. This example is am200epd.c
20and abstracted out.
21 19
22Metronomefb requires waveform information which is delivered via the AMLCD 20Metronomefb requires waveform information which is delivered via the AMLCD
23interface to the metronome controller. The waveform information is expected to 21interface to the metronome controller. The waveform information is expected to
24be delivered from userspace via the firmware class interface. The waveform file 22be delivered from userspace via the firmware class interface. The waveform file
25can be compressed as long as your udev or hotplug script is aware of the need 23can be compressed as long as your udev or hotplug script is aware of the need
26to uncompress it before delivering it. metronomefb will ask for waveform.wbf 24to uncompress it before delivering it. metronomefb will ask for metronome.wbf
27which would typically go into /lib/firmware/waveform.wbf depending on your 25which would typically go into /lib/firmware/metronome.wbf depending on your
28udev/hotplug setup. I have only tested with a single waveform file which was 26udev/hotplug setup. I have only tested with a single waveform file which was
29originally labeled 23P01201_60_WT0107_MTC. I do not know what it stands for. 27originally labeled 23P01201_60_WT0107_MTC. I do not know what it stands for.
30Caution should be exercised when manipulating the waveform as there may be 28Caution should be exercised when manipulating the waveform as there may be
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8da4683c5d20..ff6ea9a9be22 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -173,6 +173,11 @@ config FB_DEFERRED_IO
173 depends on FB 173 depends on FB
174 default y 174 default y
175 175
176config FB_METRONOME
177 tristate
178 depends on FB
179 depends on FB_DEFERRED_IO
180
176config FB_SVGALIB 181config FB_SVGALIB
177 tristate 182 tristate
178 depends on FB 183 depends on FB
@@ -1927,19 +1932,18 @@ config FB_XILINX
1927 framebuffer. ML300 carries a 640*480 LCD display on the board, 1932 framebuffer. ML300 carries a 640*480 LCD display on the board,
1928 ML403 uses a standard DB15 VGA connector. 1933 ML403 uses a standard DB15 VGA connector.
1929 1934
1930config FB_METRONOME 1935config FB_AM200EPD
1931 tristate "Metronome display controller support" 1936 tristate "AM-200 E-Ink EPD devkit support"
1932 depends on FB && ARCH_PXA && MMU 1937 depends on FB && ARCH_PXA && MMU
1933 select FB_SYS_FILLRECT 1938 select FB_SYS_FILLRECT
1934 select FB_SYS_COPYAREA 1939 select FB_SYS_COPYAREA
1935 select FB_SYS_IMAGEBLIT 1940 select FB_SYS_IMAGEBLIT
1936 select FB_SYS_FOPS 1941 select FB_SYS_FOPS
1937 select FB_DEFERRED_IO 1942 select FB_DEFERRED_IO
1943 select FB_METRONOME
1938 help 1944 help
1939 This enables support for the Metronome display controller. Tested 1945 This enables support for the Metronome display controller used on
1940 with an E-Ink 800x600 display and Gumstix Connex through an AMLCD 1946 the E-Ink AM-200 EPD devkit.
1941 interface. Please read <file:Documentation/fb/metronomefb.txt>
1942 for more information.
1943 1947
1944config FB_VIRTUAL 1948config FB_VIRTUAL
1945 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" 1949 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 80d58425c641..04bca35403ff 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,6 +29,7 @@ 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
32obj-$(CONFIG_FB_ARC) += arcfb.o 33obj-$(CONFIG_FB_ARC) += arcfb.o
33obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o 34obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
34obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o 35obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c
new file mode 100644
index 000000000000..51e26c1f5e8b
--- /dev/null
+++ b/drivers/video/am200epd.c
@@ -0,0 +1,295 @@
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 <asm/arch/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), IRQT_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");
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index 5602f3e3f919..17066dd5a190 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -13,12 +13,10 @@
13 * Corporation. http://support.eink.com/community 13 * Corporation. http://support.eink.com/community
14 * 14 *
15 * This driver is written to be used with the Metronome display controller. 15 * This driver is written to be used with the Metronome display controller.
16 * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board 16 * It is intended to be architecture independent. A board specific driver
17 * using the Lyre interface board. 17 * must be used to perform all the physical IO interactions. An example
18 * is provided as am200epd.c
18 * 19 *
19 * General notes:
20 * - User must set metronomefb_enable=1 to enable it.
21 * - See Documentation/fb/metronomefb.txt for how metronome works.
22 */ 20 */
23#include <linux/module.h> 21#include <linux/module.h>
24#include <linux/kernel.h> 22#include <linux/kernel.h>
@@ -38,9 +36,11 @@
38#include <linux/uaccess.h> 36#include <linux/uaccess.h>
39#include <linux/irq.h> 37#include <linux/irq.h>
40 38
41#include <asm/arch/pxa-regs.h> 39#include <video/metronomefb.h>
40
42#include <asm/unaligned.h> 41#include <asm/unaligned.h>
43 42
43
44#define DEBUG 1 44#define DEBUG 1
45#ifdef DEBUG 45#ifdef DEBUG
46#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) 46#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
@@ -53,35 +53,6 @@
53#define DPY_W 832 53#define DPY_W 832
54#define DPY_H 622 54#define DPY_H 622
55 55
56struct metromem_desc {
57 u32 mFDADR0;
58 u32 mFSADR0;
59 u32 mFIDR0;
60 u32 mLDCMD0;
61};
62
63struct metromem_cmd {
64 u16 opcode;
65 u16 args[((64-2)/2)];
66 u16 csum;
67};
68
69struct metronomefb_par {
70 unsigned char *metromem;
71 struct metromem_desc *metromem_desc;
72 struct metromem_cmd *metromem_cmd;
73 unsigned char *metromem_wfm;
74 unsigned char *metromem_img;
75 u16 *metromem_img_csum;
76 u16 *csum_table;
77 int metromemsize;
78 dma_addr_t metromem_dma;
79 dma_addr_t metromem_desc_dma;
80 struct fb_info *info;
81 wait_queue_head_t waitq;
82 u8 frame_count;
83};
84
85/* frame differs from image. frame includes non-visible pixels */ 56/* frame differs from image. frame includes non-visible pixels */
86struct epd_frame { 57struct epd_frame {
87 int fw; /* frame width */ 58 int fw; /* frame width */
@@ -120,8 +91,7 @@ static struct fb_var_screeninfo metronomefb_var __devinitdata = {
120 .transp = { 0, 0, 0 }, 91 .transp = { 0, 0, 0 },
121}; 92};
122 93
123static unsigned int metronomefb_enable; 94/* the waveform structure that is coming from userspace firmware */
124
125struct waveform_hdr { 95struct waveform_hdr {
126 u8 stuff[32]; 96 u8 stuff[32];
127 97
@@ -301,165 +271,6 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
301 return 0; 271 return 0;
302} 272}
303 273
304/* register offsets for gpio control */
305#define LED_GPIO_PIN 51
306#define STDBY_GPIO_PIN 48
307#define RST_GPIO_PIN 49
308#define RDY_GPIO_PIN 32
309#define ERR_GPIO_PIN 17
310#define PCBPWR_GPIO_PIN 16
311
312#define AF_SEL_GPIO_N 0x3
313#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
314#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
315#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
316#define GPDR1_OFFSET(pin) (pin - 32)
317#define GPCR1_OFFSET(pin) (pin - 32)
318#define GPSR1_OFFSET(pin) (pin - 32)
319#define GPCR0_OFFSET(pin) (pin)
320#define GPSR0_OFFSET(pin) (pin)
321
322static void metronome_set_gpio_output(int pin, int val)
323{
324 u8 index;
325
326 index = pin >> 4;
327
328 switch (index) {
329 case 1:
330 if (val)
331 GPSR0 |= (1 << GPSR0_OFFSET(pin));
332 else
333 GPCR0 |= (1 << GPCR0_OFFSET(pin));
334 break;
335 case 2:
336 break;
337 case 3:
338 if (val)
339 GPSR1 |= (1 << GPSR1_OFFSET(pin));
340 else
341 GPCR1 |= (1 << GPCR1_OFFSET(pin));
342 break;
343 default:
344 printk(KERN_ERR "unimplemented\n");
345 }
346}
347
348static void __devinit metronome_init_gpio_pin(int pin, int dir)
349{
350 u8 index;
351 /* dir 0 is output, 1 is input
352 - do 2 things here:
353 - set gpio alternate function to standard gpio
354 - set gpio direction to input or output */
355
356 index = pin >> 4;
357 switch (index) {
358 case 1:
359 GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
360
361 if (dir)
362 GPDR0 &= ~(1 << pin);
363 else
364 GPDR0 |= (1 << pin);
365 break;
366 case 2:
367 GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
368
369 if (dir)
370 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
371 else
372 GPDR1 |= (1 << GPDR1_OFFSET(pin));
373 break;
374 case 3:
375 GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
376
377 if (dir)
378 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
379 else
380 GPDR1 |= (1 << GPDR1_OFFSET(pin));
381 break;
382 default:
383 printk(KERN_ERR "unimplemented\n");
384 }
385}
386
387static void __devinit metronome_init_gpio_regs(void)
388{
389 metronome_init_gpio_pin(LED_GPIO_PIN, 0);
390 metronome_set_gpio_output(LED_GPIO_PIN, 0);
391
392 metronome_init_gpio_pin(STDBY_GPIO_PIN, 0);
393 metronome_set_gpio_output(STDBY_GPIO_PIN, 0);
394
395 metronome_init_gpio_pin(RST_GPIO_PIN, 0);
396 metronome_set_gpio_output(RST_GPIO_PIN, 0);
397
398 metronome_init_gpio_pin(RDY_GPIO_PIN, 1);
399
400 metronome_init_gpio_pin(ERR_GPIO_PIN, 1);
401
402 metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
403 metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0);
404}
405
406static void metronome_disable_lcd_controller(struct metronomefb_par *par)
407{
408 LCSR = 0xffffffff; /* Clear LCD Status Register */
409 LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
410
411 /* we reset and just wait for things to settle */
412 msleep(200);
413}
414
415static void metronome_enable_lcd_controller(struct metronomefb_par *par)
416{
417 LCSR = 0xffffffff;
418 FDADR0 = par->metromem_desc_dma;
419 LCCR0 |= LCCR0_ENB;
420}
421
422static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par)
423{
424 /* here we do:
425 - disable the lcd controller
426 - setup lcd control registers
427 - setup dma descriptor
428 - reenable lcd controller
429 */
430
431 /* disable the lcd controller */
432 metronome_disable_lcd_controller(par);
433
434 /* setup lcd control registers */
435 LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
436 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
437
438 LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */
439 | (27 << 10) /* hsync pulse width - 1 */
440 | (33 << 16) /* eol pixel count */
441 | (33 << 24); /* bol pixel count */
442
443 LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */
444 | (24 << 10) /* vsync pulse width - 1 */
445 | (2 << 16) /* eof pixel count */
446 | (0 << 24); /* bof pixel count */
447
448 LCCR3 = 2 /* pixel clock divisor */
449 | (24 << 8) /* AC Bias pin freq */
450 | LCCR3_16BPP /* BPP */
451 | LCCR3_PCP; /* PCP falling edge */
452
453 /* setup dma descriptor */
454 par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
455 par->metromem_desc->mFSADR0 = par->metromem_dma;
456 par->metromem_desc->mFIDR0 = 0;
457 par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw
458 * epd_frame_table[0].fh;
459 /* reenable lcd controller */
460 metronome_enable_lcd_controller(par);
461}
462
463static int metronome_display_cmd(struct metronomefb_par *par) 274static int metronome_display_cmd(struct metronomefb_par *par)
464{ 275{
465 int i; 276 int i;
@@ -493,8 +304,7 @@ static int metronome_display_cmd(struct metronomefb_par *par)
493 par->metromem_cmd->csum = cs; 304 par->metromem_cmd->csum = cs;
494 par->metromem_cmd->opcode = opcode; /* display cmd */ 305 par->metromem_cmd->opcode = opcode; /* display cmd */
495 306
496 i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); 307 return par->board->met_wait_event_intr(par);
497 return i;
498} 308}
499 309
500static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) 310static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
@@ -518,13 +328,12 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
518 par->metromem_cmd->csum = cs; 328 par->metromem_cmd->csum = cs;
519 329
520 msleep(1); 330 msleep(1);
521 metronome_set_gpio_output(RST_GPIO_PIN, 1); 331 par->board->set_rst(par, 1);
522 332
523 msleep(1); 333 msleep(1);
524 metronome_set_gpio_output(STDBY_GPIO_PIN, 1); 334 par->board->set_stdby(par, 1);
525 335
526 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); 336 return par->board->met_wait_event(par);
527 return i;
528} 337}
529 338
530static int __devinit metronome_config_cmd(struct metronomefb_par *par) 339static int __devinit metronome_config_cmd(struct metronomefb_par *par)
@@ -569,8 +378,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par)
569 par->metromem_cmd->csum = cs; 378 par->metromem_cmd->csum = cs;
570 par->metromem_cmd->opcode = 0xCC10; /* config cmd */ 379 par->metromem_cmd->opcode = 0xCC10; /* config cmd */
571 380
572 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); 381 return par->board->met_wait_event(par);
573 return i;
574} 382}
575 383
576static int __devinit metronome_init_cmd(struct metronomefb_par *par) 384static int __devinit metronome_init_cmd(struct metronomefb_par *par)
@@ -596,16 +404,19 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par)
596 par->metromem_cmd->csum = cs; 404 par->metromem_cmd->csum = cs;
597 par->metromem_cmd->opcode = 0xCC20; /* init cmd */ 405 par->metromem_cmd->opcode = 0xCC20; /* init cmd */
598 406
599 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); 407 return par->board->met_wait_event(par);
600 return i;
601} 408}
602 409
603static int __devinit metronome_init_regs(struct metronomefb_par *par) 410static int __devinit metronome_init_regs(struct metronomefb_par *par)
604{ 411{
605 int res; 412 int res;
606 413
607 metronome_init_gpio_regs(); 414 par->board->init_gpio_regs(par);
608 metronome_init_lcdc_regs(par); 415
416 par->board->init_lcdc_regs(par);
417
418 /* now that lcd is setup, setup dma descriptor */
419 par->board->post_dma_setup(par);
609 420
610 res = metronome_powerup_cmd(par); 421 res = metronome_powerup_cmd(par);
611 if (res) 422 if (res)
@@ -616,8 +427,6 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
616 return res; 427 return res;
617 428
618 res = metronome_init_cmd(par); 429 res = metronome_init_cmd(par);
619 if (res)
620 return res;
621 430
622 return res; 431 return res;
623} 432}
@@ -632,7 +441,7 @@ static void metronomefb_dpy_update(struct metronomefb_par *par)
632 441
633 cksum = calc_img_cksum((u16 *) par->metromem_img, 442 cksum = calc_img_cksum((u16 *) par->metromem_img,
634 (epd_frame_table[0].fw * DPY_H)/2); 443 (epd_frame_table[0].fw * DPY_H)/2);
635 *((u16 *) (par->metromem_img) + 444 *((u16 *)(par->metromem_img) +
636 (epd_frame_table[0].fw * DPY_H)/2) = cksum; 445 (epd_frame_table[0].fw * DPY_H)/2) = cksum;
637 metronome_display_cmd(par); 446 metronome_display_cmd(par);
638} 447}
@@ -641,8 +450,8 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
641{ 450{
642 int i; 451 int i;
643 u16 csum = 0; 452 u16 csum = 0;
644 u16 *buf = (u16 __force *) (par->info->screen_base + index); 453 u16 *buf = (u16 __force *)(par->info->screen_base + index);
645 u16 *img = (u16 *) (par->metromem_img + index); 454 u16 *img = (u16 *)(par->metromem_img + index);
646 455
647 /* swizzle from vm to metromem and recalc cksum at the same time*/ 456 /* swizzle from vm to metromem and recalc cksum at the same time*/
648 for (i = 0; i < PAGE_SIZE/2; i++) { 457 for (i = 0; i < PAGE_SIZE/2; i++) {
@@ -733,7 +542,7 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
733 count = total_size - p; 542 count = total_size - p;
734 } 543 }
735 544
736 dst = (void __force *) (info->screen_base + p); 545 dst = (void __force *)(info->screen_base + p);
737 546
738 if (copy_from_user(dst, buf, count)) 547 if (copy_from_user(dst, buf, count))
739 err = -EFAULT; 548 err = -EFAULT;
@@ -759,18 +568,10 @@ static struct fb_deferred_io metronomefb_defio = {
759 .deferred_io = metronomefb_dpy_deferred_io, 568 .deferred_io = metronomefb_dpy_deferred_io,
760}; 569};
761 570
762static irqreturn_t metronome_handle_irq(int irq, void *dev_id)
763{
764 struct fb_info *info = dev_id;
765 struct metronomefb_par *par = info->par;
766
767 wake_up_interruptible(&par->waitq);
768 return IRQ_HANDLED;
769}
770
771static int __devinit metronomefb_probe(struct platform_device *dev) 571static int __devinit metronomefb_probe(struct platform_device *dev)
772{ 572{
773 struct fb_info *info; 573 struct fb_info *info;
574 struct metronome_board *board;
774 int retval = -ENOMEM; 575 int retval = -ENOMEM;
775 int videomemorysize; 576 int videomemorysize;
776 unsigned char *videomemory; 577 unsigned char *videomemory;
@@ -779,17 +580,26 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
779 int cmd_size, wfm_size, img_size, padding_size, totalsize; 580 int cmd_size, wfm_size, img_size, padding_size, totalsize;
780 int i; 581 int i;
781 582
583 /* pick up board specific routines */
584 board = dev->dev.platform_data;
585 if (!board)
586 return -EINVAL;
587
588 /* try to count device specific driver, if can't, platform recalls */
589 if (!try_module_get(board->owner))
590 return -ENODEV;
591
782 /* we have two blocks of memory. 592 /* we have two blocks of memory.
783 info->screen_base which is vm, and is the fb used by apps. 593 info->screen_base which is vm, and is the fb used by apps.
784 par->metromem which is physically contiguous memory and 594 par->metromem which is physically contiguous memory and
785 contains the display controller commands, waveform, 595 contains the display controller commands, waveform,
786 processed image data and padding. this is the data pulled 596 processed image data and padding. this is the data pulled
787 by the pxa255's LCD controller and pushed to Metronome */ 597 by the device's LCD controller and pushed to Metronome */
788 598
789 videomemorysize = (DPY_W*DPY_H); 599 videomemorysize = (DPY_W*DPY_H);
790 videomemory = vmalloc(videomemorysize); 600 videomemory = vmalloc(videomemorysize);
791 if (!videomemory) 601 if (!videomemory)
792 return retval; 602 return -ENOMEM;
793 603
794 memset(videomemory, 0, videomemorysize); 604 memset(videomemory, 0, videomemorysize);
795 605
@@ -797,7 +607,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
797 if (!info) 607 if (!info)
798 goto err_vfree; 608 goto err_vfree;
799 609
800 info->screen_base = (char __iomem *) videomemory; 610 info->screen_base = (char __force __iomem *)videomemory;
801 info->fbops = &metronomefb_ops; 611 info->fbops = &metronomefb_ops;
802 612
803 info->var = metronomefb_var; 613 info->var = metronomefb_var;
@@ -805,6 +615,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
805 info->fix.smem_len = videomemorysize; 615 info->fix.smem_len = videomemorysize;
806 par = info->par; 616 par = info->par;
807 par->info = info; 617 par->info = info;
618 par->board = board;
808 init_waitqueue_head(&par->waitq); 619 init_waitqueue_head(&par->waitq);
809 620
810 /* this table caches per page csum values. */ 621 /* this table caches per page csum values. */
@@ -849,11 +660,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
849 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size 660 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
850 + img_size + padding_size; 661 + img_size + padding_size;
851 662
852 /* load the waveform in. assume mode 3, temp 31 for now */ 663 /* load the waveform in. assume mode 3, temp 31 for now
853 /* a) request the waveform file from userspace 664 a) request the waveform file from userspace
854 b) process waveform and decode into metromem */ 665 b) process waveform and decode into metromem */
855 666 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
856 retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev);
857 if (retval < 0) { 667 if (retval < 0) {
858 printk(KERN_ERR "metronomefb: couldn't get waveform\n"); 668 printk(KERN_ERR "metronomefb: couldn't get waveform\n");
859 goto err_dma_free; 669 goto err_dma_free;
@@ -867,13 +677,8 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
867 } 677 }
868 release_firmware(fw_entry); 678 release_firmware(fw_entry);
869 679
870 retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq, 680 if (board->setup_irq(info))
871 IRQF_DISABLED, "Metronome", info);
872 if (retval) {
873 dev_err(&dev->dev, "request_irq failed: %d\n", retval);
874 goto err_ld_wfm; 681 goto err_ld_wfm;
875 }
876 set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
877 682
878 retval = metronome_init_regs(par); 683 retval = metronome_init_regs(par);
879 if (retval < 0) 684 if (retval < 0)
@@ -913,7 +718,7 @@ err_cmap:
913err_fb_rel: 718err_fb_rel:
914 framebuffer_release(info); 719 framebuffer_release(info);
915err_free_irq: 720err_free_irq:
916 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); 721 board->free_irq(info);
917err_ld_wfm: 722err_ld_wfm:
918 release_firmware(fw_entry); 723 release_firmware(fw_entry);
919err_dma_free: 724err_dma_free:
@@ -923,6 +728,7 @@ err_csum_table:
923 vfree(par->csum_table); 728 vfree(par->csum_table);
924err_vfree: 729err_vfree:
925 vfree(videomemory); 730 vfree(videomemory);
731 module_put(board->owner);
926 return retval; 732 return retval;
927} 733}
928 734
@@ -939,7 +745,8 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
939 vfree(par->csum_table); 745 vfree(par->csum_table);
940 unregister_framebuffer(info); 746 unregister_framebuffer(info);
941 vfree((void __force *)info->screen_base); 747 vfree((void __force *)info->screen_base);
942 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); 748 par->board->free_irq(info);
749 module_put(par->board->owner);
943 framebuffer_release(info); 750 framebuffer_release(info);
944 } 751 }
945 return 0; 752 return 0;
@@ -949,48 +756,21 @@ static struct platform_driver metronomefb_driver = {
949 .probe = metronomefb_probe, 756 .probe = metronomefb_probe,
950 .remove = metronomefb_remove, 757 .remove = metronomefb_remove,
951 .driver = { 758 .driver = {
759 .owner = THIS_MODULE,
952 .name = "metronomefb", 760 .name = "metronomefb",
953 }, 761 },
954}; 762};
955 763
956static struct platform_device *metronomefb_device;
957
958static int __init metronomefb_init(void) 764static int __init metronomefb_init(void)
959{ 765{
960 int ret; 766 return platform_driver_register(&metronomefb_driver);
961
962 if (!metronomefb_enable) {
963 printk(KERN_ERR
964 "Use metronomefb_enable to enable the device\n");
965 return -ENXIO;
966 }
967
968 ret = platform_driver_register(&metronomefb_driver);
969 if (!ret) {
970 metronomefb_device = platform_device_alloc("metronomefb", 0);
971 if (metronomefb_device)
972 ret = platform_device_add(metronomefb_device);
973 else
974 ret = -ENOMEM;
975
976 if (ret) {
977 platform_device_put(metronomefb_device);
978 platform_driver_unregister(&metronomefb_driver);
979 }
980 }
981 return ret;
982
983} 767}
984 768
985static void __exit metronomefb_exit(void) 769static void __exit metronomefb_exit(void)
986{ 770{
987 platform_device_unregister(metronomefb_device);
988 platform_driver_unregister(&metronomefb_driver); 771 platform_driver_unregister(&metronomefb_driver);
989} 772}
990 773
991module_param(metronomefb_enable, uint, 0);
992MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome");
993
994module_init(metronomefb_init); 774module_init(metronomefb_init);
995module_exit(metronomefb_exit); 775module_exit(metronomefb_exit);
996 776
diff --git a/include/video/metronomefb.h b/include/video/metronomefb.h
new file mode 100644
index 000000000000..dab04b4fad7f
--- /dev/null
+++ b/include/video/metronomefb.h
@@ -0,0 +1,62 @@
1/*
2 * metronomefb.h - definitions for the metronome framebuffer driver
3 *
4 * Copyright (C) 2008 by 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 */
11
12#ifndef _LINUX_METRONOMEFB_H_
13#define _LINUX_METRONOMEFB_H_
14
15/* address and control descriptors used by metronome controller */
16struct metromem_desc {
17 u32 mFDADR0;
18 u32 mFSADR0;
19 u32 mFIDR0;
20 u32 mLDCMD0;
21};
22
23/* command structure used by metronome controller */
24struct metromem_cmd {
25 u16 opcode;
26 u16 args[((64-2)/2)];
27 u16 csum;
28};
29
30/* struct used by metronome. board specific stuff comes from *board */
31struct metronomefb_par {
32 unsigned char *metromem;
33 struct metromem_desc *metromem_desc;
34 struct metromem_cmd *metromem_cmd;
35 unsigned char *metromem_wfm;
36 unsigned char *metromem_img;
37 u16 *metromem_img_csum;
38 u16 *csum_table;
39 int metromemsize;
40 dma_addr_t metromem_dma;
41 dma_addr_t metromem_desc_dma;
42 struct fb_info *info;
43 struct metronome_board *board;
44 wait_queue_head_t waitq;
45 u8 frame_count;
46};
47
48/* board specific routines */
49struct metronome_board {
50 struct module *owner;
51 void (*free_irq)(struct fb_info *);
52 void (*init_gpio_regs)(struct metronomefb_par *);
53 void (*init_lcdc_regs)(struct metronomefb_par *);
54 void (*post_dma_setup)(struct metronomefb_par *);
55 void (*set_rst)(struct metronomefb_par *, int);
56 void (*set_stdby)(struct metronomefb_par *, int);
57 int (*met_wait_event)(struct metronomefb_par *);
58 int (*met_wait_event_intr)(struct metronomefb_par *);
59 int (*setup_irq)(struct fb_info *);
60};
61
62#endif