Merge tag 'dt2-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[deliverable/linux.git] / drivers / gpu / drm / exynos / exynos_drm_vidi.c
1 /* exynos_drm_vidi.c
2 *
3 * Copyright (C) 2012 Samsung Electronics Co.Ltd
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13 #include <drm/drmP.h>
14
15 #include <linux/kernel.h>
16 #include <linux/platform_device.h>
17 #include <linux/component.h>
18
19 #include <drm/exynos_drm.h>
20
21 #include <drm/drm_edid.h>
22 #include <drm/drm_crtc_helper.h>
23
24 #include "exynos_drm_drv.h"
25 #include "exynos_drm_crtc.h"
26 #include "exynos_drm_encoder.h"
27 #include "exynos_drm_vidi.h"
28
29 /* vidi has totally three virtual windows. */
30 #define WINDOWS_NR 3
31
32 #define ctx_from_connector(c) container_of(c, struct vidi_context, \
33 connector)
34
35 struct vidi_win_data {
36 unsigned int offset_x;
37 unsigned int offset_y;
38 unsigned int ovl_width;
39 unsigned int ovl_height;
40 unsigned int fb_width;
41 unsigned int fb_height;
42 unsigned int bpp;
43 dma_addr_t dma_addr;
44 unsigned int buf_offsize;
45 unsigned int line_size; /* bytes */
46 bool enabled;
47 };
48
49 struct vidi_context {
50 struct exynos_drm_manager manager;
51 struct exynos_drm_display display;
52 struct platform_device *pdev;
53 struct drm_device *drm_dev;
54 struct drm_crtc *crtc;
55 struct drm_encoder *encoder;
56 struct drm_connector connector;
57 struct vidi_win_data win_data[WINDOWS_NR];
58 struct edid *raw_edid;
59 unsigned int clkdiv;
60 unsigned int default_win;
61 unsigned long irq_flags;
62 unsigned int connected;
63 bool vblank_on;
64 bool suspended;
65 bool direct_vblank;
66 struct work_struct work;
67 struct mutex lock;
68 int pipe;
69 };
70
71 static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
72 {
73 return container_of(m, struct vidi_context, manager);
74 }
75
76 static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
77 {
78 return container_of(d, struct vidi_context, display);
79 }
80
81 static const char fake_edid_info[] = {
82 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
83 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
84 0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
85 0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
86 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
87 0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
88 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
89 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
90 0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
91 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
92 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
93 0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
94 0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
95 0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
96 0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
97 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
98 0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
99 0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x06
104 };
105
106 static void vidi_apply(struct exynos_drm_manager *mgr)
107 {
108 struct vidi_context *ctx = manager_to_vidi(mgr);
109 struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
110 struct vidi_win_data *win_data;
111 int i;
112
113 for (i = 0; i < WINDOWS_NR; i++) {
114 win_data = &ctx->win_data[i];
115 if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
116 mgr_ops->win_commit(mgr, i);
117 }
118
119 if (mgr_ops && mgr_ops->commit)
120 mgr_ops->commit(mgr);
121 }
122
123 static void vidi_commit(struct exynos_drm_manager *mgr)
124 {
125 struct vidi_context *ctx = manager_to_vidi(mgr);
126
127 if (ctx->suspended)
128 return;
129 }
130
131 static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
132 {
133 struct vidi_context *ctx = manager_to_vidi(mgr);
134
135 if (ctx->suspended)
136 return -EPERM;
137
138 if (!test_and_set_bit(0, &ctx->irq_flags))
139 ctx->vblank_on = true;
140
141 ctx->direct_vblank = true;
142
143 /*
144 * in case of page flip request, vidi_finish_pageflip function
145 * will not be called because direct_vblank is true and then
146 * that function will be called by manager_ops->win_commit callback
147 */
148 schedule_work(&ctx->work);
149
150 return 0;
151 }
152
153 static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
154 {
155 struct vidi_context *ctx = manager_to_vidi(mgr);
156
157 if (ctx->suspended)
158 return;
159
160 if (test_and_clear_bit(0, &ctx->irq_flags))
161 ctx->vblank_on = false;
162 }
163
164 static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
165 struct exynos_drm_overlay *overlay)
166 {
167 struct vidi_context *ctx = manager_to_vidi(mgr);
168 struct vidi_win_data *win_data;
169 int win;
170 unsigned long offset;
171
172 if (!overlay) {
173 DRM_ERROR("overlay is NULL\n");
174 return;
175 }
176
177 win = overlay->zpos;
178 if (win == DEFAULT_ZPOS)
179 win = ctx->default_win;
180
181 if (win < 0 || win >= WINDOWS_NR)
182 return;
183
184 offset = overlay->fb_x * (overlay->bpp >> 3);
185 offset += overlay->fb_y * overlay->pitch;
186
187 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
188
189 win_data = &ctx->win_data[win];
190
191 win_data->offset_x = overlay->crtc_x;
192 win_data->offset_y = overlay->crtc_y;
193 win_data->ovl_width = overlay->crtc_width;
194 win_data->ovl_height = overlay->crtc_height;
195 win_data->fb_width = overlay->fb_width;
196 win_data->fb_height = overlay->fb_height;
197 win_data->dma_addr = overlay->dma_addr[0] + offset;
198 win_data->bpp = overlay->bpp;
199 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
200 (overlay->bpp >> 3);
201 win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
202
203 /*
204 * some parts of win_data should be transferred to user side
205 * through specific ioctl.
206 */
207
208 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
209 win_data->offset_x, win_data->offset_y);
210 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
211 win_data->ovl_width, win_data->ovl_height);
212 DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
213 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
214 overlay->fb_width, overlay->crtc_width);
215 }
216
217 static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
218 {
219 struct vidi_context *ctx = manager_to_vidi(mgr);
220 struct vidi_win_data *win_data;
221 int win = zpos;
222
223 if (ctx->suspended)
224 return;
225
226 if (win == DEFAULT_ZPOS)
227 win = ctx->default_win;
228
229 if (win < 0 || win >= WINDOWS_NR)
230 return;
231
232 win_data = &ctx->win_data[win];
233
234 win_data->enabled = true;
235
236 DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
237
238 if (ctx->vblank_on)
239 schedule_work(&ctx->work);
240 }
241
242 static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
243 {
244 struct vidi_context *ctx = manager_to_vidi(mgr);
245 struct vidi_win_data *win_data;
246 int win = zpos;
247
248 if (win == DEFAULT_ZPOS)
249 win = ctx->default_win;
250
251 if (win < 0 || win >= WINDOWS_NR)
252 return;
253
254 win_data = &ctx->win_data[win];
255 win_data->enabled = false;
256
257 /* TODO. */
258 }
259
260 static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
261 {
262 struct vidi_context *ctx = manager_to_vidi(mgr);
263
264 DRM_DEBUG_KMS("%s\n", __FILE__);
265
266 if (enable != false && enable != true)
267 return -EINVAL;
268
269 if (enable) {
270 ctx->suspended = false;
271
272 /* if vblank was enabled status, enable it again. */
273 if (test_and_clear_bit(0, &ctx->irq_flags))
274 vidi_enable_vblank(mgr);
275
276 vidi_apply(mgr);
277 } else {
278 ctx->suspended = true;
279 }
280
281 return 0;
282 }
283
284 static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
285 {
286 struct vidi_context *ctx = manager_to_vidi(mgr);
287
288 DRM_DEBUG_KMS("%d\n", mode);
289
290 mutex_lock(&ctx->lock);
291
292 switch (mode) {
293 case DRM_MODE_DPMS_ON:
294 vidi_power_on(mgr, true);
295 break;
296 case DRM_MODE_DPMS_STANDBY:
297 case DRM_MODE_DPMS_SUSPEND:
298 case DRM_MODE_DPMS_OFF:
299 vidi_power_on(mgr, false);
300 break;
301 default:
302 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
303 break;
304 }
305
306 mutex_unlock(&ctx->lock);
307 }
308
309 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
310 struct drm_device *drm_dev)
311 {
312 struct vidi_context *ctx = manager_to_vidi(mgr);
313 struct exynos_drm_private *priv = drm_dev->dev_private;
314
315 mgr->drm_dev = ctx->drm_dev = drm_dev;
316 mgr->pipe = ctx->pipe = priv->pipe++;
317
318 return 0;
319 }
320
321 static struct exynos_drm_manager_ops vidi_manager_ops = {
322 .dpms = vidi_dpms,
323 .commit = vidi_commit,
324 .enable_vblank = vidi_enable_vblank,
325 .disable_vblank = vidi_disable_vblank,
326 .win_mode_set = vidi_win_mode_set,
327 .win_commit = vidi_win_commit,
328 .win_disable = vidi_win_disable,
329 };
330
331 static void vidi_fake_vblank_handler(struct work_struct *work)
332 {
333 struct vidi_context *ctx = container_of(work, struct vidi_context,
334 work);
335
336 if (ctx->pipe < 0)
337 return;
338
339 /* refresh rate is about 50Hz. */
340 usleep_range(16000, 20000);
341
342 mutex_lock(&ctx->lock);
343
344 if (ctx->direct_vblank) {
345 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
346 ctx->direct_vblank = false;
347 mutex_unlock(&ctx->lock);
348 return;
349 }
350
351 mutex_unlock(&ctx->lock);
352
353 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
354 }
355
356 static int vidi_show_connection(struct device *dev,
357 struct device_attribute *attr, char *buf)
358 {
359 struct vidi_context *ctx = dev_get_drvdata(dev);
360 int rc;
361
362 mutex_lock(&ctx->lock);
363
364 rc = sprintf(buf, "%d\n", ctx->connected);
365
366 mutex_unlock(&ctx->lock);
367
368 return rc;
369 }
370
371 static int vidi_store_connection(struct device *dev,
372 struct device_attribute *attr,
373 const char *buf, size_t len)
374 {
375 struct vidi_context *ctx = dev_get_drvdata(dev);
376 int ret;
377
378 ret = kstrtoint(buf, 0, &ctx->connected);
379 if (ret)
380 return ret;
381
382 if (ctx->connected > 1)
383 return -EINVAL;
384
385 /* use fake edid data for test. */
386 if (!ctx->raw_edid)
387 ctx->raw_edid = (struct edid *)fake_edid_info;
388
389 /* if raw_edid isn't same as fake data then it can't be tested. */
390 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
391 DRM_DEBUG_KMS("edid data is not fake data.\n");
392 return -EINVAL;
393 }
394
395 DRM_DEBUG_KMS("requested connection.\n");
396
397 drm_helper_hpd_irq_event(ctx->drm_dev);
398
399 return len;
400 }
401
402 static DEVICE_ATTR(connection, 0644, vidi_show_connection,
403 vidi_store_connection);
404
405 int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
406 struct drm_file *file_priv)
407 {
408 struct vidi_context *ctx = NULL;
409 struct drm_encoder *encoder;
410 struct exynos_drm_display *display;
411 struct drm_exynos_vidi_connection *vidi = data;
412
413 if (!vidi) {
414 DRM_DEBUG_KMS("user data for vidi is null.\n");
415 return -EINVAL;
416 }
417
418 if (vidi->connection > 1) {
419 DRM_DEBUG_KMS("connection should be 0 or 1.\n");
420 return -EINVAL;
421 }
422
423 list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
424 head) {
425 display = exynos_drm_get_display(encoder);
426
427 if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
428 ctx = display_to_vidi(display);
429 break;
430 }
431 }
432
433 if (!ctx) {
434 DRM_DEBUG_KMS("not found virtual device type encoder.\n");
435 return -EINVAL;
436 }
437
438 if (ctx->connected == vidi->connection) {
439 DRM_DEBUG_KMS("same connection request.\n");
440 return -EINVAL;
441 }
442
443 if (vidi->connection) {
444 struct edid *raw_edid = (struct edid *)(uint32_t)vidi->edid;
445 if (!drm_edid_is_valid(raw_edid)) {
446 DRM_DEBUG_KMS("edid data is invalid.\n");
447 return -EINVAL;
448 }
449 ctx->raw_edid = drm_edid_duplicate(raw_edid);
450 if (!ctx->raw_edid) {
451 DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
452 return -ENOMEM;
453 }
454 } else {
455 /*
456 * with connection = 0, free raw_edid
457 * only if raw edid data isn't same as fake data.
458 */
459 if (ctx->raw_edid && ctx->raw_edid !=
460 (struct edid *)fake_edid_info) {
461 kfree(ctx->raw_edid);
462 ctx->raw_edid = NULL;
463 }
464 }
465
466 ctx->connected = vidi->connection;
467 drm_helper_hpd_irq_event(ctx->drm_dev);
468
469 return 0;
470 }
471
472 static enum drm_connector_status vidi_detect(struct drm_connector *connector,
473 bool force)
474 {
475 struct vidi_context *ctx = ctx_from_connector(connector);
476
477 /*
478 * connection request would come from user side
479 * to do hotplug through specific ioctl.
480 */
481 return ctx->connected ? connector_status_connected :
482 connector_status_disconnected;
483 }
484
485 static void vidi_connector_destroy(struct drm_connector *connector)
486 {
487 }
488
489 static struct drm_connector_funcs vidi_connector_funcs = {
490 .dpms = drm_helper_connector_dpms,
491 .fill_modes = drm_helper_probe_single_connector_modes,
492 .detect = vidi_detect,
493 .destroy = vidi_connector_destroy,
494 };
495
496 static int vidi_get_modes(struct drm_connector *connector)
497 {
498 struct vidi_context *ctx = ctx_from_connector(connector);
499 struct edid *edid;
500 int edid_len;
501
502 /*
503 * the edid data comes from user side and it would be set
504 * to ctx->raw_edid through specific ioctl.
505 */
506 if (!ctx->raw_edid) {
507 DRM_DEBUG_KMS("raw_edid is null.\n");
508 return -EFAULT;
509 }
510
511 edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
512 edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
513 if (!edid) {
514 DRM_DEBUG_KMS("failed to allocate edid\n");
515 return -ENOMEM;
516 }
517
518 drm_mode_connector_update_edid_property(connector, edid);
519
520 return drm_add_edid_modes(connector, edid);
521 }
522
523 static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
524 {
525 struct vidi_context *ctx = ctx_from_connector(connector);
526
527 return ctx->encoder;
528 }
529
530 static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
531 .get_modes = vidi_get_modes,
532 .best_encoder = vidi_best_encoder,
533 };
534
535 static int vidi_create_connector(struct exynos_drm_display *display,
536 struct drm_encoder *encoder)
537 {
538 struct vidi_context *ctx = display_to_vidi(display);
539 struct drm_connector *connector = &ctx->connector;
540 int ret;
541
542 ctx->encoder = encoder;
543 connector->polled = DRM_CONNECTOR_POLL_HPD;
544
545 ret = drm_connector_init(ctx->drm_dev, connector,
546 &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
547 if (ret) {
548 DRM_ERROR("Failed to initialize connector with drm\n");
549 return ret;
550 }
551
552 drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
553 drm_connector_register(connector);
554 drm_mode_connector_attach_encoder(connector, encoder);
555
556 return 0;
557 }
558
559
560 static struct exynos_drm_display_ops vidi_display_ops = {
561 .create_connector = vidi_create_connector,
562 };
563
564 static int vidi_bind(struct device *dev, struct device *master, void *data)
565 {
566 struct vidi_context *ctx = dev_get_drvdata(dev);
567 struct drm_device *drm_dev = data;
568 struct drm_crtc *crtc = ctx->crtc;
569 int ret;
570
571 vidi_mgr_initialize(&ctx->manager, drm_dev);
572
573 ret = exynos_drm_crtc_create(&ctx->manager);
574 if (ret) {
575 DRM_ERROR("failed to create crtc.\n");
576 return ret;
577 }
578
579 ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
580 if (ret) {
581 crtc->funcs->destroy(crtc);
582 DRM_ERROR("failed to create encoder and connector.\n");
583 return ret;
584 }
585
586 return 0;
587 }
588
589
590 static void vidi_unbind(struct device *dev, struct device *master, void *data)
591 {
592 }
593
594 static const struct component_ops vidi_component_ops = {
595 .bind = vidi_bind,
596 .unbind = vidi_unbind,
597 };
598
599 static int vidi_probe(struct platform_device *pdev)
600 {
601 struct vidi_context *ctx;
602 int ret;
603
604 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
605 if (!ctx)
606 return -ENOMEM;
607
608 ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
609 ctx->manager.ops = &vidi_manager_ops;
610 ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
611 ctx->display.ops = &vidi_display_ops;
612 ctx->default_win = 0;
613 ctx->pdev = pdev;
614
615 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
616 ctx->manager.type);
617 if (ret)
618 return ret;
619
620 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
621 ctx->display.type);
622 if (ret)
623 goto err_del_crtc_component;
624
625 INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
626
627 mutex_init(&ctx->lock);
628
629 platform_set_drvdata(pdev, ctx);
630
631 ret = device_create_file(&pdev->dev, &dev_attr_connection);
632 if (ret < 0) {
633 DRM_ERROR("failed to create connection sysfs.\n");
634 goto err_del_conn_component;
635 }
636
637 ret = component_add(&pdev->dev, &vidi_component_ops);
638 if (ret)
639 goto err_remove_file;
640
641 return ret;
642
643 err_remove_file:
644 device_remove_file(&pdev->dev, &dev_attr_connection);
645 err_del_conn_component:
646 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
647 err_del_crtc_component:
648 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
649
650 return ret;
651 }
652
653 static int vidi_remove(struct platform_device *pdev)
654 {
655 struct vidi_context *ctx = platform_get_drvdata(pdev);
656
657 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
658 kfree(ctx->raw_edid);
659 ctx->raw_edid = NULL;
660
661 return -EINVAL;
662 }
663
664 component_del(&pdev->dev, &vidi_component_ops);
665 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
666 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
667
668 return 0;
669 }
670
671 struct platform_driver vidi_driver = {
672 .probe = vidi_probe,
673 .remove = vidi_remove,
674 .driver = {
675 .name = "exynos-drm-vidi",
676 .owner = THIS_MODULE,
677 },
678 };
679
680 int exynos_drm_probe_vidi(void)
681 {
682 struct platform_device *pdev;
683 int ret;
684
685 pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
686 if (IS_ERR(pdev))
687 return PTR_ERR(pdev);
688
689 ret = platform_driver_register(&vidi_driver);
690 if (ret) {
691 platform_device_unregister(pdev);
692 return ret;
693 }
694
695 return ret;
696 }
697
698 static int exynos_drm_remove_vidi_device(struct device *dev, void *data)
699 {
700 platform_device_unregister(to_platform_device(dev));
701
702 return 0;
703 }
704
705 void exynos_drm_remove_vidi(void)
706 {
707 int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
708 exynos_drm_remove_vidi_device);
709 /* silence compiler warning */
710 (void)ret;
711
712 platform_driver_unregister(&vidi_driver);
713 }
This page took 0.047745 seconds and 6 git commands to generate.