fbdev: sh_mipi_dsi: add VMLEN1/VMLEN2 calculation
[deliverable/linux.git] / drivers / video / sh_mipi_dsi.c
CommitLineData
9fd04fe3
GL
1/*
2 * Renesas SH-mobile MIPI DSI support
3 *
4 * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 *
6 * This is free software; you can redistribute it and/or modify
7 * it under the terms of version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
9 */
10
26c3d7ac 11#include <linux/bitmap.h>
9fd04fe3
GL
12#include <linux/clk.h>
13#include <linux/delay.h>
14#include <linux/init.h>
15#include <linux/io.h>
16#include <linux/platform_device.h>
236782a5 17#include <linux/pm_runtime.h>
9fd04fe3
GL
18#include <linux/slab.h>
19#include <linux/string.h>
20#include <linux/types.h>
355b200b 21#include <linux/module.h>
9fd04fe3
GL
22
23#include <video/mipi_display.h>
24#include <video/sh_mipi_dsi.h>
25#include <video/sh_mobile_lcdc.h>
26
71b146c8
MD
27#define SYSCTRL 0x0000
28#define SYSCONF 0x0004
29#define TIMSET 0x0008
30#define RESREQSET0 0x0018
31#define RESREQSET1 0x001c
32#define HSTTOVSET 0x0020
33#define LPRTOVSET 0x0024
34#define TATOVSET 0x0028
35#define PRTOVSET 0x002c
36#define DSICTRL 0x0030
37#define DSIINTE 0x0060
38#define PHYCTRL 0x0070
39
deaba190
MD
40/* relative to linkbase */
41#define DTCTR 0x0000
42#define VMCTR1 0x0020
43#define VMCTR2 0x0024
44#define VMLEN1 0x0028
08750617 45#define VMLEN2 0x002c
deaba190
MD
46#define CMTSRTREQ 0x0070
47#define CMTSRTCTR 0x00d0
9fd04fe3
GL
48
49/* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
50#define MAX_SH_MIPI_DSI 2
51
52struct sh_mipi {
53 void __iomem *base;
deaba190 54 void __iomem *linkbase;
9fd04fe3
GL
55 struct clk *dsit_clk;
56 struct clk *dsip_clk;
236782a5
GL
57 struct device *dev;
58
59 void *next_board_data;
60 void (*next_display_on)(void *board_data, struct fb_info *info);
61 void (*next_display_off)(void *board_data);
9fd04fe3
GL
62};
63
64static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
65
66/* Protect the above array */
67static DEFINE_MUTEX(array_lock);
68
69static struct sh_mipi *sh_mipi_by_handle(int handle)
70{
71 if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0)
72 return NULL;
73
74 return mipi_dsi[handle];
75}
76
77static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
78 u8 cmd, u8 param)
79{
80 u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8);
81 int cnt = 100;
82
83 /* transmit a short packet to LCD panel */
deaba190
MD
84 iowrite32(1 | data, mipi->linkbase + CMTSRTCTR);
85 iowrite32(1, mipi->linkbase + CMTSRTREQ);
9fd04fe3 86
deaba190 87 while ((ioread32(mipi->linkbase + CMTSRTREQ) & 1) && --cnt)
9fd04fe3
GL
88 udelay(1);
89
90 return cnt ? 0 : -ETIMEDOUT;
91}
92
93#define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \
94 -EINVAL : (c) - 1)
95
96static int sh_mipi_dcs(int handle, u8 cmd)
97{
98 struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
99 if (!mipi)
100 return -ENODEV;
101 return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);
102}
103
104static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param)
105{
106 struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
107 if (!mipi)
108 return -ENODEV;
109 return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd,
110 param);
111}
112
113static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
114{
115 /*
116 * enable LCDC data tx, transition to LPS after completion of each HS
117 * packet
118 */
deaba190 119 iowrite32(0x00000002 | enable, mipi->linkbase + DTCTR);
9fd04fe3
GL
120}
121
122static void sh_mipi_shutdown(struct platform_device *pdev)
123{
124 struct sh_mipi *mipi = platform_get_drvdata(pdev);
125
126 sh_mipi_dsi_enable(mipi, false);
127}
128
c2439398 129static void mipi_display_on(void *arg, struct fb_info *info)
9fd04fe3
GL
130{
131 struct sh_mipi *mipi = arg;
132
236782a5 133 pm_runtime_get_sync(mipi->dev);
9fd04fe3 134 sh_mipi_dsi_enable(mipi, true);
6722a401
MD
135
136 if (mipi->next_display_on)
137 mipi->next_display_on(mipi->next_board_data, info);
9fd04fe3
GL
138}
139
140static void mipi_display_off(void *arg)
141{
142 struct sh_mipi *mipi = arg;
143
6722a401
MD
144 if (mipi->next_display_off)
145 mipi->next_display_off(mipi->next_board_data);
146
9fd04fe3 147 sh_mipi_dsi_enable(mipi, false);
236782a5 148 pm_runtime_put(mipi->dev);
9fd04fe3
GL
149}
150
151static int __init sh_mipi_setup(struct sh_mipi *mipi,
152 struct sh_mipi_dsi_info *pdata)
153{
154 void __iomem *base = mipi->base;
155 struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
f832906a 156 u32 pctype, datatype, pixfmt, linelength, vmctr2;
08750617 157 u32 tmp, top, bottom, delay;
9fd04fe3 158 bool yuv;
08750617 159 int bpp;
9fd04fe3 160
44432407
GL
161 /*
162 * Select data format. MIPI DSI is not hot-pluggable, so, we just use
163 * the default videomode. If this ever becomes a problem, We'll have to
164 * move this to mipi_display_on() above and use info->var.xres
165 */
9fd04fe3
GL
166 switch (pdata->data_format) {
167 case MIPI_RGB888:
168 pctype = 0;
169 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
170 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407 171 linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe3
GL
172 yuv = false;
173 break;
174 case MIPI_RGB565:
175 pctype = 1;
176 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
177 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407 178 linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe3
GL
179 yuv = false;
180 break;
181 case MIPI_RGB666_LP:
182 pctype = 2;
183 datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
184 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407 185 linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe3
GL
186 yuv = false;
187 break;
188 case MIPI_RGB666:
189 pctype = 3;
190 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
191 pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
44432407 192 linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
9fd04fe3
GL
193 yuv = false;
194 break;
195 case MIPI_BGR888:
196 pctype = 8;
197 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
198 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407 199 linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe3
GL
200 yuv = false;
201 break;
202 case MIPI_BGR565:
203 pctype = 9;
204 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
205 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407 206 linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe3
GL
207 yuv = false;
208 break;
209 case MIPI_BGR666_LP:
210 pctype = 0xa;
211 datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
212 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407 213 linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe3
GL
214 yuv = false;
215 break;
216 case MIPI_BGR666:
217 pctype = 0xb;
218 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
219 pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
44432407 220 linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
9fd04fe3
GL
221 yuv = false;
222 break;
223 case MIPI_YUYV:
224 pctype = 4;
225 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
226 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407 227 linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe3
GL
228 yuv = true;
229 break;
230 case MIPI_UYVY:
231 pctype = 5;
232 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
233 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407 234 linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe3
GL
235 yuv = true;
236 break;
237 case MIPI_YUV420_L:
238 pctype = 6;
239 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
240 pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
44432407 241 linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8;
9fd04fe3
GL
242 yuv = true;
243 break;
244 case MIPI_YUV420:
245 pctype = 7;
246 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
247 pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
248 /* Length of U/V line */
44432407 249 linelength = (ch->lcd_cfg[0].xres + 1) / 2;
9fd04fe3
GL
250 yuv = true;
251 break;
252 default:
253 return -EINVAL;
254 }
255
256 if ((yuv && ch->interface_type != YUV422) ||
257 (!yuv && ch->interface_type != RGB24))
258 return -EINVAL;
259
26c3d7ac
KM
260 if (!pdata->lane)
261 return -EINVAL;
262
9fd04fe3 263 /* reset DSI link */
71b146c8 264 iowrite32(0x00000001, base + SYSCTRL);
9fd04fe3
GL
265 /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
266 udelay(50);
71b146c8 267 iowrite32(0x00000000, base + SYSCTRL);
9fd04fe3
GL
268
269 /* setup DSI link */
270
271 /*
272 * Default = ULPS enable |
273 * Contention detection enabled |
274 * EoT packet transmission enable |
275 * CRC check enable |
276 * ECC check enable
277 * additionally enable first two lanes
278 */
26c3d7ac
KM
279 bitmap_fill((unsigned long *)&tmp, pdata->lane);
280 tmp |= 0x00003700;
281 iowrite32(tmp, base + SYSCONF);
282
9fd04fe3
GL
283 /*
284 * T_wakeup = 0x7000
285 * T_hs-trail = 3
286 * T_hs-prepare = 3
287 * T_clk-trail = 3
288 * T_clk-prepare = 2
289 */
71b146c8 290 iowrite32(0x70003332, base + TIMSET);
9fd04fe3 291 /* no responses requested */
71b146c8 292 iowrite32(0x00000000, base + RESREQSET0);
9fd04fe3 293 /* request response to packets of type 0x28 */
71b146c8 294 iowrite32(0x00000100, base + RESREQSET1);
9fd04fe3 295 /* High-speed transmission timeout, default 0xffffffff */
71b146c8 296 iowrite32(0x0fffffff, base + HSTTOVSET);
9fd04fe3 297 /* LP reception timeout, default 0xffffffff */
71b146c8 298 iowrite32(0x0fffffff, base + LPRTOVSET);
9fd04fe3 299 /* Turn-around timeout, default 0xffffffff */
71b146c8 300 iowrite32(0x0fffffff, base + TATOVSET);
9fd04fe3 301 /* Peripheral reset timeout, default 0xffffffff */
71b146c8 302 iowrite32(0x0fffffff, base + PRTOVSET);
9fd04fe3 303 /* Enable timeout counters */
71b146c8 304 iowrite32(0x00000f00, base + DSICTRL);
9fd04fe3
GL
305 /* Interrupts not used, disable all */
306 iowrite32(0, base + DSIINTE);
307 /* DSI-Tx bias on */
71b146c8 308 iowrite32(0x00000001, base + PHYCTRL);
9fd04fe3
GL
309 udelay(200);
310 /* Deassert resets, power on, set multiplier */
71b146c8 311 iowrite32(0x03070b01, base + PHYCTRL);
9fd04fe3
GL
312
313 /* setup l-bridge */
314
315 /*
316 * Enable transmission of all packets,
317 * transmit LPS after each HS packet completion
318 */
deaba190 319 iowrite32(0x00000006, mipi->linkbase + DTCTR);
9fd04fe3 320 /* VSYNC width = 2 (<< 17) */
14bbb7c6
GL
321 iowrite32((ch->lcd_cfg[0].vsync_len << pdata->vsynw_offset) |
322 (pdata->clksrc << 16) | (pctype << 12) | datatype,
deaba190 323 mipi->linkbase + VMCTR1);
14bbb7c6 324
9fd04fe3
GL
325 /*
326 * Non-burst mode with sync pulses: VSE and HSE are output,
327 * HSA period allowed, no commands in LP
328 */
f832906a
KM
329 vmctr2 = 0;
330 if (pdata->flags & SH_MIPI_DSI_VSEE)
331 vmctr2 |= 1 << 23;
332 if (pdata->flags & SH_MIPI_DSI_HSEE)
333 vmctr2 |= 1 << 22;
334 if (pdata->flags & SH_MIPI_DSI_HSAE)
335 vmctr2 |= 1 << 21;
d07a9d2a
KM
336 if (pdata->flags & SH_MIPI_DSI_BL2E)
337 vmctr2 |= 1 << 17;
14bbb7c6 338 if (pdata->flags & SH_MIPI_DSI_HSABM)
3c2a6599 339 vmctr2 |= 1 << 5;
32ba95c6 340 if (pdata->flags & SH_MIPI_DSI_HBPBM)
3c2a6599 341 vmctr2 |= 1 << 4;
f7b0af68
KM
342 if (pdata->flags & SH_MIPI_DSI_HFPBM)
343 vmctr2 |= 1 << 3;
14bbb7c6
GL
344 iowrite32(vmctr2, mipi->linkbase + VMCTR2);
345
9fd04fe3 346 /*
08750617
KM
347 * VMLEN1 = RGBLEN | HSALEN
348 *
349 * see
350 * Video mode - Blanking Packet setting
9fd04fe3 351 */
08750617
KM
352 top = linelength << 16; /* RGBLEN */
353 bottom = 0x00000001;
354 if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */
355 bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10;
356 iowrite32(top | bottom , mipi->linkbase + VMLEN1);
357
358 /*
359 * VMLEN2 = HBPLEN | HFPLEN
360 *
361 * see
362 * Video mode - Blanking Packet setting
363 */
364 top = 0x00010000;
365 bottom = 0x00000001;
366 delay = 0;
367
368 if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */
369 top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin;
370 top = ((pdata->lane * top) - 10) << 16;
371 }
372 if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */
373 bottom = ch->lcd_cfg[0].right_margin;
374 bottom = (pdata->lane * bottom) - 12;
375 }
376
377 bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */
378 if (pdata->lane > bpp) {
379 tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */
380 tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */
381 delay = (pdata->lane * tmp);
382 }
383
384 iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2);
9fd04fe3
GL
385
386 msleep(5);
387
388 /* setup LCD panel */
389
390 /* cf. drivers/video/omap/lcd_mipid.c */
391 sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE);
392 msleep(120);
393 /*
394 * [7] - Page Address Mode
395 * [6] - Column Address Mode
396 * [5] - Page / Column Address Mode
397 * [4] - Display Device Line Refresh Order
398 * [3] - RGB/BGR Order
399 * [2] - Display Data Latch Data Order
400 * [1] - Flip Horizontal
401 * [0] - Flip Vertical
402 */
403 sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
404 /* cf. set_data_lines() */
405 sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT,
406 pixfmt << 4);
407 sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
408
409 return 0;
410}
411
412static int __init sh_mipi_probe(struct platform_device *pdev)
413{
414 struct sh_mipi *mipi;
415 struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
416 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
deaba190 417 struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
9fd04fe3
GL
418 unsigned long rate, f_current;
419 int idx = pdev->id, ret;
9fd04fe3 420
deaba190 421 if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
9fd04fe3
GL
422 return -ENODEV;
423
424 mutex_lock(&array_lock);
425 if (idx < 0)
426 for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
427 ;
428
429 if (idx == ARRAY_SIZE(mipi_dsi)) {
430 ret = -EBUSY;
431 goto efindslot;
432 }
433
434 mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
435 if (!mipi) {
436 ret = -ENOMEM;
437 goto ealloc;
438 }
439
440 if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
441 dev_err(&pdev->dev, "MIPI register region already claimed\n");
442 ret = -EBUSY;
443 goto ereqreg;
444 }
445
446 mipi->base = ioremap(res->start, resource_size(res));
447 if (!mipi->base) {
448 ret = -ENOMEM;
449 goto emap;
450 }
451
deaba190
MD
452 if (!request_mem_region(res2->start, resource_size(res2), pdev->name)) {
453 dev_err(&pdev->dev, "MIPI register region 2 already claimed\n");
454 ret = -EBUSY;
455 goto ereqreg2;
456 }
457
458 mipi->linkbase = ioremap(res2->start, resource_size(res2));
459 if (!mipi->linkbase) {
460 ret = -ENOMEM;
461 goto emap2;
462 }
463
236782a5
GL
464 mipi->dev = &pdev->dev;
465
9fd04fe3
GL
466 mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
467 if (IS_ERR(mipi->dsit_clk)) {
468 ret = PTR_ERR(mipi->dsit_clk);
469 goto eclktget;
470 }
471
472 f_current = clk_get_rate(mipi->dsit_clk);
473 /* 80MHz required by the datasheet */
474 rate = clk_round_rate(mipi->dsit_clk, 80000000);
475 if (rate > 0 && rate != f_current)
476 ret = clk_set_rate(mipi->dsit_clk, rate);
477 else
478 ret = rate;
479 if (ret < 0)
480 goto esettrate;
481
482 dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate);
483
9250741e 484 mipi->dsip_clk = clk_get(&pdev->dev, "dsip_clk");
9fd04fe3
GL
485 if (IS_ERR(mipi->dsip_clk)) {
486 ret = PTR_ERR(mipi->dsip_clk);
487 goto eclkpget;
488 }
489
490 f_current = clk_get_rate(mipi->dsip_clk);
491 /* Between 10 and 50MHz */
492 rate = clk_round_rate(mipi->dsip_clk, 24000000);
493 if (rate > 0 && rate != f_current)
494 ret = clk_set_rate(mipi->dsip_clk, rate);
495 else
496 ret = rate;
497 if (ret < 0)
498 goto esetprate;
499
500 dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate);
501
502 msleep(10);
503
504 ret = clk_enable(mipi->dsit_clk);
505 if (ret < 0)
506 goto eclkton;
507
508 ret = clk_enable(mipi->dsip_clk);
509 if (ret < 0)
510 goto eclkpon;
511
512 mipi_dsi[idx] = mipi;
513
236782a5
GL
514 pm_runtime_enable(&pdev->dev);
515 pm_runtime_resume(&pdev->dev);
516
9fd04fe3
GL
517 ret = sh_mipi_setup(mipi, pdata);
518 if (ret < 0)
519 goto emipisetup;
520
521 mutex_unlock(&array_lock);
522 platform_set_drvdata(pdev, mipi);
523
6722a401
MD
524 /* Save original LCDC callbacks */
525 mipi->next_board_data = pdata->lcd_chan->board_cfg.board_data;
526 mipi->next_display_on = pdata->lcd_chan->board_cfg.display_on;
527 mipi->next_display_off = pdata->lcd_chan->board_cfg.display_off;
528
9fd04fe3
GL
529 /* Set up LCDC callbacks */
530 pdata->lcd_chan->board_cfg.board_data = mipi;
531 pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
532 pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
236782a5 533 pdata->lcd_chan->board_cfg.owner = THIS_MODULE;
9fd04fe3
GL
534
535 return 0;
536
537emipisetup:
538 mipi_dsi[idx] = NULL;
236782a5 539 pm_runtime_disable(&pdev->dev);
9fd04fe3
GL
540 clk_disable(mipi->dsip_clk);
541eclkpon:
542 clk_disable(mipi->dsit_clk);
543eclkton:
544esetprate:
545 clk_put(mipi->dsip_clk);
546eclkpget:
547esettrate:
548 clk_put(mipi->dsit_clk);
549eclktget:
deaba190
MD
550 iounmap(mipi->linkbase);
551emap2:
552 release_mem_region(res2->start, resource_size(res2));
553ereqreg2:
9fd04fe3
GL
554 iounmap(mipi->base);
555emap:
556 release_mem_region(res->start, resource_size(res));
557ereqreg:
558 kfree(mipi);
559ealloc:
560efindslot:
561 mutex_unlock(&array_lock);
562
563 return ret;
564}
565
566static int __exit sh_mipi_remove(struct platform_device *pdev)
567{
568 struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
569 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
deaba190 570 struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
9fd04fe3
GL
571 struct sh_mipi *mipi = platform_get_drvdata(pdev);
572 int i, ret;
573
574 mutex_lock(&array_lock);
575
576 for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++)
577 ;
578
579 if (i == ARRAY_SIZE(mipi_dsi)) {
580 ret = -EINVAL;
581 } else {
582 ret = 0;
583 mipi_dsi[i] = NULL;
584 }
585
586 mutex_unlock(&array_lock);
587
588 if (ret < 0)
589 return ret;
590
236782a5 591 pdata->lcd_chan->board_cfg.owner = NULL;
9fd04fe3
GL
592 pdata->lcd_chan->board_cfg.display_on = NULL;
593 pdata->lcd_chan->board_cfg.display_off = NULL;
594 pdata->lcd_chan->board_cfg.board_data = NULL;
595
236782a5 596 pm_runtime_disable(&pdev->dev);
9fd04fe3
GL
597 clk_disable(mipi->dsip_clk);
598 clk_disable(mipi->dsit_clk);
599 clk_put(mipi->dsit_clk);
600 clk_put(mipi->dsip_clk);
deaba190
MD
601 iounmap(mipi->linkbase);
602 if (res2)
603 release_mem_region(res2->start, resource_size(res2));
9fd04fe3
GL
604 iounmap(mipi->base);
605 if (res)
606 release_mem_region(res->start, resource_size(res));
607 platform_set_drvdata(pdev, NULL);
608 kfree(mipi);
609
610 return 0;
611}
612
613static struct platform_driver sh_mipi_driver = {
614 .remove = __exit_p(sh_mipi_remove),
615 .shutdown = sh_mipi_shutdown,
616 .driver = {
617 .name = "sh-mipi-dsi",
618 },
619};
620
621static int __init sh_mipi_init(void)
622{
623 return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
624}
625module_init(sh_mipi_init);
626
627static void __exit sh_mipi_exit(void)
628{
629 platform_driver_unregister(&sh_mipi_driver);
630}
631module_exit(sh_mipi_exit);
632
633MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
634MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
635MODULE_LICENSE("GPL v2");
This page took 0.128369 seconds and 5 git commands to generate.