diff options
author | Heiko Stübner <heiko@sntech.de> | 2012-04-28 06:20:00 -0400 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2012-04-29 15:35:35 -0400 |
commit | 2c8304d3125b9c75797a35037945df63869bfdf6 (patch) | |
tree | 7785826daa53e6ae5f27d66e404eb2627e53b830 /drivers | |
parent | 1f45f9dbb392f9ca0919e9cd2370ab66ae752ec8 (diff) |
video: auo_k190x: add code shared by controller drivers
The AUO-K190X controllers share a very similar set of commands and
can therefore also share most of the driver code.
Signed-off-by: Heiko Stübner <heiko@sntech.de>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 17 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/auo_k190x.c | 1046 | ||||
-rw-r--r-- | drivers/video/auo_k190x.h | 129 |
4 files changed, 1193 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index edc2a22d289e..caf9eaa0fb93 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -2382,6 +2382,23 @@ config FB_BROADSHEET | |||
2382 | and could also have been called by other names when coupled with | 2382 | and could also have been called by other names when coupled with |
2383 | a bridge adapter. | 2383 | a bridge adapter. |
2384 | 2384 | ||
2385 | config FB_AUO_K190X | ||
2386 | tristate "AUO-K190X EPD controller support" | ||
2387 | depends on FB | ||
2388 | select FB_SYS_FILLRECT | ||
2389 | select FB_SYS_COPYAREA | ||
2390 | select FB_SYS_IMAGEBLIT | ||
2391 | select FB_SYS_FOPS | ||
2392 | select FB_DEFERRED_IO | ||
2393 | help | ||
2394 | Provides support for epaper controllers from the K190X series | ||
2395 | of AUO. These controllers can be used to drive epaper displays | ||
2396 | from Sipix. | ||
2397 | |||
2398 | This option enables the common support, shared by the individual | ||
2399 | controller drivers. You will also have to enable the driver | ||
2400 | for the controller type used in your device. | ||
2401 | |||
2385 | config FB_JZ4740 | 2402 | config FB_JZ4740 |
2386 | tristate "JZ4740 LCD framebuffer support" | 2403 | tristate "JZ4740 LCD framebuffer support" |
2387 | depends on FB && MACH_JZ4740 | 2404 | depends on FB && MACH_JZ4740 |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9356add945b3..d5406f2f2e5f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -118,6 +118,7 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o | |||
118 | obj-$(CONFIG_FB_MAXINE) += maxinefb.o | 118 | obj-$(CONFIG_FB_MAXINE) += maxinefb.o |
119 | obj-$(CONFIG_FB_METRONOME) += metronomefb.o | 119 | obj-$(CONFIG_FB_METRONOME) += metronomefb.o |
120 | obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o | 120 | obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o |
121 | obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o | ||
121 | obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o | 122 | obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o |
122 | obj-$(CONFIG_FB_SH7760) += sh7760fb.o | 123 | obj-$(CONFIG_FB_SH7760) += sh7760fb.o |
123 | obj-$(CONFIG_FB_IMX) += imxfb.o | 124 | obj-$(CONFIG_FB_IMX) += imxfb.o |
diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c new file mode 100644 index 000000000000..77da6a2f43dc --- /dev/null +++ b/drivers/video/auo_k190x.c | |||
@@ -0,0 +1,1046 @@ | |||
1 | /* | ||
2 | * Common code for AUO-K190X framebuffer drivers | ||
3 | * | ||
4 | * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/pm_runtime.h> | ||
15 | #include <linux/fb.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/uaccess.h> | ||
18 | #include <linux/vmalloc.h> | ||
19 | #include <linux/regulator/consumer.h> | ||
20 | |||
21 | #include <video/auo_k190xfb.h> | ||
22 | |||
23 | #include "auo_k190x.h" | ||
24 | |||
25 | struct panel_info { | ||
26 | int w; | ||
27 | int h; | ||
28 | }; | ||
29 | |||
30 | /* table of panel specific parameters to be indexed into by the board drivers */ | ||
31 | static struct panel_info panel_table[] = { | ||
32 | /* standard 6" */ | ||
33 | [AUOK190X_RESOLUTION_800_600] = { | ||
34 | .w = 800, | ||
35 | .h = 600, | ||
36 | }, | ||
37 | /* standard 9" */ | ||
38 | [AUOK190X_RESOLUTION_1024_768] = { | ||
39 | .w = 1024, | ||
40 | .h = 768, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * private I80 interface to the board driver | ||
46 | */ | ||
47 | |||
48 | static void auok190x_issue_data(struct auok190xfb_par *par, u16 data) | ||
49 | { | ||
50 | par->board->set_ctl(par, AUOK190X_I80_WR, 0); | ||
51 | par->board->set_hdb(par, data); | ||
52 | par->board->set_ctl(par, AUOK190X_I80_WR, 1); | ||
53 | } | ||
54 | |||
55 | static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data) | ||
56 | { | ||
57 | par->board->set_ctl(par, AUOK190X_I80_DC, 0); | ||
58 | auok190x_issue_data(par, data); | ||
59 | par->board->set_ctl(par, AUOK190X_I80_DC, 1); | ||
60 | } | ||
61 | |||
62 | static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, | ||
63 | u16 *data) | ||
64 | { | ||
65 | struct device *dev = par->info->device; | ||
66 | int i; | ||
67 | u16 tmp; | ||
68 | |||
69 | if (size & 3) { | ||
70 | dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n", | ||
71 | size); | ||
72 | return -EINVAL; | ||
73 | } | ||
74 | |||
75 | for (i = 0; i < (size >> 1); i++) { | ||
76 | par->board->set_ctl(par, AUOK190X_I80_WR, 0); | ||
77 | |||
78 | /* simple reduction of 8bit staticgray to 4bit gray | ||
79 | * combines 4 * 4bit pixel values into a 16bit value | ||
80 | */ | ||
81 | tmp = (data[2*i] & 0xF0) >> 4; | ||
82 | tmp |= (data[2*i] & 0xF000) >> 8; | ||
83 | tmp |= (data[2*i+1] & 0xF0) << 4; | ||
84 | tmp |= (data[2*i+1] & 0xF000); | ||
85 | |||
86 | par->board->set_hdb(par, tmp); | ||
87 | par->board->set_ctl(par, AUOK190X_I80_WR, 1); | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static u16 auok190x_read_data(struct auok190xfb_par *par) | ||
94 | { | ||
95 | u16 data; | ||
96 | |||
97 | par->board->set_ctl(par, AUOK190X_I80_OE, 0); | ||
98 | data = par->board->get_hdb(par); | ||
99 | par->board->set_ctl(par, AUOK190X_I80_OE, 1); | ||
100 | |||
101 | return data; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Command interface for the controller drivers | ||
106 | */ | ||
107 | |||
108 | void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data) | ||
109 | { | ||
110 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
111 | auok190x_issue_cmd(par, data); | ||
112 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
113 | } | ||
114 | EXPORT_SYMBOL_GPL(auok190x_send_command_nowait); | ||
115 | |||
116 | void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, | ||
117 | int argc, u16 *argv) | ||
118 | { | ||
119 | int i; | ||
120 | |||
121 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
122 | auok190x_issue_cmd(par, cmd); | ||
123 | |||
124 | for (i = 0; i < argc; i++) | ||
125 | auok190x_issue_data(par, argv[i]); | ||
126 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
127 | } | ||
128 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait); | ||
129 | |||
130 | int auok190x_send_command(struct auok190xfb_par *par, u16 data) | ||
131 | { | ||
132 | int ret; | ||
133 | |||
134 | ret = par->board->wait_for_rdy(par); | ||
135 | if (ret) | ||
136 | return ret; | ||
137 | |||
138 | auok190x_send_command_nowait(par, data); | ||
139 | return 0; | ||
140 | } | ||
141 | EXPORT_SYMBOL_GPL(auok190x_send_command); | ||
142 | |||
143 | int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
144 | int argc, u16 *argv) | ||
145 | { | ||
146 | int ret; | ||
147 | |||
148 | ret = par->board->wait_for_rdy(par); | ||
149 | if (ret) | ||
150 | return ret; | ||
151 | |||
152 | auok190x_send_cmdargs_nowait(par, cmd, argc, argv); | ||
153 | return 0; | ||
154 | } | ||
155 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs); | ||
156 | |||
157 | int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
158 | int argc, u16 *argv) | ||
159 | { | ||
160 | int i, ret; | ||
161 | |||
162 | ret = par->board->wait_for_rdy(par); | ||
163 | if (ret) | ||
164 | return ret; | ||
165 | |||
166 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
167 | auok190x_issue_cmd(par, cmd); | ||
168 | |||
169 | for (i = 0; i < argc; i++) | ||
170 | argv[i] = auok190x_read_data(par); | ||
171 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | EXPORT_SYMBOL_GPL(auok190x_read_cmdargs); | ||
176 | |||
177 | void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd, | ||
178 | int argc, u16 *argv, int size, u16 *data) | ||
179 | { | ||
180 | int i; | ||
181 | |||
182 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
183 | |||
184 | auok190x_issue_cmd(par, cmd); | ||
185 | |||
186 | for (i = 0; i < argc; i++) | ||
187 | auok190x_issue_data(par, argv[i]); | ||
188 | |||
189 | auok190x_issue_pixels(par, size, data); | ||
190 | |||
191 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
192 | } | ||
193 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait); | ||
194 | |||
195 | int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, | ||
196 | int argc, u16 *argv, int size, u16 *data) | ||
197 | { | ||
198 | int ret; | ||
199 | |||
200 | ret = par->board->wait_for_rdy(par); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | |||
204 | auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels); | ||
209 | |||
210 | /* | ||
211 | * fbdefio callbacks - common on both controllers. | ||
212 | */ | ||
213 | |||
214 | static void auok190xfb_dpy_first_io(struct fb_info *info) | ||
215 | { | ||
216 | /* tell runtime-pm that we wish to use the device in a short time */ | ||
217 | pm_runtime_get(info->device); | ||
218 | } | ||
219 | |||
220 | /* this is called back from the deferred io workqueue */ | ||
221 | static void auok190xfb_dpy_deferred_io(struct fb_info *info, | ||
222 | struct list_head *pagelist) | ||
223 | { | ||
224 | struct fb_deferred_io *fbdefio = info->fbdefio; | ||
225 | struct auok190xfb_par *par = info->par; | ||
226 | u16 yres = info->var.yres; | ||
227 | u16 xres = info->var.xres; | ||
228 | u16 y1 = 0, h = 0; | ||
229 | int prev_index = -1; | ||
230 | struct page *cur; | ||
231 | int h_inc; | ||
232 | int threshold; | ||
233 | |||
234 | if (!list_empty(pagelist)) | ||
235 | /* the device resume should've been requested through first_io, | ||
236 | * if the resume did not finish until now, wait for it. | ||
237 | */ | ||
238 | pm_runtime_barrier(info->device); | ||
239 | else | ||
240 | /* We reached this via the fsync or some other way. | ||
241 | * In either case the first_io function did not run, | ||
242 | * so we runtime_resume the device here synchronously. | ||
243 | */ | ||
244 | pm_runtime_get_sync(info->device); | ||
245 | |||
246 | /* Do a full screen update every n updates to prevent | ||
247 | * excessive darkening of the Sipix display. | ||
248 | * If we do this, there is no need to walk the pages. | ||
249 | */ | ||
250 | if (par->need_refresh(par)) { | ||
251 | par->update_all(par); | ||
252 | goto out; | ||
253 | } | ||
254 | |||
255 | /* height increment is fixed per page */ | ||
256 | h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); | ||
257 | |||
258 | /* calculate number of pages from pixel height */ | ||
259 | threshold = par->consecutive_threshold / h_inc; | ||
260 | if (threshold < 1) | ||
261 | threshold = 1; | ||
262 | |||
263 | /* walk the written page list and swizzle the data */ | ||
264 | list_for_each_entry(cur, &fbdefio->pagelist, lru) { | ||
265 | if (prev_index < 0) { | ||
266 | /* just starting so assign first page */ | ||
267 | y1 = (cur->index << PAGE_SHIFT) / xres; | ||
268 | h = h_inc; | ||
269 | } else if ((cur->index - prev_index) <= threshold) { | ||
270 | /* page is within our threshold for single updates */ | ||
271 | h += h_inc * (cur->index - prev_index); | ||
272 | } else { | ||
273 | /* page not consecutive, issue previous update first */ | ||
274 | par->update_partial(par, y1, y1 + h); | ||
275 | |||
276 | /* start over with our non consecutive page */ | ||
277 | y1 = (cur->index << PAGE_SHIFT) / xres; | ||
278 | h = h_inc; | ||
279 | } | ||
280 | prev_index = cur->index; | ||
281 | } | ||
282 | |||
283 | /* if we still have any pages to update we do so now */ | ||
284 | if (h >= yres) | ||
285 | /* its a full screen update, just do it */ | ||
286 | par->update_all(par); | ||
287 | else | ||
288 | par->update_partial(par, y1, min((u16) (y1 + h), yres)); | ||
289 | |||
290 | out: | ||
291 | pm_runtime_mark_last_busy(info->device); | ||
292 | pm_runtime_put_autosuspend(info->device); | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * framebuffer operations | ||
297 | */ | ||
298 | |||
299 | /* | ||
300 | * this is the slow path from userspace. they can seek and write to | ||
301 | * the fb. it's inefficient to do anything less than a full screen draw | ||
302 | */ | ||
303 | static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf, | ||
304 | size_t count, loff_t *ppos) | ||
305 | { | ||
306 | struct auok190xfb_par *par = info->par; | ||
307 | unsigned long p = *ppos; | ||
308 | void *dst; | ||
309 | int err = 0; | ||
310 | unsigned long total_size; | ||
311 | |||
312 | if (info->state != FBINFO_STATE_RUNNING) | ||
313 | return -EPERM; | ||
314 | |||
315 | total_size = info->fix.smem_len; | ||
316 | |||
317 | if (p > total_size) | ||
318 | return -EFBIG; | ||
319 | |||
320 | if (count > total_size) { | ||
321 | err = -EFBIG; | ||
322 | count = total_size; | ||
323 | } | ||
324 | |||
325 | if (count + p > total_size) { | ||
326 | if (!err) | ||
327 | err = -ENOSPC; | ||
328 | |||
329 | count = total_size - p; | ||
330 | } | ||
331 | |||
332 | dst = (void *)(info->screen_base + p); | ||
333 | |||
334 | if (copy_from_user(dst, buf, count)) | ||
335 | err = -EFAULT; | ||
336 | |||
337 | if (!err) | ||
338 | *ppos += count; | ||
339 | |||
340 | par->update_all(par); | ||
341 | |||
342 | return (err) ? err : count; | ||
343 | } | ||
344 | |||
345 | static void auok190xfb_fillrect(struct fb_info *info, | ||
346 | const struct fb_fillrect *rect) | ||
347 | { | ||
348 | struct auok190xfb_par *par = info->par; | ||
349 | |||
350 | sys_fillrect(info, rect); | ||
351 | |||
352 | par->update_all(par); | ||
353 | } | ||
354 | |||
355 | static void auok190xfb_copyarea(struct fb_info *info, | ||
356 | const struct fb_copyarea *area) | ||
357 | { | ||
358 | struct auok190xfb_par *par = info->par; | ||
359 | |||
360 | sys_copyarea(info, area); | ||
361 | |||
362 | par->update_all(par); | ||
363 | } | ||
364 | |||
365 | static void auok190xfb_imageblit(struct fb_info *info, | ||
366 | const struct fb_image *image) | ||
367 | { | ||
368 | struct auok190xfb_par *par = info->par; | ||
369 | |||
370 | sys_imageblit(info, image); | ||
371 | |||
372 | par->update_all(par); | ||
373 | } | ||
374 | |||
375 | static int auok190xfb_check_var(struct fb_var_screeninfo *var, | ||
376 | struct fb_info *info) | ||
377 | { | ||
378 | if (info->var.xres != var->xres || info->var.yres != var->yres || | ||
379 | info->var.xres_virtual != var->xres_virtual || | ||
380 | info->var.yres_virtual != var->yres_virtual) { | ||
381 | pr_info("%s: Resolution not supported: X%u x Y%u\n", | ||
382 | __func__, var->xres, var->yres); | ||
383 | return -EINVAL; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * Memory limit | ||
388 | */ | ||
389 | |||
390 | if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { | ||
391 | pr_info("%s: Memory Limit requested yres_virtual = %u\n", | ||
392 | __func__, var->yres_virtual); | ||
393 | return -ENOMEM; | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static struct fb_ops auok190xfb_ops = { | ||
400 | .owner = THIS_MODULE, | ||
401 | .fb_read = fb_sys_read, | ||
402 | .fb_write = auok190xfb_write, | ||
403 | .fb_fillrect = auok190xfb_fillrect, | ||
404 | .fb_copyarea = auok190xfb_copyarea, | ||
405 | .fb_imageblit = auok190xfb_imageblit, | ||
406 | .fb_check_var = auok190xfb_check_var, | ||
407 | }; | ||
408 | |||
409 | /* | ||
410 | * Controller-functions common to both K1900 and K1901 | ||
411 | */ | ||
412 | |||
413 | static int auok190x_read_temperature(struct auok190xfb_par *par) | ||
414 | { | ||
415 | struct device *dev = par->info->device; | ||
416 | u16 data[4]; | ||
417 | int temp; | ||
418 | |||
419 | pm_runtime_get_sync(dev); | ||
420 | |||
421 | mutex_lock(&(par->io_lock)); | ||
422 | |||
423 | auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); | ||
424 | |||
425 | mutex_unlock(&(par->io_lock)); | ||
426 | |||
427 | pm_runtime_mark_last_busy(dev); | ||
428 | pm_runtime_put_autosuspend(dev); | ||
429 | |||
430 | /* sanitize and split of half-degrees for now */ | ||
431 | temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1); | ||
432 | |||
433 | /* handle positive and negative temperatures */ | ||
434 | if (temp >= 201) | ||
435 | return (255 - temp + 1) * (-1); | ||
436 | else | ||
437 | return temp; | ||
438 | } | ||
439 | |||
440 | static void auok190x_identify(struct auok190xfb_par *par) | ||
441 | { | ||
442 | struct device *dev = par->info->device; | ||
443 | u16 data[4]; | ||
444 | |||
445 | pm_runtime_get_sync(dev); | ||
446 | |||
447 | mutex_lock(&(par->io_lock)); | ||
448 | |||
449 | auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); | ||
450 | |||
451 | mutex_unlock(&(par->io_lock)); | ||
452 | |||
453 | par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK; | ||
454 | |||
455 | par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]); | ||
456 | par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]); | ||
457 | par->panel_model = AUOK190X_VERSION_MODEL(data[2]); | ||
458 | |||
459 | par->tcon_version = AUOK190X_VERSION_TCON(data[3]); | ||
460 | par->lut_version = AUOK190X_VERSION_LUT(data[3]); | ||
461 | |||
462 | dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x", | ||
463 | par->panel_size_int, par->panel_size_float, par->panel_model, | ||
464 | par->epd_type, par->tcon_version, par->lut_version); | ||
465 | |||
466 | pm_runtime_mark_last_busy(dev); | ||
467 | pm_runtime_put_autosuspend(dev); | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * Sysfs functions | ||
472 | */ | ||
473 | |||
474 | static ssize_t update_mode_show(struct device *dev, | ||
475 | struct device_attribute *attr, char *buf) | ||
476 | { | ||
477 | struct fb_info *info = dev_get_drvdata(dev); | ||
478 | struct auok190xfb_par *par = info->par; | ||
479 | |||
480 | return sprintf(buf, "%d\n", par->update_mode); | ||
481 | } | ||
482 | |||
483 | static ssize_t update_mode_store(struct device *dev, | ||
484 | struct device_attribute *attr, | ||
485 | const char *buf, size_t count) | ||
486 | { | ||
487 | struct fb_info *info = dev_get_drvdata(dev); | ||
488 | struct auok190xfb_par *par = info->par; | ||
489 | int mode, ret; | ||
490 | |||
491 | ret = kstrtoint(buf, 10, &mode); | ||
492 | if (ret) | ||
493 | return ret; | ||
494 | |||
495 | par->update_mode = mode; | ||
496 | |||
497 | /* if we enter a better mode, do a full update */ | ||
498 | if (par->last_mode > 1 && mode < par->last_mode) | ||
499 | par->update_all(par); | ||
500 | |||
501 | return count; | ||
502 | } | ||
503 | |||
504 | static ssize_t flash_show(struct device *dev, struct device_attribute *attr, | ||
505 | char *buf) | ||
506 | { | ||
507 | struct fb_info *info = dev_get_drvdata(dev); | ||
508 | struct auok190xfb_par *par = info->par; | ||
509 | |||
510 | return sprintf(buf, "%d\n", par->flash); | ||
511 | } | ||
512 | |||
513 | static ssize_t flash_store(struct device *dev, struct device_attribute *attr, | ||
514 | const char *buf, size_t count) | ||
515 | { | ||
516 | struct fb_info *info = dev_get_drvdata(dev); | ||
517 | struct auok190xfb_par *par = info->par; | ||
518 | int flash, ret; | ||
519 | |||
520 | ret = kstrtoint(buf, 10, &flash); | ||
521 | if (ret) | ||
522 | return ret; | ||
523 | |||
524 | if (flash > 0) | ||
525 | par->flash = 1; | ||
526 | else | ||
527 | par->flash = 0; | ||
528 | |||
529 | return count; | ||
530 | } | ||
531 | |||
532 | static ssize_t temp_show(struct device *dev, struct device_attribute *attr, | ||
533 | char *buf) | ||
534 | { | ||
535 | struct fb_info *info = dev_get_drvdata(dev); | ||
536 | struct auok190xfb_par *par = info->par; | ||
537 | int temp; | ||
538 | |||
539 | temp = auok190x_read_temperature(par); | ||
540 | return sprintf(buf, "%d\n", temp); | ||
541 | } | ||
542 | |||
543 | static DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store); | ||
544 | static DEVICE_ATTR(flash, 0644, flash_show, flash_store); | ||
545 | static DEVICE_ATTR(temp, 0644, temp_show, NULL); | ||
546 | |||
547 | static struct attribute *auok190x_attributes[] = { | ||
548 | &dev_attr_update_mode.attr, | ||
549 | &dev_attr_flash.attr, | ||
550 | &dev_attr_temp.attr, | ||
551 | NULL | ||
552 | }; | ||
553 | |||
554 | static const struct attribute_group auok190x_attr_group = { | ||
555 | .attrs = auok190x_attributes, | ||
556 | }; | ||
557 | |||
558 | static int auok190x_power(struct auok190xfb_par *par, bool on) | ||
559 | { | ||
560 | struct auok190x_board *board = par->board; | ||
561 | int ret; | ||
562 | |||
563 | if (on) { | ||
564 | /* We should maintain POWER up for at least 80ms before set | ||
565 | * RST_N and SLP_N to high (TCON spec 20100803_v35 p59) | ||
566 | */ | ||
567 | ret = regulator_enable(par->regulator); | ||
568 | if (ret) | ||
569 | return ret; | ||
570 | |||
571 | msleep(200); | ||
572 | gpio_set_value(board->gpio_nrst, 1); | ||
573 | gpio_set_value(board->gpio_nsleep, 1); | ||
574 | msleep(200); | ||
575 | } else { | ||
576 | regulator_disable(par->regulator); | ||
577 | gpio_set_value(board->gpio_nrst, 0); | ||
578 | gpio_set_value(board->gpio_nsleep, 0); | ||
579 | } | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | /* | ||
585 | * Recovery - powercycle the controller | ||
586 | */ | ||
587 | |||
588 | static void auok190x_recover(struct auok190xfb_par *par) | ||
589 | { | ||
590 | auok190x_power(par, 0); | ||
591 | msleep(100); | ||
592 | auok190x_power(par, 1); | ||
593 | |||
594 | par->init(par); | ||
595 | |||
596 | /* wait for init to complete */ | ||
597 | par->board->wait_for_rdy(par); | ||
598 | } | ||
599 | |||
600 | /* | ||
601 | * Power-management | ||
602 | */ | ||
603 | |||
604 | #ifdef CONFIG_PM | ||
605 | static int auok190x_runtime_suspend(struct device *dev) | ||
606 | { | ||
607 | struct platform_device *pdev = to_platform_device(dev); | ||
608 | struct fb_info *info = platform_get_drvdata(pdev); | ||
609 | struct auok190xfb_par *par = info->par; | ||
610 | struct auok190x_board *board = par->board; | ||
611 | u16 standby_param; | ||
612 | |||
613 | /* take and keep the lock until we are resumed, as the controller | ||
614 | * will never reach the non-busy state when in standby mode | ||
615 | */ | ||
616 | mutex_lock(&(par->io_lock)); | ||
617 | |||
618 | if (par->standby) { | ||
619 | dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n"); | ||
620 | mutex_unlock(&(par->io_lock)); | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | /* according to runtime_pm.txt runtime_suspend only means, that the | ||
625 | * device will not process data and will not communicate with the CPU | ||
626 | * As we hold the lock, this stays true even without standby | ||
627 | */ | ||
628 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
629 | dev_dbg(dev, "runtime suspend without standby\n"); | ||
630 | goto finish; | ||
631 | } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) { | ||
632 | /* for some TCON versions STANDBY expects a parameter (0) but | ||
633 | * it seems the real tcon version has to be determined yet. | ||
634 | */ | ||
635 | dev_dbg(dev, "runtime suspend with additional empty param\n"); | ||
636 | standby_param = 0; | ||
637 | auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1, | ||
638 | &standby_param); | ||
639 | } else { | ||
640 | dev_dbg(dev, "runtime suspend without param\n"); | ||
641 | auok190x_send_command(par, AUOK190X_CMD_STANDBY); | ||
642 | } | ||
643 | |||
644 | msleep(64); | ||
645 | |||
646 | finish: | ||
647 | par->standby = 1; | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int auok190x_runtime_resume(struct device *dev) | ||
653 | { | ||
654 | struct platform_device *pdev = to_platform_device(dev); | ||
655 | struct fb_info *info = platform_get_drvdata(pdev); | ||
656 | struct auok190xfb_par *par = info->par; | ||
657 | struct auok190x_board *board = par->board; | ||
658 | |||
659 | if (!par->standby) { | ||
660 | dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n"); | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
665 | dev_dbg(dev, "runtime resume without standby\n"); | ||
666 | } else { | ||
667 | /* when in standby, controller is always busy | ||
668 | * and only accepts the wakeup command | ||
669 | */ | ||
670 | dev_dbg(dev, "runtime resume from standby\n"); | ||
671 | auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP); | ||
672 | |||
673 | msleep(160); | ||
674 | |||
675 | /* wait for the controller to be ready and release the lock */ | ||
676 | board->wait_for_rdy(par); | ||
677 | } | ||
678 | |||
679 | par->standby = 0; | ||
680 | |||
681 | mutex_unlock(&(par->io_lock)); | ||
682 | |||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static int auok190x_suspend(struct device *dev) | ||
687 | { | ||
688 | struct platform_device *pdev = to_platform_device(dev); | ||
689 | struct fb_info *info = platform_get_drvdata(pdev); | ||
690 | struct auok190xfb_par *par = info->par; | ||
691 | struct auok190x_board *board = par->board; | ||
692 | int ret; | ||
693 | |||
694 | dev_dbg(dev, "suspend\n"); | ||
695 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
696 | /* suspend via powering off the ic */ | ||
697 | dev_dbg(dev, "suspend with broken standby\n"); | ||
698 | |||
699 | auok190x_power(par, 0); | ||
700 | } else { | ||
701 | dev_dbg(dev, "suspend using sleep\n"); | ||
702 | |||
703 | /* the sleep state can only be entered from the standby state. | ||
704 | * pm_runtime_get_noresume gets called before the suspend call. | ||
705 | * So the devices usage count is >0 but it is not necessarily | ||
706 | * active. | ||
707 | */ | ||
708 | if (!pm_runtime_status_suspended(dev)) { | ||
709 | ret = auok190x_runtime_suspend(dev); | ||
710 | if (ret < 0) { | ||
711 | dev_err(dev, "auok190x_runtime_suspend failed with %d\n", | ||
712 | ret); | ||
713 | return ret; | ||
714 | } | ||
715 | par->manual_standby = 1; | ||
716 | } | ||
717 | |||
718 | gpio_direction_output(board->gpio_nsleep, 0); | ||
719 | } | ||
720 | |||
721 | msleep(100); | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static int auok190x_resume(struct device *dev) | ||
727 | { | ||
728 | struct platform_device *pdev = to_platform_device(dev); | ||
729 | struct fb_info *info = platform_get_drvdata(pdev); | ||
730 | struct auok190xfb_par *par = info->par; | ||
731 | struct auok190x_board *board = par->board; | ||
732 | |||
733 | dev_dbg(dev, "resume\n"); | ||
734 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
735 | dev_dbg(dev, "resume with broken standby\n"); | ||
736 | |||
737 | auok190x_power(par, 1); | ||
738 | |||
739 | par->init(par); | ||
740 | } else { | ||
741 | dev_dbg(dev, "resume from sleep\n"); | ||
742 | |||
743 | /* device should be in runtime suspend when we were suspended | ||
744 | * and pm_runtime_put_sync gets called after this function. | ||
745 | * So there is no need to touch the standby mode here at all. | ||
746 | */ | ||
747 | gpio_direction_output(board->gpio_nsleep, 1); | ||
748 | msleep(100); | ||
749 | |||
750 | /* an additional init call seems to be necessary after sleep */ | ||
751 | auok190x_runtime_resume(dev); | ||
752 | par->init(par); | ||
753 | |||
754 | /* if we were runtime-suspended before, suspend again*/ | ||
755 | if (!par->manual_standby) | ||
756 | auok190x_runtime_suspend(dev); | ||
757 | else | ||
758 | par->manual_standby = 0; | ||
759 | } | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | #endif | ||
764 | |||
765 | const struct dev_pm_ops auok190x_pm = { | ||
766 | SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume, | ||
767 | NULL) | ||
768 | SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume) | ||
769 | }; | ||
770 | EXPORT_SYMBOL_GPL(auok190x_pm); | ||
771 | |||
772 | /* | ||
773 | * Common probe and remove code | ||
774 | */ | ||
775 | |||
776 | int __devinit auok190x_common_probe(struct platform_device *pdev, | ||
777 | struct auok190x_init_data *init) | ||
778 | { | ||
779 | struct auok190x_board *board = init->board; | ||
780 | struct auok190xfb_par *par; | ||
781 | struct fb_info *info; | ||
782 | struct panel_info *panel; | ||
783 | int videomemorysize, ret; | ||
784 | unsigned char *videomemory; | ||
785 | |||
786 | /* check board contents */ | ||
787 | if (!board->init || !board->cleanup || !board->wait_for_rdy | ||
788 | || !board->set_ctl || !board->set_hdb || !board->get_hdb | ||
789 | || !board->setup_irq) | ||
790 | return -EINVAL; | ||
791 | |||
792 | info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev); | ||
793 | if (!info) | ||
794 | return -ENOMEM; | ||
795 | |||
796 | par = info->par; | ||
797 | par->info = info; | ||
798 | par->board = board; | ||
799 | par->recover = auok190x_recover; | ||
800 | par->update_partial = init->update_partial; | ||
801 | par->update_all = init->update_all; | ||
802 | par->need_refresh = init->need_refresh; | ||
803 | par->init = init->init; | ||
804 | |||
805 | /* init update modes */ | ||
806 | par->update_cnt = 0; | ||
807 | par->update_mode = -1; | ||
808 | par->last_mode = -1; | ||
809 | par->flash = 0; | ||
810 | |||
811 | par->regulator = regulator_get(info->device, "vdd"); | ||
812 | if (IS_ERR(par->regulator)) { | ||
813 | ret = PTR_ERR(par->regulator); | ||
814 | dev_err(info->device, "Failed to get regulator: %d\n", ret); | ||
815 | goto err_reg; | ||
816 | } | ||
817 | |||
818 | ret = board->init(par); | ||
819 | if (ret) { | ||
820 | dev_err(info->device, "board init failed, %d\n", ret); | ||
821 | goto err_board; | ||
822 | } | ||
823 | |||
824 | ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep"); | ||
825 | if (ret) { | ||
826 | dev_err(info->device, "could not request sleep gpio, %d\n", | ||
827 | ret); | ||
828 | goto err_gpio1; | ||
829 | } | ||
830 | |||
831 | ret = gpio_direction_output(board->gpio_nsleep, 0); | ||
832 | if (ret) { | ||
833 | dev_err(info->device, "could not set sleep gpio, %d\n", ret); | ||
834 | goto err_gpio2; | ||
835 | } | ||
836 | |||
837 | ret = gpio_request(board->gpio_nrst, "AUOK190x reset"); | ||
838 | if (ret) { | ||
839 | dev_err(info->device, "could not request reset gpio, %d\n", | ||
840 | ret); | ||
841 | goto err_gpio2; | ||
842 | } | ||
843 | |||
844 | ret = gpio_direction_output(board->gpio_nrst, 0); | ||
845 | if (ret) { | ||
846 | dev_err(info->device, "could not set reset gpio, %d\n", ret); | ||
847 | goto err_gpio3; | ||
848 | } | ||
849 | |||
850 | ret = auok190x_power(par, 1); | ||
851 | if (ret) { | ||
852 | dev_err(info->device, "could not power on the device, %d\n", | ||
853 | ret); | ||
854 | goto err_gpio3; | ||
855 | } | ||
856 | |||
857 | mutex_init(&par->io_lock); | ||
858 | |||
859 | init_waitqueue_head(&par->waitq); | ||
860 | |||
861 | ret = par->board->setup_irq(par->info); | ||
862 | if (ret) { | ||
863 | dev_err(info->device, "could not setup ready-irq, %d\n", ret); | ||
864 | goto err_irq; | ||
865 | } | ||
866 | |||
867 | /* wait for init to complete */ | ||
868 | par->board->wait_for_rdy(par); | ||
869 | |||
870 | /* | ||
871 | * From here on the controller can talk to us | ||
872 | */ | ||
873 | |||
874 | /* initialise fix, var, resolution and rotation */ | ||
875 | |||
876 | strlcpy(info->fix.id, init->id, 16); | ||
877 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
878 | info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; | ||
879 | info->fix.xpanstep = 0; | ||
880 | info->fix.ypanstep = 0; | ||
881 | info->fix.ywrapstep = 0; | ||
882 | info->fix.accel = FB_ACCEL_NONE; | ||
883 | |||
884 | info->var.bits_per_pixel = 8; | ||
885 | info->var.grayscale = 1; | ||
886 | info->var.red.length = 8; | ||
887 | info->var.green.length = 8; | ||
888 | info->var.blue.length = 8; | ||
889 | |||
890 | panel = &panel_table[board->resolution]; | ||
891 | |||
892 | /* if 90 degree rotation, switch width and height */ | ||
893 | if (board->rotation & 1) { | ||
894 | info->var.xres = panel->h; | ||
895 | info->var.yres = panel->w; | ||
896 | info->var.xres_virtual = panel->h; | ||
897 | info->var.yres_virtual = panel->w; | ||
898 | info->fix.line_length = panel->h; | ||
899 | } else { | ||
900 | info->var.xres = panel->w; | ||
901 | info->var.yres = panel->h; | ||
902 | info->var.xres_virtual = panel->w; | ||
903 | info->var.yres_virtual = panel->h; | ||
904 | info->fix.line_length = panel->w; | ||
905 | } | ||
906 | |||
907 | par->resolution = board->resolution; | ||
908 | par->rotation = board->rotation; | ||
909 | |||
910 | /* videomemory handling */ | ||
911 | |||
912 | videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE); | ||
913 | videomemory = vmalloc(videomemorysize); | ||
914 | if (!videomemory) { | ||
915 | ret = -ENOMEM; | ||
916 | goto err_irq; | ||
917 | } | ||
918 | |||
919 | memset(videomemory, 0, videomemorysize); | ||
920 | info->screen_base = (char *)videomemory; | ||
921 | info->fix.smem_len = videomemorysize; | ||
922 | |||
923 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; | ||
924 | info->fbops = &auok190xfb_ops; | ||
925 | |||
926 | /* deferred io init */ | ||
927 | |||
928 | info->fbdefio = devm_kzalloc(info->device, | ||
929 | sizeof(struct fb_deferred_io), | ||
930 | GFP_KERNEL); | ||
931 | if (!info->fbdefio) { | ||
932 | dev_err(info->device, "Failed to allocate memory\n"); | ||
933 | ret = -ENOMEM; | ||
934 | goto err_defio; | ||
935 | } | ||
936 | |||
937 | dev_dbg(info->device, "targetting %d frames per second\n", board->fps); | ||
938 | info->fbdefio->delay = HZ / board->fps; | ||
939 | info->fbdefio->first_io = auok190xfb_dpy_first_io, | ||
940 | info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io, | ||
941 | fb_deferred_io_init(info); | ||
942 | |||
943 | /* color map */ | ||
944 | |||
945 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
946 | if (ret < 0) { | ||
947 | dev_err(info->device, "Failed to allocate colormap\n"); | ||
948 | goto err_cmap; | ||
949 | } | ||
950 | |||
951 | /* controller init */ | ||
952 | |||
953 | par->consecutive_threshold = 100; | ||
954 | par->init(par); | ||
955 | auok190x_identify(par); | ||
956 | |||
957 | platform_set_drvdata(pdev, info); | ||
958 | |||
959 | ret = register_framebuffer(info); | ||
960 | if (ret < 0) | ||
961 | goto err_regfb; | ||
962 | |||
963 | ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group); | ||
964 | if (ret) | ||
965 | goto err_sysfs; | ||
966 | |||
967 | dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n", | ||
968 | info->node, info->var.xres, info->var.yres, | ||
969 | videomemorysize >> 10); | ||
970 | |||
971 | /* increase autosuspend_delay when we use alternative methods | ||
972 | * for runtime_pm | ||
973 | */ | ||
974 | par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) | ||
975 | ? 1000 : 200; | ||
976 | |||
977 | pm_runtime_set_active(info->device); | ||
978 | pm_runtime_enable(info->device); | ||
979 | pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay); | ||
980 | pm_runtime_use_autosuspend(info->device); | ||
981 | |||
982 | return 0; | ||
983 | |||
984 | err_sysfs: | ||
985 | unregister_framebuffer(info); | ||
986 | err_regfb: | ||
987 | fb_dealloc_cmap(&info->cmap); | ||
988 | err_cmap: | ||
989 | fb_deferred_io_cleanup(info); | ||
990 | kfree(info->fbdefio); | ||
991 | err_defio: | ||
992 | vfree((void *)info->screen_base); | ||
993 | err_irq: | ||
994 | auok190x_power(par, 0); | ||
995 | err_gpio3: | ||
996 | gpio_free(board->gpio_nrst); | ||
997 | err_gpio2: | ||
998 | gpio_free(board->gpio_nsleep); | ||
999 | err_gpio1: | ||
1000 | board->cleanup(par); | ||
1001 | err_board: | ||
1002 | regulator_put(par->regulator); | ||
1003 | err_reg: | ||
1004 | framebuffer_release(info); | ||
1005 | |||
1006 | return ret; | ||
1007 | } | ||
1008 | EXPORT_SYMBOL_GPL(auok190x_common_probe); | ||
1009 | |||
1010 | int __devexit auok190x_common_remove(struct platform_device *pdev) | ||
1011 | { | ||
1012 | struct fb_info *info = platform_get_drvdata(pdev); | ||
1013 | struct auok190xfb_par *par = info->par; | ||
1014 | struct auok190x_board *board = par->board; | ||
1015 | |||
1016 | pm_runtime_disable(info->device); | ||
1017 | |||
1018 | sysfs_remove_group(&info->device->kobj, &auok190x_attr_group); | ||
1019 | |||
1020 | unregister_framebuffer(info); | ||
1021 | |||
1022 | fb_dealloc_cmap(&info->cmap); | ||
1023 | |||
1024 | fb_deferred_io_cleanup(info); | ||
1025 | kfree(info->fbdefio); | ||
1026 | |||
1027 | vfree((void *)info->screen_base); | ||
1028 | |||
1029 | auok190x_power(par, 0); | ||
1030 | |||
1031 | gpio_free(board->gpio_nrst); | ||
1032 | gpio_free(board->gpio_nsleep); | ||
1033 | |||
1034 | board->cleanup(par); | ||
1035 | |||
1036 | regulator_put(par->regulator); | ||
1037 | |||
1038 | framebuffer_release(info); | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | EXPORT_SYMBOL_GPL(auok190x_common_remove); | ||
1043 | |||
1044 | MODULE_DESCRIPTION("Common code for AUO-K190X controllers"); | ||
1045 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); | ||
1046 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/auo_k190x.h b/drivers/video/auo_k190x.h new file mode 100644 index 000000000000..e35af1f51b28 --- /dev/null +++ b/drivers/video/auo_k190x.h | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * Private common definitions for AUO-K190X framebuffer drivers | ||
3 | * | ||
4 | * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * I80 interface specific defines | ||
13 | */ | ||
14 | |||
15 | #define AUOK190X_I80_CS 0x01 | ||
16 | #define AUOK190X_I80_DC 0x02 | ||
17 | #define AUOK190X_I80_WR 0x03 | ||
18 | #define AUOK190X_I80_OE 0x04 | ||
19 | |||
20 | /* | ||
21 | * AUOK190x commands, common to both controllers | ||
22 | */ | ||
23 | |||
24 | #define AUOK190X_CMD_INIT 0x0000 | ||
25 | #define AUOK190X_CMD_STANDBY 0x0001 | ||
26 | #define AUOK190X_CMD_WAKEUP 0x0002 | ||
27 | #define AUOK190X_CMD_TCON_RESET 0x0003 | ||
28 | #define AUOK190X_CMD_DATA_STOP 0x1002 | ||
29 | #define AUOK190X_CMD_LUT_START 0x1003 | ||
30 | #define AUOK190X_CMD_DISP_REFRESH 0x1004 | ||
31 | #define AUOK190X_CMD_DISP_RESET 0x1005 | ||
32 | #define AUOK190X_CMD_PRE_DISPLAY_START 0x100D | ||
33 | #define AUOK190X_CMD_PRE_DISPLAY_STOP 0x100F | ||
34 | #define AUOK190X_CMD_FLASH_W 0x2000 | ||
35 | #define AUOK190X_CMD_FLASH_E 0x2001 | ||
36 | #define AUOK190X_CMD_FLASH_STS 0x2002 | ||
37 | #define AUOK190X_CMD_FRAMERATE 0x3000 | ||
38 | #define AUOK190X_CMD_READ_VERSION 0x4000 | ||
39 | #define AUOK190X_CMD_READ_STATUS 0x4001 | ||
40 | #define AUOK190X_CMD_READ_LUT 0x4003 | ||
41 | #define AUOK190X_CMD_DRIVERTIMING 0x5000 | ||
42 | #define AUOK190X_CMD_LBALANCE 0x5001 | ||
43 | #define AUOK190X_CMD_AGINGMODE 0x6000 | ||
44 | #define AUOK190X_CMD_AGINGEXIT 0x6001 | ||
45 | |||
46 | /* | ||
47 | * Common settings for AUOK190X_CMD_INIT | ||
48 | */ | ||
49 | |||
50 | #define AUOK190X_INIT_DATA_FILTER (0 << 12) | ||
51 | #define AUOK190X_INIT_DATA_BYPASS (1 << 12) | ||
52 | #define AUOK190X_INIT_INVERSE_WHITE (0 << 9) | ||
53 | #define AUOK190X_INIT_INVERSE_BLACK (1 << 9) | ||
54 | #define AUOK190X_INIT_SCAN_DOWN (0 << 1) | ||
55 | #define AUOK190X_INIT_SCAN_UP (1 << 1) | ||
56 | #define AUOK190X_INIT_SHIFT_LEFT (0 << 0) | ||
57 | #define AUOK190X_INIT_SHIFT_RIGHT (1 << 0) | ||
58 | |||
59 | /* Common bits to pixels | ||
60 | * Mode 15-12 11-8 7-4 3-0 | ||
61 | * format0 4 3 2 1 | ||
62 | * format1 3 4 1 2 | ||
63 | */ | ||
64 | |||
65 | #define AUOK190X_INIT_FORMAT0 0 | ||
66 | #define AUOK190X_INIT_FORMAT1 (1 << 6) | ||
67 | |||
68 | /* | ||
69 | * settings for AUOK190X_CMD_RESET | ||
70 | */ | ||
71 | |||
72 | #define AUOK190X_RESET_TCON (0 << 0) | ||
73 | #define AUOK190X_RESET_NORMAL (1 << 0) | ||
74 | #define AUOK190X_RESET_PON (1 << 1) | ||
75 | |||
76 | /* | ||
77 | * AUOK190X_CMD_VERSION | ||
78 | */ | ||
79 | |||
80 | #define AUOK190X_VERSION_TEMP_MASK (0x1ff) | ||
81 | #define AUOK190X_VERSION_EPD_MASK (0xff) | ||
82 | #define AUOK190X_VERSION_SIZE_INT(_val) ((_val & 0xfc00) >> 10) | ||
83 | #define AUOK190X_VERSION_SIZE_FLOAT(_val) ((_val & 0x3c0) >> 6) | ||
84 | #define AUOK190X_VERSION_MODEL(_val) (_val & 0x3f) | ||
85 | #define AUOK190X_VERSION_LUT(_val) (_val & 0xff) | ||
86 | #define AUOK190X_VERSION_TCON(_val) ((_val & 0xff00) >> 8) | ||
87 | |||
88 | /* | ||
89 | * update modes for CMD_PARTIALDISP on K1900 and CMD_DDMA on K1901 | ||
90 | */ | ||
91 | |||
92 | #define AUOK190X_UPDATE_MODE(_res) ((_res & 0x7) << 12) | ||
93 | #define AUOK190X_UPDATE_NONFLASH (1 << 15) | ||
94 | |||
95 | /* | ||
96 | * track panel specific parameters for common init | ||
97 | */ | ||
98 | |||
99 | struct auok190x_init_data { | ||
100 | char *id; | ||
101 | struct auok190x_board *board; | ||
102 | |||
103 | void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2); | ||
104 | void (*update_all)(struct auok190xfb_par *par); | ||
105 | bool (*need_refresh)(struct auok190xfb_par *par); | ||
106 | void (*init)(struct auok190xfb_par *par); | ||
107 | }; | ||
108 | |||
109 | |||
110 | extern void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data); | ||
111 | extern int auok190x_send_command(struct auok190xfb_par *par, u16 data); | ||
112 | extern void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, | ||
113 | int argc, u16 *argv); | ||
114 | extern int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
115 | int argc, u16 *argv); | ||
116 | extern void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, | ||
117 | u16 cmd, int argc, u16 *argv, | ||
118 | int size, u16 *data); | ||
119 | extern int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, | ||
120 | int argc, u16 *argv, int size, | ||
121 | u16 *data); | ||
122 | extern int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
123 | int argc, u16 *argv); | ||
124 | |||
125 | extern int auok190x_common_probe(struct platform_device *pdev, | ||
126 | struct auok190x_init_data *init); | ||
127 | extern int auok190x_common_remove(struct platform_device *pdev); | ||
128 | |||
129 | extern const struct dev_pm_ops auok190x_pm; | ||