fbdev: add the carmine FB driver
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / video / am200epd.c
blob51e26c1f5e8b747310cc5b6e2aff47c5661336a9
1 /*
2 * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit
4 * Copyright (C) 2008, Jaya Kumar
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.
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
12 * This work was made possible by help and equipment support from E-Ink
13 * Corporation. http://support.eink.com/community
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.
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>
34 #include <video/metronomefb.h>
36 #include <asm/arch/pxa-regs.h>
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
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)
56 static void am200_set_gpio_output(int pin, int val)
58 u8 index;
60 index = pin >> 4;
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");
82 static void __devinit am200_init_gpio_pin(int pin, int dir)
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 */
90 index = pin >> 4;
91 switch (index) {
92 case 1:
93 GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
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));
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));
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");
121 static void am200_init_gpio_regs(struct metronomefb_par *par)
123 am200_init_gpio_pin(LED_GPIO_PIN, 0);
124 am200_set_gpio_output(LED_GPIO_PIN, 0);
126 am200_init_gpio_pin(STDBY_GPIO_PIN, 0);
127 am200_set_gpio_output(STDBY_GPIO_PIN, 0);
129 am200_init_gpio_pin(RST_GPIO_PIN, 0);
130 am200_set_gpio_output(RST_GPIO_PIN, 0);
132 am200_init_gpio_pin(RDY_GPIO_PIN, 1);
134 am200_init_gpio_pin(ERR_GPIO_PIN, 1);
136 am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
137 am200_set_gpio_output(PCBPWR_GPIO_PIN, 0);
140 static void am200_disable_lcd_controller(struct metronomefb_par *par)
142 LCSR = 0xffffffff; /* Clear LCD Status Register */
143 LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
145 /* we reset and just wait for things to settle */
146 msleep(200);
149 static void am200_enable_lcd_controller(struct metronomefb_par *par)
151 LCSR = 0xffffffff;
152 FDADR0 = par->metromem_desc_dma;
153 LCCR0 |= LCCR0_ENB;
156 static void am200_init_lcdc_regs(struct metronomefb_par *par)
158 /* here we do:
159 - disable the lcd controller
160 - setup lcd control registers
161 - setup dma descriptor
162 - reenable lcd controller
165 /* disable the lcd controller */
166 am200_disable_lcd_controller(par);
168 /* setup lcd control registers */
169 LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
170 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
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 */
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 */
182 LCCR3 = 2 /* pixel clock divisor */
183 | (24 << 8) /* AC Bias pin freq */
184 | LCCR3_16BPP /* BPP */
185 | LCCR3_PCP; /* PCP falling edge */
189 static void am200_post_dma_setup(struct metronomefb_par *par)
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);
199 static void am200_free_irq(struct fb_info *info)
201 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
204 static irqreturn_t am200_handle_irq(int irq, void *dev_id)
206 struct fb_info *info = dev_id;
207 struct metronomefb_par *par = info->par;
209 wake_up_interruptible(&par->waitq);
210 return IRQ_HANDLED;
213 static int am200_setup_irq(struct fb_info *info)
215 int retval;
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;
224 return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
227 static void am200_set_rst(struct metronomefb_par *par, int state)
229 am200_set_gpio_output(RST_GPIO_PIN, state);
232 static void am200_set_stdby(struct metronomefb_par *par, int state)
234 am200_set_gpio_output(STDBY_GPIO_PIN, state);
237 static int am200_wait_event(struct metronomefb_par *par)
239 return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
242 static int am200_wait_event_intr(struct metronomefb_par *par)
244 return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
247 static 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,
260 static struct platform_device *am200_device;
262 static int __init am200_init(void)
264 int ret;
266 /* request our platform independent driver */
267 request_module("metronomefb");
269 am200_device = platform_device_alloc("metronomefb", -1);
270 if (!am200_device)
271 return -ENOMEM;
273 platform_device_add_data(am200_device, &am200_board,
274 sizeof(am200_board));
276 /* this _add binds metronomefb to am200. metronomefb refcounts am200 */
277 ret = platform_device_add(am200_device);
279 if (ret)
280 platform_device_put(am200_device);
282 return ret;
285 static void __exit am200_exit(void)
287 platform_device_unregister(am200_device);
290 module_init(am200_init);
291 module_exit(am200_exit);
293 MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
294 MODULE_AUTHOR("Jaya Kumar");
295 MODULE_LICENSE("GPL");