• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/msm/
1/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18#include "msm_fb.h"
19
20#include <linux/memory.h>
21#include <linux/kernel.h>
22#include <linux/sched.h>
23#include <linux/time.h>
24#include <linux/init.h>
25#include <linux/interrupt.h>
26#include "linux/proc_fs.h"
27
28#include <linux/delay.h>
29
30#include <mach/hardware.h>
31#include <linux/io.h>
32
33#include <asm/system.h>
34#include <asm/mach-types.h>
35
36/* The following are for MSM5100 on Gator
37*/
38#ifdef FEATURE_PM1000
39#include "pm1000.h"
40#endif /* FEATURE_PM1000 */
41/* The following are for MSM6050 on Bambi
42*/
43#ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER
44#include "pm.h"
45#endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */
46
47#ifdef DISP_DEVICE_18BPP
48#undef DISP_DEVICE_18BPP
49#define DISP_DEVICE_16BPP
50#endif
51
52#define QCIF_WIDTH        176
53#define QCIF_HEIGHT       220
54
55static void *DISP_CMD_PORT;
56static void *DISP_DATA_PORT;
57
58#define DISP_CMD_DISON    0xaf
59#define DISP_CMD_DISOFF   0xae
60#define DISP_CMD_DISNOR   0xa6
61#define DISP_CMD_DISINV   0xa7
62#define DISP_CMD_DISCTL   0xca
63#define DISP_CMD_GCP64    0xcb
64#define DISP_CMD_GCP16    0xcc
65#define DISP_CMD_GSSET    0xcd
66#define DISP_GS_2       0x02
67#define DISP_GS_16      0x01
68#define DISP_GS_64      0x00
69#define DISP_CMD_SLPIN    0x95
70#define DISP_CMD_SLPOUT   0x94
71#define DISP_CMD_SD_PSET  0x75
72#define DISP_CMD_MD_PSET  0x76
73#define DISP_CMD_SD_CSET  0x15
74#define DISP_CMD_MD_CSET  0x16
75#define DISP_CMD_DATCTL   0xbc
76#define DISP_DATCTL_666 0x08
77#define DISP_DATCTL_565 0x28
78#define DISP_DATCTL_444 0x38
79#define DISP_CMD_RAMWR    0x5c
80#define DISP_CMD_RAMRD    0x5d
81#define DISP_CMD_PTLIN    0xa8
82#define DISP_CMD_PTLOUT   0xa9
83#define DISP_CMD_ASCSET   0xaa
84#define DISP_CMD_SCSTART  0xab
85#define DISP_CMD_VOLCTL   0xc6
86#define DISP_VOLCTL_TONE 0x80
87#define DISP_CMD_NOp      0x25
88#define DISP_CMD_OSSEL    0xd0
89#define DISP_CMD_3500KSET 0xd1
90#define DISP_CMD_3500KEND 0xd2
91#define DISP_CMD_14MSET   0xd3
92#define DISP_CMD_14MEND   0xd4
93
94#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd);
95
96#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data);
97
98#define DISP_DATA_IN() inpw(DISP_DATA_PORT);
99
100/* Epson device column number starts at 2
101*/
102#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \
103	  DISP_CMD_OUT(DISP_CMD_SD_PSET) \
104	  DISP_DATA_OUT((ulhc_row) & 0xFF) \
105	  DISP_DATA_OUT((ulhc_row) >> 8) \
106	  DISP_DATA_OUT((lrhc_row) & 0xFF) \
107	  DISP_DATA_OUT((lrhc_row) >> 8) \
108	  DISP_CMD_OUT(DISP_CMD_SD_CSET) \
109	  DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \
110	  DISP_DATA_OUT(((ulhc_col)+2) >> 8) \
111	  DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \
112	  DISP_DATA_OUT(((lrhc_col)+2) >> 8)
113
114#define DISP_MIN_CONTRAST      0
115#define DISP_MAX_CONTRAST      127
116#define DISP_DEFAULT_CONTRAST  80
117
118#define DISP_MIN_BACKLIGHT     0
119#define DISP_MAX_BACKLIGHT     15
120#define DISP_DEFAULT_BACKLIGHT 2
121
122#define WAIT_SEC(sec) mdelay((sec)/1000)
123
124static word disp_area_start_row;
125static word disp_area_end_row;
126static byte disp_contrast = DISP_DEFAULT_CONTRAST;
127static boolean disp_powered_up;
128static boolean disp_initialized = FALSE;
129/* For some reason the contrast set at init time is not good. Need to do
130 * it again
131 */
132static boolean display_on = FALSE;
133static void epsonQcif_disp_init(struct platform_device *pdev);
134static void epsonQcif_disp_set_contrast(word contrast);
135static void epsonQcif_disp_set_display_area(word start_row, word end_row);
136static int epsonQcif_disp_off(struct platform_device *pdev);
137static int epsonQcif_disp_on(struct platform_device *pdev);
138static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres);
139
140volatile word databack;
141static void epsonQcif_disp_init(struct platform_device *pdev)
142{
143	struct msm_fb_data_type *mfd;
144
145	int i;
146
147	if (disp_initialized)
148		return;
149
150	mfd = platform_get_drvdata(pdev);
151
152	DISP_CMD_PORT = mfd->cmd_port;
153	DISP_DATA_PORT = mfd->data_port;
154
155	/* Sleep in */
156	DISP_CMD_OUT(DISP_CMD_SLPIN);
157
158	/* Display off */
159	DISP_CMD_OUT(DISP_CMD_DISOFF);
160
161	/* Display normal */
162	DISP_CMD_OUT(DISP_CMD_DISNOR);
163
164	/* Set data mode */
165	DISP_CMD_OUT(DISP_CMD_DATCTL);
166	DISP_DATA_OUT(DISP_DATCTL_565);
167
168	/* Set display timing */
169	DISP_CMD_OUT(DISP_CMD_DISCTL);
170	DISP_DATA_OUT(0x1c);	/* p1 */
171	DISP_DATA_OUT(0x02);	/* p1 */
172	DISP_DATA_OUT(0x82);	/* p2 */
173	DISP_DATA_OUT(0x00);	/* p3 */
174	DISP_DATA_OUT(0x00);	/* p4 */
175	DISP_DATA_OUT(0xe0);	/* p5 */
176	DISP_DATA_OUT(0x00);	/* p5 */
177	DISP_DATA_OUT(0xdc);	/* p6 */
178	DISP_DATA_OUT(0x00);	/* p6 */
179	DISP_DATA_OUT(0x02);	/* p7 */
180	DISP_DATA_OUT(0x00);	/* p8 */
181
182	/* Set 64 gray scale level */
183	DISP_CMD_OUT(DISP_CMD_GCP64);
184	DISP_DATA_OUT(0x08);	/* p01 */
185	DISP_DATA_OUT(0x00);
186	DISP_DATA_OUT(0x2a);	/* p02 */
187	DISP_DATA_OUT(0x00);
188	DISP_DATA_OUT(0x4e);	/* p03 */
189	DISP_DATA_OUT(0x00);
190	DISP_DATA_OUT(0x6b);	/* p04 */
191	DISP_DATA_OUT(0x00);
192	DISP_DATA_OUT(0x88);	/* p05 */
193	DISP_DATA_OUT(0x00);
194	DISP_DATA_OUT(0xa3);	/* p06 */
195	DISP_DATA_OUT(0x00);
196	DISP_DATA_OUT(0xba);	/* p07 */
197	DISP_DATA_OUT(0x00);
198	DISP_DATA_OUT(0xd1);	/* p08 */
199	DISP_DATA_OUT(0x00);
200	DISP_DATA_OUT(0xe5);	/* p09 */
201	DISP_DATA_OUT(0x00);
202	DISP_DATA_OUT(0xf3);	/* p10 */
203	DISP_DATA_OUT(0x00);
204	DISP_DATA_OUT(0x03);	/* p11 */
205	DISP_DATA_OUT(0x01);
206	DISP_DATA_OUT(0x13);	/* p12 */
207	DISP_DATA_OUT(0x01);
208	DISP_DATA_OUT(0x22);	/* p13 */
209	DISP_DATA_OUT(0x01);
210	DISP_DATA_OUT(0x2f);	/* p14 */
211	DISP_DATA_OUT(0x01);
212	DISP_DATA_OUT(0x3b);	/* p15 */
213	DISP_DATA_OUT(0x01);
214	DISP_DATA_OUT(0x46);	/* p16 */
215	DISP_DATA_OUT(0x01);
216	DISP_DATA_OUT(0x51);	/* p17 */
217	DISP_DATA_OUT(0x01);
218	DISP_DATA_OUT(0x5b);	/* p18 */
219	DISP_DATA_OUT(0x01);
220	DISP_DATA_OUT(0x64);	/* p19 */
221	DISP_DATA_OUT(0x01);
222	DISP_DATA_OUT(0x6c);	/* p20 */
223	DISP_DATA_OUT(0x01);
224	DISP_DATA_OUT(0x74);	/* p21 */
225	DISP_DATA_OUT(0x01);
226	DISP_DATA_OUT(0x7c);	/* p22 */
227	DISP_DATA_OUT(0x01);
228	DISP_DATA_OUT(0x83);	/* p23 */
229	DISP_DATA_OUT(0x01);
230	DISP_DATA_OUT(0x8a);	/* p24 */
231	DISP_DATA_OUT(0x01);
232	DISP_DATA_OUT(0x91);	/* p25 */
233	DISP_DATA_OUT(0x01);
234	DISP_DATA_OUT(0x98);	/* p26 */
235	DISP_DATA_OUT(0x01);
236	DISP_DATA_OUT(0x9f);	/* p27 */
237	DISP_DATA_OUT(0x01);
238	DISP_DATA_OUT(0xa6);	/* p28 */
239	DISP_DATA_OUT(0x01);
240	DISP_DATA_OUT(0xac);	/* p29 */
241	DISP_DATA_OUT(0x01);
242	DISP_DATA_OUT(0xb2);	/* p30 */
243	DISP_DATA_OUT(0x01);
244	DISP_DATA_OUT(0xb7);	/* p31 */
245	DISP_DATA_OUT(0x01);
246	DISP_DATA_OUT(0xbc);	/* p32 */
247	DISP_DATA_OUT(0x01);
248	DISP_DATA_OUT(0xc1);	/* p33 */
249	DISP_DATA_OUT(0x01);
250	DISP_DATA_OUT(0xc6);	/* p34 */
251	DISP_DATA_OUT(0x01);
252	DISP_DATA_OUT(0xcb);	/* p35 */
253	DISP_DATA_OUT(0x01);
254	DISP_DATA_OUT(0xd0);	/* p36 */
255	DISP_DATA_OUT(0x01);
256	DISP_DATA_OUT(0xd4);	/* p37 */
257	DISP_DATA_OUT(0x01);
258	DISP_DATA_OUT(0xd8);	/* p38 */
259	DISP_DATA_OUT(0x01);
260	DISP_DATA_OUT(0xdc);	/* p39 */
261	DISP_DATA_OUT(0x01);
262	DISP_DATA_OUT(0xe0);	/* p40 */
263	DISP_DATA_OUT(0x01);
264	DISP_DATA_OUT(0xe4);	/* p41 */
265	DISP_DATA_OUT(0x01);
266	DISP_DATA_OUT(0xe8);	/* p42 */
267	DISP_DATA_OUT(0x01);
268	DISP_DATA_OUT(0xec);	/* p43 */
269	DISP_DATA_OUT(0x01);
270	DISP_DATA_OUT(0xf0);	/* p44 */
271	DISP_DATA_OUT(0x01);
272	DISP_DATA_OUT(0xf4);	/* p45 */
273	DISP_DATA_OUT(0x01);
274	DISP_DATA_OUT(0xf8);	/* p46 */
275	DISP_DATA_OUT(0x01);
276	DISP_DATA_OUT(0xfb);	/* p47 */
277	DISP_DATA_OUT(0x01);
278	DISP_DATA_OUT(0xfe);	/* p48 */
279	DISP_DATA_OUT(0x01);
280	DISP_DATA_OUT(0x01);	/* p49 */
281	DISP_DATA_OUT(0x02);
282	DISP_DATA_OUT(0x03);	/* p50 */
283	DISP_DATA_OUT(0x02);
284	DISP_DATA_OUT(0x05);	/* p51 */
285	DISP_DATA_OUT(0x02);
286	DISP_DATA_OUT(0x07);	/* p52 */
287	DISP_DATA_OUT(0x02);
288	DISP_DATA_OUT(0x09);	/* p53 */
289	DISP_DATA_OUT(0x02);
290	DISP_DATA_OUT(0x0b);	/* p54 */
291	DISP_DATA_OUT(0x02);
292	DISP_DATA_OUT(0x0d);	/* p55 */
293	DISP_DATA_OUT(0x02);
294	DISP_DATA_OUT(0x0f);	/* p56 */
295	DISP_DATA_OUT(0x02);
296	DISP_DATA_OUT(0x11);	/* p57 */
297	DISP_DATA_OUT(0x02);
298	DISP_DATA_OUT(0x13);	/* p58 */
299	DISP_DATA_OUT(0x02);
300	DISP_DATA_OUT(0x15);	/* p59 */
301	DISP_DATA_OUT(0x02);
302	DISP_DATA_OUT(0x17);	/* p60 */
303	DISP_DATA_OUT(0x02);
304	DISP_DATA_OUT(0x19);	/* p61 */
305	DISP_DATA_OUT(0x02);
306	DISP_DATA_OUT(0x1b);	/* p62 */
307	DISP_DATA_OUT(0x02);
308	DISP_DATA_OUT(0x1c);	/* p63 */
309	DISP_DATA_OUT(0x02);
310
311	/* Set 16 gray scale level */
312	DISP_CMD_OUT(DISP_CMD_GCP16);
313	DISP_DATA_OUT(0x1a);	/* p01 */
314	DISP_DATA_OUT(0x32);	/* p02 */
315	DISP_DATA_OUT(0x42);	/* p03 */
316	DISP_DATA_OUT(0x4c);	/* p04 */
317	DISP_DATA_OUT(0x58);	/* p05 */
318	DISP_DATA_OUT(0x5f);	/* p06 */
319	DISP_DATA_OUT(0x66);	/* p07 */
320	DISP_DATA_OUT(0x6b);	/* p08 */
321	DISP_DATA_OUT(0x70);	/* p09 */
322	DISP_DATA_OUT(0x74);	/* p10 */
323	DISP_DATA_OUT(0x78);	/* p11 */
324	DISP_DATA_OUT(0x7b);	/* p12 */
325	DISP_DATA_OUT(0x7e);	/* p13 */
326	DISP_DATA_OUT(0x80);	/* p14 */
327	DISP_DATA_OUT(0x82);	/* p15 */
328
329	/* Set DSP column */
330	DISP_CMD_OUT(DISP_CMD_MD_CSET);
331	DISP_DATA_OUT(0xff);
332	DISP_DATA_OUT(0x03);
333	DISP_DATA_OUT(0xff);
334	DISP_DATA_OUT(0x03);
335
336	/* Set DSP page */
337	DISP_CMD_OUT(DISP_CMD_MD_PSET);
338	DISP_DATA_OUT(0xff);
339	DISP_DATA_OUT(0x01);
340	DISP_DATA_OUT(0xff);
341	DISP_DATA_OUT(0x01);
342
343	/* Set ARM column */
344	DISP_CMD_OUT(DISP_CMD_SD_CSET);
345	DISP_DATA_OUT(0x02);
346	DISP_DATA_OUT(0x00);
347	DISP_DATA_OUT((QCIF_WIDTH + 1) & 0xFF);
348	DISP_DATA_OUT((QCIF_WIDTH + 1) >> 8);
349
350	/* Set ARM page */
351	DISP_CMD_OUT(DISP_CMD_SD_PSET);
352	DISP_DATA_OUT(0x00);
353	DISP_DATA_OUT(0x00);
354	DISP_DATA_OUT((QCIF_HEIGHT - 1) & 0xFF);
355	DISP_DATA_OUT((QCIF_HEIGHT - 1) >> 8);
356
357	/* Set 64 gray scales */
358	DISP_CMD_OUT(DISP_CMD_GSSET);
359	DISP_DATA_OUT(DISP_GS_64);
360
361	DISP_CMD_OUT(DISP_CMD_OSSEL);
362	DISP_DATA_OUT(0);
363
364	/* Sleep out */
365	DISP_CMD_OUT(DISP_CMD_SLPOUT);
366
367	WAIT_SEC(40000);
368
369	/* Initialize power IC */
370	DISP_CMD_OUT(DISP_CMD_VOLCTL);
371	DISP_DATA_OUT(DISP_VOLCTL_TONE);
372
373	WAIT_SEC(40000);
374
375	/* Set electronic volume, d'xx */
376	DISP_CMD_OUT(DISP_CMD_VOLCTL);
377	DISP_DATA_OUT(DISP_DEFAULT_CONTRAST);	/* value from 0 to 127 */
378
379	/* Initialize display data */
380	DISP_SET_RECT(0, (QCIF_HEIGHT - 1), 0, (QCIF_WIDTH - 1));
381	DISP_CMD_OUT(DISP_CMD_RAMWR);
382	for (i = 0; i < QCIF_HEIGHT * QCIF_WIDTH; i++)
383		DISP_DATA_OUT(0xffff);
384
385	DISP_CMD_OUT(DISP_CMD_RAMRD);
386	databack = DISP_DATA_IN();
387	databack = DISP_DATA_IN();
388	databack = DISP_DATA_IN();
389	databack = DISP_DATA_IN();
390
391	WAIT_SEC(80000);
392
393	DISP_CMD_OUT(DISP_CMD_DISON);
394
395	disp_area_start_row = 0;
396	disp_area_end_row = QCIF_HEIGHT - 1;
397	disp_powered_up = TRUE;
398	disp_initialized = TRUE;
399	epsonQcif_disp_set_display_area(0, QCIF_HEIGHT - 1);
400	display_on = TRUE;
401}
402
403static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres)
404{
405	if (!disp_initialized)
406		return;
407
408	DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1);
409	DISP_CMD_OUT(DISP_CMD_RAMWR);
410}
411
412static void epsonQcif_disp_set_display_area(word start_row, word end_row)
413{
414	if (!disp_initialized)
415		return;
416
417	if ((start_row == disp_area_start_row)
418	    && (end_row == disp_area_end_row))
419		return;
420	disp_area_start_row = start_row;
421	disp_area_end_row = end_row;
422
423	/* Range checking
424	 */
425	if (end_row >= QCIF_HEIGHT)
426		end_row = QCIF_HEIGHT - 1;
427	if (start_row > end_row)
428		start_row = end_row;
429
430	/* When display is not the full screen, gray scale is set to
431	 ** 2; otherwise it is set to 64.
432	 */
433	if ((start_row == 0) && (end_row == (QCIF_HEIGHT - 1))) {
434		/* The whole screen */
435		DISP_CMD_OUT(DISP_CMD_PTLOUT);
436		WAIT_SEC(10000);
437		DISP_CMD_OUT(DISP_CMD_DISOFF);
438		WAIT_SEC(100000);
439		DISP_CMD_OUT(DISP_CMD_GSSET);
440		DISP_DATA_OUT(DISP_GS_64);
441		WAIT_SEC(100000);
442		DISP_CMD_OUT(DISP_CMD_DISON);
443	} else {
444		/* partial screen */
445		DISP_CMD_OUT(DISP_CMD_PTLIN);
446		DISP_DATA_OUT(start_row);
447		DISP_DATA_OUT(start_row >> 8);
448		DISP_DATA_OUT(end_row);
449		DISP_DATA_OUT(end_row >> 8);
450		DISP_CMD_OUT(DISP_CMD_GSSET);
451		DISP_DATA_OUT(DISP_GS_2);
452	}
453}
454
455static int epsonQcif_disp_off(struct platform_device *pdev)
456{
457	if (!disp_initialized)
458		epsonQcif_disp_init(pdev);
459
460	if (display_on) {
461		DISP_CMD_OUT(DISP_CMD_DISOFF);
462		DISP_CMD_OUT(DISP_CMD_SLPIN);
463		display_on = FALSE;
464	}
465
466	return 0;
467}
468
469static int epsonQcif_disp_on(struct platform_device *pdev)
470{
471	if (!disp_initialized)
472		epsonQcif_disp_init(pdev);
473
474	if (!display_on) {
475		DISP_CMD_OUT(DISP_CMD_SLPOUT);
476		WAIT_SEC(40000);
477		DISP_CMD_OUT(DISP_CMD_DISON);
478		epsonQcif_disp_set_contrast(disp_contrast);
479		display_on = TRUE;
480	}
481
482	return 0;
483}
484
485static void epsonQcif_disp_set_contrast(word contrast)
486{
487	if (!disp_initialized)
488		return;
489
490	/* Initialize power IC, d'24 */
491	DISP_CMD_OUT(DISP_CMD_VOLCTL);
492	DISP_DATA_OUT(DISP_VOLCTL_TONE);
493
494	WAIT_SEC(40000);
495
496	/* Set electronic volume, d'xx */
497	DISP_CMD_OUT(DISP_CMD_VOLCTL);
498	if (contrast > 127)
499		contrast = 127;
500	DISP_DATA_OUT(contrast);	/* value from 0 to 127 */
501	disp_contrast = (byte) contrast;
502}				/* End disp_set_contrast */
503
504static void epsonQcif_disp_clear_screen_area(
505	word start_row, word end_row, word start_column, word end_column) {
506	int32 i;
507
508	/* Clear the display screen */
509	DISP_SET_RECT(start_row, end_row, start_column, end_column);
510	DISP_CMD_OUT(DISP_CMD_RAMWR);
511	i = (end_row - start_row + 1) * (end_column - start_column + 1);
512	for (; i > 0; i--)
513		DISP_DATA_OUT(0xffff);
514}
515
516static int __init epsonQcif_probe(struct platform_device *pdev)
517{
518	msm_fb_add_device(pdev);
519
520	return 0;
521}
522
523static struct platform_driver this_driver = {
524	.probe  = epsonQcif_probe,
525	.driver = {
526		.name   = "ebi2_epson_qcif",
527	},
528};
529
530static struct msm_fb_panel_data epsonQcif_panel_data = {
531	.on = epsonQcif_disp_on,
532	.off = epsonQcif_disp_off,
533	.set_rect = epsonQcif_disp_set_rect,
534};
535
536static struct platform_device this_device = {
537	.name   = "ebi2_epson_qcif",
538	.id	= 0,
539	.dev	= {
540		.platform_data = &epsonQcif_panel_data,
541	}
542};
543
544static int __init epsonQcif_init(void)
545{
546	int ret;
547	struct msm_panel_info *pinfo;
548
549	ret = platform_driver_register(&this_driver);
550	if (!ret) {
551		pinfo = &epsonQcif_panel_data.panel_info;
552		pinfo->xres = QCIF_WIDTH;
553		pinfo->yres = QCIF_HEIGHT;
554		pinfo->type = EBI2_PANEL;
555		pinfo->pdest = DISPLAY_2;
556		pinfo->wait_cycle = 0x808000;
557		pinfo->bpp = 16;
558		pinfo->fb_num = 2;
559		pinfo->lcd.vsync_enable = FALSE;
560
561		ret = platform_device_register(&this_device);
562		if (ret)
563			platform_driver_unregister(&this_driver);
564	}
565
566	return ret;
567}
568
569module_init(epsonQcif_init);
570