blob: 698d5b92f8e27cba3b4edb0917ffdd759eb6d8d3 [file] [log] [blame]
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +03001/*
2 * linux/drivers/video/omap2/dss/rfbi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "RFBI"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
Paul Gortmakera8a35932011-07-10 13:20:26 -040027#include <linux/export.h>
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030028#include <linux/vmalloc.h>
29#include <linux/clk.h>
30#include <linux/io.h>
31#include <linux/delay.h>
32#include <linux/kfifo.h>
33#include <linux/ktime.h>
34#include <linux/hrtimer.h>
35#include <linux/seq_file.h>
Tomi Valkeinen773139f2011-04-21 19:50:31 +030036#include <linux/semaphore.h>
Tomi Valkeinen24e62892011-05-23 11:51:18 +030037#include <linux/platform_device.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030038#include <linux/pm_runtime.h>
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030039
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030040#include <video/omapdss.h>
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030041#include "dss.h"
42
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030043struct rfbi_reg { u16 idx; };
44
45#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
46
47#define RFBI_REVISION RFBI_REG(0x0000)
48#define RFBI_SYSCONFIG RFBI_REG(0x0010)
49#define RFBI_SYSSTATUS RFBI_REG(0x0014)
50#define RFBI_CONTROL RFBI_REG(0x0040)
51#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
52#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
53#define RFBI_CMD RFBI_REG(0x004c)
54#define RFBI_PARAM RFBI_REG(0x0050)
55#define RFBI_DATA RFBI_REG(0x0054)
56#define RFBI_READ RFBI_REG(0x0058)
57#define RFBI_STATUS RFBI_REG(0x005c)
58
59#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
60#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
61#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
62#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
63#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
64#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
65
66#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
67#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
68
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030069#define REG_FLD_MOD(idx, val, start, end) \
70 rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
71
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030072enum omap_rfbi_cycleformat {
73 OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
74 OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
75 OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
76 OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
77};
78
79enum omap_rfbi_datatype {
80 OMAP_DSS_RFBI_DATATYPE_12 = 0,
81 OMAP_DSS_RFBI_DATATYPE_16 = 1,
82 OMAP_DSS_RFBI_DATATYPE_18 = 2,
83 OMAP_DSS_RFBI_DATATYPE_24 = 3,
84};
85
86enum omap_rfbi_parallelmode {
87 OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
88 OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
89 OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
90 OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
91};
92
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030093static int rfbi_convert_timings(struct rfbi_timings *t);
94static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030095
96static struct {
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +000097 struct platform_device *pdev;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +030098 void __iomem *base;
99
100 unsigned long l4_khz;
101
102 enum omap_rfbi_datatype datatype;
103 enum omap_rfbi_parallelmode parallelmode;
104
105 enum omap_rfbi_te_mode te_mode;
106 int te_enabled;
107
108 void (*framedone_callback)(void *data);
109 void *framedone_callback_data;
110
111 struct omap_dss_device *dssdev[2];
112
Tomi Valkeinen773139f2011-04-21 19:50:31 +0300113 struct semaphore bus_lock;
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530114
115 struct omap_video_timings timings;
Archit Tanejab02875b2012-08-13 15:26:49 +0530116 int pixel_size;
Archit Taneja475989b2012-08-13 15:28:15 +0530117 int data_lines;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300118} rfbi;
119
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300120static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
121{
122 __raw_writel(val, rfbi.base + idx.idx);
123}
124
125static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
126{
127 return __raw_readl(rfbi.base + idx.idx);
128}
129
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300130static int rfbi_runtime_get(void)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300131{
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300132 int r;
133
134 DSSDBG("rfbi_runtime_get\n");
135
136 r = pm_runtime_get_sync(&rfbi.pdev->dev);
137 WARN_ON(r < 0);
138 return r < 0 ? r : 0;
139}
140
141static void rfbi_runtime_put(void)
142{
143 int r;
144
145 DSSDBG("rfbi_runtime_put\n");
146
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +0200147 r = pm_runtime_put_sync(&rfbi.pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300148 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300149}
150
Tomi Valkeinen773139f2011-04-21 19:50:31 +0300151void rfbi_bus_lock(void)
152{
153 down(&rfbi.bus_lock);
154}
155EXPORT_SYMBOL(rfbi_bus_lock);
156
157void rfbi_bus_unlock(void)
158{
159 up(&rfbi.bus_lock);
160}
161EXPORT_SYMBOL(rfbi_bus_unlock);
162
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300163void omap_rfbi_write_command(const void *buf, u32 len)
164{
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300165 switch (rfbi.parallelmode) {
166 case OMAP_DSS_RFBI_PARALLELMODE_8:
167 {
168 const u8 *b = buf;
169 for (; len; len--)
170 rfbi_write_reg(RFBI_CMD, *b++);
171 break;
172 }
173
174 case OMAP_DSS_RFBI_PARALLELMODE_16:
175 {
176 const u16 *w = buf;
177 BUG_ON(len & 1);
178 for (; len; len -= 2)
179 rfbi_write_reg(RFBI_CMD, *w++);
180 break;
181 }
182
183 case OMAP_DSS_RFBI_PARALLELMODE_9:
184 case OMAP_DSS_RFBI_PARALLELMODE_12:
185 default:
186 BUG();
187 }
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300188}
189EXPORT_SYMBOL(omap_rfbi_write_command);
190
191void omap_rfbi_read_data(void *buf, u32 len)
192{
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300193 switch (rfbi.parallelmode) {
194 case OMAP_DSS_RFBI_PARALLELMODE_8:
195 {
196 u8 *b = buf;
197 for (; len; len--) {
198 rfbi_write_reg(RFBI_READ, 0);
199 *b++ = rfbi_read_reg(RFBI_READ);
200 }
201 break;
202 }
203
204 case OMAP_DSS_RFBI_PARALLELMODE_16:
205 {
206 u16 *w = buf;
207 BUG_ON(len & ~1);
208 for (; len; len -= 2) {
209 rfbi_write_reg(RFBI_READ, 0);
210 *w++ = rfbi_read_reg(RFBI_READ);
211 }
212 break;
213 }
214
215 case OMAP_DSS_RFBI_PARALLELMODE_9:
216 case OMAP_DSS_RFBI_PARALLELMODE_12:
217 default:
218 BUG();
219 }
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300220}
221EXPORT_SYMBOL(omap_rfbi_read_data);
222
223void omap_rfbi_write_data(const void *buf, u32 len)
224{
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300225 switch (rfbi.parallelmode) {
226 case OMAP_DSS_RFBI_PARALLELMODE_8:
227 {
228 const u8 *b = buf;
229 for (; len; len--)
230 rfbi_write_reg(RFBI_PARAM, *b++);
231 break;
232 }
233
234 case OMAP_DSS_RFBI_PARALLELMODE_16:
235 {
236 const u16 *w = buf;
237 BUG_ON(len & 1);
238 for (; len; len -= 2)
239 rfbi_write_reg(RFBI_PARAM, *w++);
240 break;
241 }
242
243 case OMAP_DSS_RFBI_PARALLELMODE_9:
244 case OMAP_DSS_RFBI_PARALLELMODE_12:
245 default:
246 BUG();
247
248 }
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300249}
250EXPORT_SYMBOL(omap_rfbi_write_data);
251
252void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
253 u16 x, u16 y,
254 u16 w, u16 h)
255{
256 int start_offset = scr_width * y + x;
257 int horiz_offset = scr_width - w;
258 int i;
259
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300260 if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
261 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
262 const u16 __iomem *pd = buf;
263 pd += start_offset;
264
265 for (; h; --h) {
266 for (i = 0; i < w; ++i) {
267 const u8 __iomem *b = (const u8 __iomem *)pd;
268 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
269 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
270 ++pd;
271 }
272 pd += horiz_offset;
273 }
274 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
275 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
276 const u32 __iomem *pd = buf;
277 pd += start_offset;
278
279 for (; h; --h) {
280 for (i = 0; i < w; ++i) {
281 const u8 __iomem *b = (const u8 __iomem *)pd;
282 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
283 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
284 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
285 ++pd;
286 }
287 pd += horiz_offset;
288 }
289 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
290 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
291 const u16 __iomem *pd = buf;
292 pd += start_offset;
293
294 for (; h; --h) {
295 for (i = 0; i < w; ++i) {
296 rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
297 ++pd;
298 }
299 pd += horiz_offset;
300 }
301 } else {
302 BUG();
303 }
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300304}
305EXPORT_SYMBOL(omap_rfbi_write_pixels);
306
Archit Taneja43eab862012-08-13 12:24:53 +0530307static int rfbi_transfer_area(struct omap_dss_device *dssdev,
308 void (*callback)(void *data), void *data)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300309{
310 u32 l;
Archit Tanejac47cdb32012-05-29 11:55:38 +0530311 int r;
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530312 u16 width = rfbi.timings.x_res;
313 u16 height = rfbi.timings.y_res;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300314
315 /*BUG_ON(callback == 0);*/
316 BUG_ON(rfbi.framedone_callback != NULL);
317
318 DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
319
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530320 dss_mgr_set_timings(dssdev->manager, &rfbi.timings);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300321
Archit Tanejac47cdb32012-05-29 11:55:38 +0530322 r = dss_mgr_enable(dssdev->manager);
323 if (r)
324 return r;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300325
326 rfbi.framedone_callback = callback;
327 rfbi.framedone_callback_data = data;
328
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300329 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
330
331 l = rfbi_read_reg(RFBI_CONTROL);
332 l = FLD_MOD(l, 1, 0, 0); /* enable */
333 if (!rfbi.te_enabled)
334 l = FLD_MOD(l, 1, 4, 4); /* ITE */
335
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300336 rfbi_write_reg(RFBI_CONTROL, l);
Archit Tanejac47cdb32012-05-29 11:55:38 +0530337
338 return 0;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300339}
340
341static void framedone_callback(void *data, u32 mask)
342{
343 void (*callback)(void *data);
344
345 DSSDBG("FRAMEDONE\n");
346
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300347 REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
348
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300349 callback = rfbi.framedone_callback;
350 rfbi.framedone_callback = NULL;
351
Tomi Valkeinen18946f62010-01-12 14:16:41 +0200352 if (callback != NULL)
353 callback(rfbi.framedone_callback_data);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300354}
355
356#if 1 /* VERBOSE */
357static void rfbi_print_timings(void)
358{
359 u32 l;
360 u32 time;
361
362 l = rfbi_read_reg(RFBI_CONFIG(0));
363 time = 1000000000 / rfbi.l4_khz;
364 if (l & (1 << 4))
365 time *= 2;
366
367 DSSDBG("Tick time %u ps\n", time);
368 l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
369 DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
370 "REONTIME %d, REOFFTIME %d\n",
371 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
372 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
373
374 l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
375 DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
376 "ACCESSTIME %d\n",
377 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
378 (l >> 22) & 0x3f);
379}
380#else
381static void rfbi_print_timings(void) {}
382#endif
383
384
385
386
387static u32 extif_clk_period;
388
389static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
390{
391 int bus_tick = extif_clk_period * div;
392 return (ps + bus_tick - 1) / bus_tick * bus_tick;
393}
394
395static int calc_reg_timing(struct rfbi_timings *t, int div)
396{
397 t->clk_div = div;
398
399 t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
400
401 t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
402 t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
403 t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
404
405 t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
406 t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
407 t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
408
409 t->access_time = round_to_extif_ticks(t->access_time, div);
410 t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
411 t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
412
413 DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
414 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
415 DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
416 t->we_on_time, t->we_off_time, t->re_cycle_time,
417 t->we_cycle_time);
418 DSSDBG("[reg]rdaccess %d cspulse %d\n",
419 t->access_time, t->cs_pulse_width);
420
421 return rfbi_convert_timings(t);
422}
423
424static int calc_extif_timings(struct rfbi_timings *t)
425{
426 u32 max_clk_div;
427 int div;
428
429 rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
430 for (div = 1; div <= max_clk_div; div++) {
431 if (calc_reg_timing(t, div) == 0)
432 break;
433 }
434
435 if (div <= max_clk_div)
436 return 0;
437
438 DSSERR("can't setup timings\n");
439 return -1;
440}
441
442
Tomi Valkeinenc42ced62011-04-29 16:51:10 +0300443static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300444{
445 int r;
446
447 if (!t->converted) {
448 r = calc_extif_timings(t);
449 if (r < 0)
450 DSSERR("Failed to calc timings\n");
451 }
452
453 BUG_ON(!t->converted);
454
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300455 rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
456 rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
457
458 /* TIMEGRANULARITY */
459 REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
460 (t->tim[2] ? 1 : 0), 4, 4);
461
462 rfbi_print_timings();
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300463}
464
465static int ps_to_rfbi_ticks(int time, int div)
466{
467 unsigned long tick_ps;
468 int ret;
469
470 /* Calculate in picosecs to yield more exact results */
471 tick_ps = 1000000000 / (rfbi.l4_khz) * div;
472
473 ret = (time + tick_ps - 1) / tick_ps;
474
475 return ret;
476}
477
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300478static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
479{
480 *clk_period = 1000000000 / rfbi.l4_khz;
481 *max_clk_div = 2;
482}
483
484static int rfbi_convert_timings(struct rfbi_timings *t)
485{
486 u32 l;
487 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
488 int actim, recyc, wecyc;
489 int div = t->clk_div;
490
491 if (div <= 0 || div > 2)
492 return -1;
493
494 /* Make sure that after conversion it still holds that:
495 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
496 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
497 */
498 weon = ps_to_rfbi_ticks(t->we_on_time, div);
499 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
500 if (weoff <= weon)
501 weoff = weon + 1;
502 if (weon > 0x0f)
503 return -1;
504 if (weoff > 0x3f)
505 return -1;
506
507 reon = ps_to_rfbi_ticks(t->re_on_time, div);
508 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
509 if (reoff <= reon)
510 reoff = reon + 1;
511 if (reon > 0x0f)
512 return -1;
513 if (reoff > 0x3f)
514 return -1;
515
516 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
517 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
518 if (csoff <= cson)
519 csoff = cson + 1;
520 if (csoff < max(weoff, reoff))
521 csoff = max(weoff, reoff);
522 if (cson > 0x0f)
523 return -1;
524 if (csoff > 0x3f)
525 return -1;
526
527 l = cson;
528 l |= csoff << 4;
529 l |= weon << 10;
530 l |= weoff << 14;
531 l |= reon << 20;
532 l |= reoff << 24;
533
534 t->tim[0] = l;
535
536 actim = ps_to_rfbi_ticks(t->access_time, div);
537 if (actim <= reon)
538 actim = reon + 1;
539 if (actim > 0x3f)
540 return -1;
541
542 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
543 if (wecyc < weoff)
544 wecyc = weoff;
545 if (wecyc > 0x3f)
546 return -1;
547
548 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
549 if (recyc < reoff)
550 recyc = reoff;
551 if (recyc > 0x3f)
552 return -1;
553
554 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
555 if (cs_pulse > 0x3f)
556 return -1;
557
558 l = wecyc;
559 l |= recyc << 6;
560 l |= cs_pulse << 12;
561 l |= actim << 22;
562
563 t->tim[1] = l;
564
565 t->tim[2] = div - 1;
566
567 t->converted = 1;
568
569 return 0;
570}
571
572/* xxx FIX module selection missing */
573int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
574 unsigned hs_pulse_time, unsigned vs_pulse_time,
575 int hs_pol_inv, int vs_pol_inv, int extif_div)
576{
577 int hs, vs;
578 int min;
579 u32 l;
580
581 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
582 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
583 if (hs < 2)
584 return -EDOM;
585 if (mode == OMAP_DSS_RFBI_TE_MODE_2)
586 min = 2;
587 else /* OMAP_DSS_RFBI_TE_MODE_1 */
588 min = 4;
589 if (vs < min)
590 return -EDOM;
591 if (vs == hs)
592 return -EINVAL;
593 rfbi.te_mode = mode;
594 DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
595 mode, hs, vs, hs_pol_inv, vs_pol_inv);
596
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300597 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
598 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
599
600 l = rfbi_read_reg(RFBI_CONFIG(0));
601 if (hs_pol_inv)
602 l &= ~(1 << 21);
603 else
604 l |= 1 << 21;
605 if (vs_pol_inv)
606 l &= ~(1 << 20);
607 else
608 l |= 1 << 20;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300609
610 return 0;
611}
612EXPORT_SYMBOL(omap_rfbi_setup_te);
613
614/* xxx FIX module selection missing */
615int omap_rfbi_enable_te(bool enable, unsigned line)
616{
617 u32 l;
618
619 DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
620 if (line > (1 << 11) - 1)
621 return -EINVAL;
622
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300623 l = rfbi_read_reg(RFBI_CONFIG(0));
624 l &= ~(0x3 << 2);
625 if (enable) {
626 rfbi.te_enabled = 1;
627 l |= rfbi.te_mode << 2;
628 } else
629 rfbi.te_enabled = 0;
630 rfbi_write_reg(RFBI_CONFIG(0), l);
631 rfbi_write_reg(RFBI_LINE_NUMBER, line);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300632
633 return 0;
634}
635EXPORT_SYMBOL(omap_rfbi_enable_te);
636
Tomi Valkeinenc42ced62011-04-29 16:51:10 +0300637static int rfbi_configure(int rfbi_module, int bpp, int lines)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300638{
639 u32 l;
640 int cycle1 = 0, cycle2 = 0, cycle3 = 0;
641 enum omap_rfbi_cycleformat cycleformat;
642 enum omap_rfbi_datatype datatype;
643 enum omap_rfbi_parallelmode parallelmode;
644
645 switch (bpp) {
646 case 12:
647 datatype = OMAP_DSS_RFBI_DATATYPE_12;
648 break;
649 case 16:
650 datatype = OMAP_DSS_RFBI_DATATYPE_16;
651 break;
652 case 18:
653 datatype = OMAP_DSS_RFBI_DATATYPE_18;
654 break;
655 case 24:
656 datatype = OMAP_DSS_RFBI_DATATYPE_24;
657 break;
658 default:
659 BUG();
660 return 1;
661 }
662 rfbi.datatype = datatype;
663
664 switch (lines) {
665 case 8:
666 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
667 break;
668 case 9:
669 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
670 break;
671 case 12:
672 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
673 break;
674 case 16:
675 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
676 break;
677 default:
678 BUG();
679 return 1;
680 }
681 rfbi.parallelmode = parallelmode;
682
683 if ((bpp % lines) == 0) {
684 switch (bpp / lines) {
685 case 1:
686 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
687 break;
688 case 2:
689 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
690 break;
691 case 3:
692 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
693 break;
694 default:
695 BUG();
696 return 1;
697 }
698 } else if ((2 * bpp % lines) == 0) {
699 if ((2 * bpp / lines) == 3)
700 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
701 else {
702 BUG();
703 return 1;
704 }
705 } else {
706 BUG();
707 return 1;
708 }
709
710 switch (cycleformat) {
711 case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
712 cycle1 = lines;
713 break;
714
715 case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
716 cycle1 = lines;
717 cycle2 = lines;
718 break;
719
720 case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
721 cycle1 = lines;
722 cycle2 = lines;
723 cycle3 = lines;
724 break;
725
726 case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
727 cycle1 = lines;
728 cycle2 = (lines / 2) | ((lines / 2) << 16);
729 cycle3 = (lines << 16);
730 break;
731 }
732
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300733 REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
734
735 l = 0;
736 l |= FLD_VAL(parallelmode, 1, 0);
737 l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
738 l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
739 l |= FLD_VAL(datatype, 6, 5);
740 /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
741 l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
742 l |= FLD_VAL(cycleformat, 10, 9);
743 l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
744 l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
745 l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
746 l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
747 l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
748 l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
749 l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
750 rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
751
752 rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
753 rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
754 rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
755
756
757 l = rfbi_read_reg(RFBI_CONTROL);
758 l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
759 l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
760 rfbi_write_reg(RFBI_CONTROL, l);
761
762
763 DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
764 bpp, lines, cycle1, cycle2, cycle3);
765
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300766 return 0;
767}
Tomi Valkeinen1d5952a2011-04-29 15:57:01 +0300768
Archit Taneja475989b2012-08-13 15:28:15 +0530769int omap_rfbi_configure(struct omap_dss_device *dssdev)
Tomi Valkeinen1d5952a2011-04-29 15:57:01 +0300770{
Archit Tanejab02875b2012-08-13 15:26:49 +0530771 return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
Archit Taneja475989b2012-08-13 15:28:15 +0530772 rfbi.data_lines);
Tomi Valkeinen1d5952a2011-04-29 15:57:01 +0300773}
774EXPORT_SYMBOL(omap_rfbi_configure);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300775
Archit Taneja43eab862012-08-13 12:24:53 +0530776int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
777 void *data)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300778{
Archit Taneja43eab862012-08-13 12:24:53 +0530779 return rfbi_transfer_area(dssdev, callback, data);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300780}
Tomi Valkeinen18946f62010-01-12 14:16:41 +0200781EXPORT_SYMBOL(omap_rfbi_update);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300782
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530783void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
784{
785 rfbi.timings.x_res = w;
786 rfbi.timings.y_res = h;
787}
788EXPORT_SYMBOL(omapdss_rfbi_set_size);
789
Archit Tanejab02875b2012-08-13 15:26:49 +0530790void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
791{
792 rfbi.pixel_size = pixel_size;
793}
794EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size);
795
Archit Taneja475989b2012-08-13 15:28:15 +0530796void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
797{
798 rfbi.data_lines = data_lines;
799}
800EXPORT_SYMBOL(omapdss_rfbi_set_data_lines);
801
Tomi Valkeinene40402c2012-03-02 18:01:07 +0200802static void rfbi_dump_regs(struct seq_file *s)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300803{
804#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
805
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300806 if (rfbi_runtime_get())
807 return;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300808
809 DUMPREG(RFBI_REVISION);
810 DUMPREG(RFBI_SYSCONFIG);
811 DUMPREG(RFBI_SYSSTATUS);
812 DUMPREG(RFBI_CONTROL);
813 DUMPREG(RFBI_PIXEL_CNT);
814 DUMPREG(RFBI_LINE_NUMBER);
815 DUMPREG(RFBI_CMD);
816 DUMPREG(RFBI_PARAM);
817 DUMPREG(RFBI_DATA);
818 DUMPREG(RFBI_READ);
819 DUMPREG(RFBI_STATUS);
820
821 DUMPREG(RFBI_CONFIG(0));
822 DUMPREG(RFBI_ONOFF_TIME(0));
823 DUMPREG(RFBI_CYCLE_TIME(0));
824 DUMPREG(RFBI_DATA_CYCLE1(0));
825 DUMPREG(RFBI_DATA_CYCLE2(0));
826 DUMPREG(RFBI_DATA_CYCLE3(0));
827
828 DUMPREG(RFBI_CONFIG(1));
829 DUMPREG(RFBI_ONOFF_TIME(1));
830 DUMPREG(RFBI_CYCLE_TIME(1));
831 DUMPREG(RFBI_DATA_CYCLE1(1));
832 DUMPREG(RFBI_DATA_CYCLE2(1));
833 DUMPREG(RFBI_DATA_CYCLE3(1));
834
835 DUMPREG(RFBI_VSYNC_WIDTH);
836 DUMPREG(RFBI_HSYNC_WIDTH);
837
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300838 rfbi_runtime_put();
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300839#undef DUMPREG
840}
841
Archit Tanejabc2e60a2012-06-25 11:24:10 +0530842static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
843{
844 struct dss_lcd_mgr_config mgr_config;
845
846 mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
847
848 mgr_config.stallmode = true;
849 /* Do we need fifohandcheck for RFBI? */
850 mgr_config.fifohandcheck = false;
851
Archit Tanejab02875b2012-08-13 15:26:49 +0530852 mgr_config.video_port_width = rfbi.pixel_size;
Archit Tanejabc2e60a2012-06-25 11:24:10 +0530853 mgr_config.lcden_sig_polarity = 0;
854
Archit Tanejaf476ae92012-06-29 14:37:03 +0530855 dss_mgr_set_lcd_config(dssdev->manager, &mgr_config);
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530856
857 /*
858 * Set rfbi.timings with default values, the x_res and y_res fields
859 * are expected to be already configured by the panel driver via
860 * omapdss_rfbi_set_size()
861 */
862 rfbi.timings.hsw = 1;
863 rfbi.timings.hfp = 1;
864 rfbi.timings.hbp = 1;
865 rfbi.timings.vsw = 1;
866 rfbi.timings.vfp = 0;
867 rfbi.timings.vbp = 0;
868
869 rfbi.timings.interlace = false;
870 rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
871 rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
872 rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
873 rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
874 rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
875
876 dss_mgr_set_timings(dssdev->manager, &rfbi.timings);
Archit Tanejabc2e60a2012-06-25 11:24:10 +0530877}
878
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +0200879int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300880{
881 int r;
882
Tomi Valkeinen05e1d602011-06-23 16:38:21 +0300883 if (dssdev->manager == NULL) {
884 DSSERR("failed to enable display: no manager\n");
885 return -ENODEV;
886 }
887
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300888 r = rfbi_runtime_get();
889 if (r)
890 return r;
Tomi Valkeinen5be685f2011-04-21 19:53:25 +0300891
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300892 r = omap_dss_start_device(dssdev);
893 if (r) {
894 DSSERR("failed to start device\n");
895 goto err0;
896 }
897
898 r = omap_dispc_register_isr(framedone_callback, NULL,
899 DISPC_IRQ_FRAMEDONE);
900 if (r) {
901 DSSERR("can't get FRAMEDONE irq\n");
902 goto err1;
903 }
904
Archit Tanejabc2e60a2012-06-25 11:24:10 +0530905 rfbi_config_lcd_manager(dssdev);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300906
Archit Tanejab02875b2012-08-13 15:26:49 +0530907 rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
Archit Taneja475989b2012-08-13 15:28:15 +0530908 rfbi.data_lines);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300909
910 rfbi_set_timings(dssdev->phy.rfbi.channel,
911 &dssdev->ctrl.rfbi_timings);
912
913
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300914 return 0;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300915err1:
916 omap_dss_stop_device(dssdev);
917err0:
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300918 rfbi_runtime_put();
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300919 return r;
920}
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +0200921EXPORT_SYMBOL(omapdss_rfbi_display_enable);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300922
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +0200923void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300924{
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300925 omap_dispc_unregister_isr(framedone_callback, NULL,
926 DISPC_IRQ_FRAMEDONE);
927 omap_dss_stop_device(dssdev);
Tomi Valkeinen5be685f2011-04-21 19:53:25 +0300928
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300929 rfbi_runtime_put();
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300930}
Tomi Valkeinen37ac60e2010-01-12 15:12:07 +0200931EXPORT_SYMBOL(omapdss_rfbi_display_disable);
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300932
Tomi Valkeinen9d8232a2012-03-01 16:58:39 +0200933static int __init rfbi_init_display(struct omap_dss_device *dssdev)
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300934{
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300935 rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300936 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
Tomi Valkeinen5c18adb2009-08-05 16:18:31 +0300937 return 0;
938}
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000939
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +0300940static void __init rfbi_probe_pdata(struct platform_device *pdev)
941{
942 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
943 int i, r;
944
945 for (i = 0; i < pdata->num_devices; ++i) {
946 struct omap_dss_device *dssdev = pdata->devices[i];
947
948 if (dssdev->type != OMAP_DISPLAY_TYPE_DBI)
949 continue;
950
951 r = rfbi_init_display(dssdev);
952 if (r) {
953 DSSERR("device %s init failed: %d\n", dssdev->name, r);
954 continue;
955 }
956
957 r = omap_dss_register_device(dssdev, &pdev->dev, i);
958 if (r)
959 DSSERR("device %s register failed: %d\n",
960 dssdev->name, r);
961 }
962}
963
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000964/* RFBI HW IP initialisation */
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +0200965static int __init omap_rfbihw_probe(struct platform_device *pdev)
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000966{
967 u32 rev;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +0000968 struct resource *rfbi_mem;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300969 struct clk *clk;
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +0300970 int r;
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000971
972 rfbi.pdev = pdev;
973
Tomi Valkeinen773139f2011-04-21 19:50:31 +0300974 sema_init(&rfbi.bus_lock, 1);
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000975
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +0000976 rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
977 if (!rfbi_mem) {
978 DSSERR("can't get IORESOURCE_MEM RFBI\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +0200979 return -EINVAL;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +0000980 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +0200981
Julia Lawall6e2a14d2012-01-24 14:00:45 +0100982 rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start,
983 resource_size(rfbi_mem));
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000984 if (!rfbi.base) {
985 DSSERR("can't ioremap RFBI\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +0200986 return -ENOMEM;
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000987 }
988
Tomi Valkeinenbfe4f8d2011-08-04 11:22:54 +0300989 clk = clk_get(&pdev->dev, "ick");
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300990 if (IS_ERR(clk)) {
991 DSSERR("can't get ick\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +0200992 return PTR_ERR(clk);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300993 }
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000994
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300995 rfbi.l4_khz = clk_get_rate(clk) / 1000;
996
997 clk_put(clk);
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +0000998
Tomi Valkeinencd3b3442012-01-25 13:31:04 +0200999 pm_runtime_enable(&pdev->dev);
1000
1001 r = rfbi_runtime_get();
1002 if (r)
1003 goto err_runtime_get;
1004
1005 msleep(10);
1006
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001007 rev = rfbi_read_reg(RFBI_REVISION);
Sumit Semwala06b62f2011-01-24 06:22:03 +00001008 dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001009 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
1010
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001011 rfbi_runtime_put();
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001012
Tomi Valkeinene40402c2012-03-02 18:01:07 +02001013 dss_debugfs_create_file("rfbi", rfbi_dump_regs);
1014
Tomi Valkeinen38f3daf2012-05-02 14:55:12 +03001015 rfbi_probe_pdata(pdev);
Tomi Valkeinen35deca32012-03-01 15:45:53 +02001016
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001017 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001018
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02001019err_runtime_get:
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001020 pm_runtime_disable(&pdev->dev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001021 return r;
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001022}
1023
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001024static int __exit omap_rfbihw_remove(struct platform_device *pdev)
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001025{
Tomi Valkeinen35deca32012-03-01 15:45:53 +02001026 omap_dss_unregister_child_devices(&pdev->dev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001027 pm_runtime_disable(&pdev->dev);
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001028 return 0;
1029}
1030
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001031static int rfbi_runtime_suspend(struct device *dev)
1032{
1033 dispc_runtime_put();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001034
1035 return 0;
1036}
1037
1038static int rfbi_runtime_resume(struct device *dev)
1039{
1040 int r;
1041
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001042 r = dispc_runtime_get();
1043 if (r < 0)
Tomi Valkeinen852f0832012-02-17 17:58:04 +02001044 return r;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001045
1046 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001047}
1048
1049static const struct dev_pm_ops rfbi_pm_ops = {
1050 .runtime_suspend = rfbi_runtime_suspend,
1051 .runtime_resume = rfbi_runtime_resume,
1052};
1053
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001054static struct platform_driver omap_rfbihw_driver = {
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001055 .remove = __exit_p(omap_rfbihw_remove),
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001056 .driver = {
1057 .name = "omapdss_rfbi",
1058 .owner = THIS_MODULE,
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001059 .pm = &rfbi_pm_ops,
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001060 },
1061};
1062
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001063int __init rfbi_init_platform_driver(void)
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001064{
Tomi Valkeinen61055d42012-03-07 12:53:38 +02001065 return platform_driver_probe(&omap_rfbihw_driver, omap_rfbihw_probe);
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001066}
1067
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02001068void __exit rfbi_uninit_platform_driver(void)
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001069{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02001070 platform_driver_unregister(&omap_rfbihw_driver);
Senthilvadivu Guruswamy3448d502011-01-24 06:21:59 +00001071}