Version:  2.0.40 2.2.26 2.4.37 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7

Linux/drivers/media/platform/vsp1/vsp1_drv.c

  1 /*
  2  * vsp1_drv.c  --  R-Car VSP1 Driver
  3  *
  4  * Copyright (C) 2013-2015 Renesas Electronics Corporation
  5  *
  6  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2 of the License, or
 11  * (at your option) any later version.
 12  */
 13 
 14 #include <linux/clk.h>
 15 #include <linux/delay.h>
 16 #include <linux/device.h>
 17 #include <linux/interrupt.h>
 18 #include <linux/module.h>
 19 #include <linux/of.h>
 20 #include <linux/of_device.h>
 21 #include <linux/platform_device.h>
 22 #include <linux/videodev2.h>
 23 
 24 #include <media/v4l2-subdev.h>
 25 
 26 #include "vsp1.h"
 27 #include "vsp1_bru.h"
 28 #include "vsp1_dl.h"
 29 #include "vsp1_drm.h"
 30 #include "vsp1_hsit.h"
 31 #include "vsp1_lif.h"
 32 #include "vsp1_lut.h"
 33 #include "vsp1_pipe.h"
 34 #include "vsp1_rwpf.h"
 35 #include "vsp1_sru.h"
 36 #include "vsp1_uds.h"
 37 #include "vsp1_video.h"
 38 
 39 /* -----------------------------------------------------------------------------
 40  * Interrupt Handling
 41  */
 42 
 43 static irqreturn_t vsp1_irq_handler(int irq, void *data)
 44 {
 45         u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
 46         struct vsp1_device *vsp1 = data;
 47         irqreturn_t ret = IRQ_NONE;
 48         unsigned int i;
 49         u32 status;
 50 
 51         for (i = 0; i < vsp1->info->wpf_count; ++i) {
 52                 struct vsp1_rwpf *wpf = vsp1->wpf[i];
 53 
 54                 if (wpf == NULL)
 55                         continue;
 56 
 57                 status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
 58                 vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
 59 
 60                 if (status & VI6_WFP_IRQ_STA_FRE) {
 61                         vsp1_pipeline_frame_end(wpf->pipe);
 62                         ret = IRQ_HANDLED;
 63                 }
 64         }
 65 
 66         status = vsp1_read(vsp1, VI6_DISP_IRQ_STA);
 67         vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST);
 68 
 69         if (status & VI6_DISP_IRQ_STA_DST) {
 70                 vsp1_drm_display_start(vsp1);
 71                 ret = IRQ_HANDLED;
 72         }
 73 
 74         return ret;
 75 }
 76 
 77 /* -----------------------------------------------------------------------------
 78  * Entities
 79  */
 80 
 81 /*
 82  * vsp1_create_sink_links - Create links from all sources to the given sink
 83  *
 84  * This function creates media links from all valid sources to the given sink
 85  * pad. Links that would be invalid according to the VSP1 hardware capabilities
 86  * are skipped. Those include all links
 87  *
 88  * - from a UDS to a UDS (UDS entities can't be chained)
 89  * - from an entity to itself (no loops are allowed)
 90  */
 91 static int vsp1_create_sink_links(struct vsp1_device *vsp1,
 92                                   struct vsp1_entity *sink)
 93 {
 94         struct media_entity *entity = &sink->subdev.entity;
 95         struct vsp1_entity *source;
 96         unsigned int pad;
 97         int ret;
 98 
 99         list_for_each_entry(source, &vsp1->entities, list_dev) {
100                 u32 flags;
101 
102                 if (source->type == sink->type)
103                         continue;
104 
105                 if (source->type == VSP1_ENTITY_LIF ||
106                     source->type == VSP1_ENTITY_WPF)
107                         continue;
108 
109                 flags = source->type == VSP1_ENTITY_RPF &&
110                         sink->type == VSP1_ENTITY_WPF &&
111                         source->index == sink->index
112                       ? MEDIA_LNK_FL_ENABLED : 0;
113 
114                 for (pad = 0; pad < entity->num_pads; ++pad) {
115                         if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
116                                 continue;
117 
118                         ret = media_create_pad_link(&source->subdev.entity,
119                                                        source->source_pad,
120                                                        entity, pad, flags);
121                         if (ret < 0)
122                                 return ret;
123 
124                         if (flags & MEDIA_LNK_FL_ENABLED)
125                                 source->sink = entity;
126                 }
127         }
128 
129         return 0;
130 }
131 
132 static int vsp1_uapi_create_links(struct vsp1_device *vsp1)
133 {
134         struct vsp1_entity *entity;
135         unsigned int i;
136         int ret;
137 
138         list_for_each_entry(entity, &vsp1->entities, list_dev) {
139                 if (entity->type == VSP1_ENTITY_LIF ||
140                     entity->type == VSP1_ENTITY_RPF)
141                         continue;
142 
143                 ret = vsp1_create_sink_links(vsp1, entity);
144                 if (ret < 0)
145                         return ret;
146         }
147 
148         if (vsp1->info->features & VSP1_HAS_LIF) {
149                 ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
150                                             RWPF_PAD_SOURCE,
151                                             &vsp1->lif->entity.subdev.entity,
152                                             LIF_PAD_SINK, 0);
153                 if (ret < 0)
154                         return ret;
155         }
156 
157         for (i = 0; i < vsp1->info->rpf_count; ++i) {
158                 struct vsp1_rwpf *rpf = vsp1->rpf[i];
159 
160                 ret = media_create_pad_link(&rpf->video->video.entity, 0,
161                                             &rpf->entity.subdev.entity,
162                                             RWPF_PAD_SINK,
163                                             MEDIA_LNK_FL_ENABLED |
164                                             MEDIA_LNK_FL_IMMUTABLE);
165                 if (ret < 0)
166                         return ret;
167         }
168 
169         for (i = 0; i < vsp1->info->wpf_count; ++i) {
170                 /* Connect the video device to the WPF. All connections are
171                  * immutable except for the WPF0 source link if a LIF is
172                  * present.
173                  */
174                 struct vsp1_rwpf *wpf = vsp1->wpf[i];
175                 unsigned int flags = MEDIA_LNK_FL_ENABLED;
176 
177                 if (!(vsp1->info->features & VSP1_HAS_LIF) || i != 0)
178                         flags |= MEDIA_LNK_FL_IMMUTABLE;
179 
180                 ret = media_create_pad_link(&wpf->entity.subdev.entity,
181                                             RWPF_PAD_SOURCE,
182                                             &wpf->video->video.entity, 0,
183                                             flags);
184                 if (ret < 0)
185                         return ret;
186         }
187 
188         return 0;
189 }
190 
191 static void vsp1_destroy_entities(struct vsp1_device *vsp1)
192 {
193         struct vsp1_entity *entity, *_entity;
194         struct vsp1_video *video, *_video;
195 
196         list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) {
197                 list_del(&entity->list_dev);
198                 vsp1_entity_destroy(entity);
199         }
200 
201         list_for_each_entry_safe(video, _video, &vsp1->videos, list) {
202                 list_del(&video->list);
203                 vsp1_video_cleanup(video);
204         }
205 
206         v4l2_device_unregister(&vsp1->v4l2_dev);
207         media_device_unregister(&vsp1->media_dev);
208         media_device_cleanup(&vsp1->media_dev);
209 
210         if (!vsp1->info->uapi)
211                 vsp1_drm_cleanup(vsp1);
212 }
213 
214 static int vsp1_create_entities(struct vsp1_device *vsp1)
215 {
216         struct media_device *mdev = &vsp1->media_dev;
217         struct v4l2_device *vdev = &vsp1->v4l2_dev;
218         struct vsp1_entity *entity;
219         unsigned int i;
220         int ret;
221 
222         mdev->dev = vsp1->dev;
223         strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
224         snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
225                  dev_name(mdev->dev));
226         media_device_init(mdev);
227 
228         vsp1->media_ops.link_setup = vsp1_entity_link_setup;
229         /* Don't perform link validation when the userspace API is disabled as
230          * the pipeline is configured internally by the driver in that case, and
231          * its configuration can thus be trusted.
232          */
233         if (vsp1->info->uapi)
234                 vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
235 
236         vdev->mdev = mdev;
237         ret = v4l2_device_register(vsp1->dev, vdev);
238         if (ret < 0) {
239                 dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
240                         ret);
241                 goto done;
242         }
243 
244         /* Instantiate all the entities. */
245         if (vsp1->info->features & VSP1_HAS_BRU) {
246                 vsp1->bru = vsp1_bru_create(vsp1);
247                 if (IS_ERR(vsp1->bru)) {
248                         ret = PTR_ERR(vsp1->bru);
249                         goto done;
250                 }
251 
252                 list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
253         }
254 
255         vsp1->hsi = vsp1_hsit_create(vsp1, true);
256         if (IS_ERR(vsp1->hsi)) {
257                 ret = PTR_ERR(vsp1->hsi);
258                 goto done;
259         }
260 
261         list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
262 
263         vsp1->hst = vsp1_hsit_create(vsp1, false);
264         if (IS_ERR(vsp1->hst)) {
265                 ret = PTR_ERR(vsp1->hst);
266                 goto done;
267         }
268 
269         list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
270 
271         if (vsp1->info->features & VSP1_HAS_LIF) {
272                 vsp1->lif = vsp1_lif_create(vsp1);
273                 if (IS_ERR(vsp1->lif)) {
274                         ret = PTR_ERR(vsp1->lif);
275                         goto done;
276                 }
277 
278                 list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
279         }
280 
281         if (vsp1->info->features & VSP1_HAS_LUT) {
282                 vsp1->lut = vsp1_lut_create(vsp1);
283                 if (IS_ERR(vsp1->lut)) {
284                         ret = PTR_ERR(vsp1->lut);
285                         goto done;
286                 }
287 
288                 list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
289         }
290 
291         for (i = 0; i < vsp1->info->rpf_count; ++i) {
292                 struct vsp1_rwpf *rpf;
293 
294                 rpf = vsp1_rpf_create(vsp1, i);
295                 if (IS_ERR(rpf)) {
296                         ret = PTR_ERR(rpf);
297                         goto done;
298                 }
299 
300                 vsp1->rpf[i] = rpf;
301                 list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
302 
303                 if (vsp1->info->uapi) {
304                         struct vsp1_video *video = vsp1_video_create(vsp1, rpf);
305 
306                         if (IS_ERR(video)) {
307                                 ret = PTR_ERR(video);
308                                 goto done;
309                         }
310 
311                         list_add_tail(&video->list, &vsp1->videos);
312                 }
313         }
314 
315         if (vsp1->info->features & VSP1_HAS_SRU) {
316                 vsp1->sru = vsp1_sru_create(vsp1);
317                 if (IS_ERR(vsp1->sru)) {
318                         ret = PTR_ERR(vsp1->sru);
319                         goto done;
320                 }
321 
322                 list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
323         }
324 
325         for (i = 0; i < vsp1->info->uds_count; ++i) {
326                 struct vsp1_uds *uds;
327 
328                 uds = vsp1_uds_create(vsp1, i);
329                 if (IS_ERR(uds)) {
330                         ret = PTR_ERR(uds);
331                         goto done;
332                 }
333 
334                 vsp1->uds[i] = uds;
335                 list_add_tail(&uds->entity.list_dev, &vsp1->entities);
336         }
337 
338         for (i = 0; i < vsp1->info->wpf_count; ++i) {
339                 struct vsp1_rwpf *wpf;
340 
341                 wpf = vsp1_wpf_create(vsp1, i);
342                 if (IS_ERR(wpf)) {
343                         ret = PTR_ERR(wpf);
344                         goto done;
345                 }
346 
347                 vsp1->wpf[i] = wpf;
348                 list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
349 
350                 if (vsp1->info->uapi) {
351                         struct vsp1_video *video = vsp1_video_create(vsp1, wpf);
352 
353                         if (IS_ERR(video)) {
354                                 ret = PTR_ERR(video);
355                                 goto done;
356                         }
357 
358                         list_add_tail(&video->list, &vsp1->videos);
359                         wpf->entity.sink = &video->video.entity;
360                 }
361         }
362 
363         /* Register all subdevs. */
364         list_for_each_entry(entity, &vsp1->entities, list_dev) {
365                 ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
366                                                   &entity->subdev);
367                 if (ret < 0)
368                         goto done;
369         }
370 
371         /* Create links. */
372         if (vsp1->info->uapi)
373                 ret = vsp1_uapi_create_links(vsp1);
374         else
375                 ret = vsp1_drm_create_links(vsp1);
376         if (ret < 0)
377                 goto done;
378 
379         /* Register subdev nodes if the userspace API is enabled or initialize
380          * the DRM pipeline otherwise.
381          */
382         if (vsp1->info->uapi)
383                 ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
384         else
385                 ret = vsp1_drm_init(vsp1);
386         if (ret < 0)
387                 goto done;
388 
389         ret = media_device_register(mdev);
390 
391 done:
392         if (ret < 0)
393                 vsp1_destroy_entities(vsp1);
394 
395         return ret;
396 }
397 
398 int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
399 {
400         unsigned int timeout;
401         u32 status;
402 
403         status = vsp1_read(vsp1, VI6_STATUS);
404         if (!(status & VI6_STATUS_SYS_ACT(index)))
405                 return 0;
406 
407         vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
408         for (timeout = 10; timeout > 0; --timeout) {
409                 status = vsp1_read(vsp1, VI6_STATUS);
410                 if (!(status & VI6_STATUS_SYS_ACT(index)))
411                         break;
412 
413                 usleep_range(1000, 2000);
414         }
415 
416         if (!timeout) {
417                 dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
418                 return -ETIMEDOUT;
419         }
420 
421         return 0;
422 }
423 
424 static int vsp1_device_init(struct vsp1_device *vsp1)
425 {
426         unsigned int i;
427         int ret;
428 
429         /* Reset any channel that might be running. */
430         for (i = 0; i < vsp1->info->wpf_count; ++i) {
431                 ret = vsp1_reset_wpf(vsp1, i);
432                 if (ret < 0)
433                         return ret;
434         }
435 
436         vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
437                    (8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
438 
439         for (i = 0; i < vsp1->info->rpf_count; ++i)
440                 vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
441 
442         for (i = 0; i < vsp1->info->uds_count; ++i)
443                 vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
444 
445         vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
446         vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
447         vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
448         vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
449         vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
450         vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
451 
452         vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
453                    (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
454         vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
455                    (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
456 
457         vsp1_dlm_setup(vsp1);
458 
459         return 0;
460 }
461 
462 /*
463  * vsp1_device_get - Acquire the VSP1 device
464  *
465  * Increment the VSP1 reference count and initialize the device if the first
466  * reference is taken.
467  *
468  * Return 0 on success or a negative error code otherwise.
469  */
470 int vsp1_device_get(struct vsp1_device *vsp1)
471 {
472         int ret = 0;
473 
474         mutex_lock(&vsp1->lock);
475         if (vsp1->ref_count > 0)
476                 goto done;
477 
478         ret = clk_prepare_enable(vsp1->clock);
479         if (ret < 0)
480                 goto done;
481 
482         ret = vsp1_device_init(vsp1);
483         if (ret < 0) {
484                 clk_disable_unprepare(vsp1->clock);
485                 goto done;
486         }
487 
488 done:
489         if (!ret)
490                 vsp1->ref_count++;
491 
492         mutex_unlock(&vsp1->lock);
493         return ret;
494 }
495 
496 /*
497  * vsp1_device_put - Release the VSP1 device
498  *
499  * Decrement the VSP1 reference count and cleanup the device if the last
500  * reference is released.
501  */
502 void vsp1_device_put(struct vsp1_device *vsp1)
503 {
504         mutex_lock(&vsp1->lock);
505 
506         if (--vsp1->ref_count == 0)
507                 clk_disable_unprepare(vsp1->clock);
508 
509         mutex_unlock(&vsp1->lock);
510 }
511 
512 /* -----------------------------------------------------------------------------
513  * Power Management
514  */
515 
516 #ifdef CONFIG_PM_SLEEP
517 static int vsp1_pm_suspend(struct device *dev)
518 {
519         struct vsp1_device *vsp1 = dev_get_drvdata(dev);
520 
521         WARN_ON(mutex_is_locked(&vsp1->lock));
522 
523         if (vsp1->ref_count == 0)
524                 return 0;
525 
526         vsp1_pipelines_suspend(vsp1);
527 
528         clk_disable_unprepare(vsp1->clock);
529 
530         return 0;
531 }
532 
533 static int vsp1_pm_resume(struct device *dev)
534 {
535         struct vsp1_device *vsp1 = dev_get_drvdata(dev);
536 
537         WARN_ON(mutex_is_locked(&vsp1->lock));
538 
539         if (vsp1->ref_count == 0)
540                 return 0;
541 
542         clk_prepare_enable(vsp1->clock);
543 
544         vsp1_pipelines_resume(vsp1);
545 
546         return 0;
547 }
548 #endif
549 
550 static const struct dev_pm_ops vsp1_pm_ops = {
551         SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
552 };
553 
554 /* -----------------------------------------------------------------------------
555  * Platform Driver
556  */
557 
558 static const struct vsp1_device_info vsp1_device_infos[] = {
559         {
560                 .version = VI6_IP_VERSION_MODEL_VSPS_H2,
561                 .gen = 2,
562                 .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
563                 .rpf_count = 5,
564                 .uds_count = 3,
565                 .wpf_count = 4,
566                 .num_bru_inputs = 4,
567                 .uapi = true,
568         }, {
569                 .version = VI6_IP_VERSION_MODEL_VSPR_H2,
570                 .gen = 2,
571                 .features = VSP1_HAS_BRU | VSP1_HAS_SRU,
572                 .rpf_count = 5,
573                 .uds_count = 1,
574                 .wpf_count = 4,
575                 .num_bru_inputs = 4,
576                 .uapi = true,
577         }, {
578                 .version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
579                 .gen = 2,
580                 .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
581                 .rpf_count = 4,
582                 .uds_count = 1,
583                 .wpf_count = 4,
584                 .num_bru_inputs = 4,
585                 .uapi = true,
586         }, {
587                 .version = VI6_IP_VERSION_MODEL_VSPS_M2,
588                 .gen = 2,
589                 .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
590                 .rpf_count = 5,
591                 .uds_count = 3,
592                 .wpf_count = 4,
593                 .num_bru_inputs = 4,
594                 .uapi = true,
595         }, {
596                 .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
597                 .gen = 3,
598                 .features = VSP1_HAS_LUT | VSP1_HAS_SRU,
599                 .rpf_count = 1,
600                 .uds_count = 1,
601                 .wpf_count = 1,
602                 .uapi = true,
603         }, {
604                 .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
605                 .gen = 3,
606                 .features = VSP1_HAS_BRU,
607                 .rpf_count = 5,
608                 .wpf_count = 1,
609                 .num_bru_inputs = 5,
610                 .uapi = true,
611         }, {
612                 .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
613                 .gen = 3,
614                 .features = VSP1_HAS_BRU | VSP1_HAS_LUT,
615                 .rpf_count = 5,
616                 .wpf_count = 1,
617                 .num_bru_inputs = 5,
618                 .uapi = true,
619         }, {
620                 .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
621                 .gen = 3,
622                 .features = VSP1_HAS_BRU | VSP1_HAS_LIF,
623                 .rpf_count = 5,
624                 .wpf_count = 2,
625                 .num_bru_inputs = 5,
626         },
627 };
628 
629 static int vsp1_probe(struct platform_device *pdev)
630 {
631         struct vsp1_device *vsp1;
632         struct resource *irq;
633         struct resource *io;
634         unsigned int i;
635         u32 version;
636         int ret;
637 
638         vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
639         if (vsp1 == NULL)
640                 return -ENOMEM;
641 
642         vsp1->dev = &pdev->dev;
643         mutex_init(&vsp1->lock);
644         INIT_LIST_HEAD(&vsp1->entities);
645         INIT_LIST_HEAD(&vsp1->videos);
646 
647         /* I/O, IRQ and clock resources */
648         io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
649         vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
650         if (IS_ERR(vsp1->mmio))
651                 return PTR_ERR(vsp1->mmio);
652 
653         vsp1->clock = devm_clk_get(&pdev->dev, NULL);
654         if (IS_ERR(vsp1->clock)) {
655                 dev_err(&pdev->dev, "failed to get clock\n");
656                 return PTR_ERR(vsp1->clock);
657         }
658 
659         irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
660         if (!irq) {
661                 dev_err(&pdev->dev, "missing IRQ\n");
662                 return -EINVAL;
663         }
664 
665         ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
666                               IRQF_SHARED, dev_name(&pdev->dev), vsp1);
667         if (ret < 0) {
668                 dev_err(&pdev->dev, "failed to request IRQ\n");
669                 return ret;
670         }
671 
672         /* Configure device parameters based on the version register. */
673         ret = clk_prepare_enable(vsp1->clock);
674         if (ret < 0)
675                 return ret;
676 
677         version = vsp1_read(vsp1, VI6_IP_VERSION);
678         clk_disable_unprepare(vsp1->clock);
679 
680         for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
681                 if ((version & VI6_IP_VERSION_MODEL_MASK) ==
682                     vsp1_device_infos[i].version) {
683                         vsp1->info = &vsp1_device_infos[i];
684                         break;
685                 }
686         }
687 
688         if (!vsp1->info) {
689                 dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version);
690                 return -ENXIO;
691         }
692 
693         dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
694 
695         /* Instanciate entities */
696         ret = vsp1_create_entities(vsp1);
697         if (ret < 0) {
698                 dev_err(&pdev->dev, "failed to create entities\n");
699                 return ret;
700         }
701 
702         platform_set_drvdata(pdev, vsp1);
703 
704         return 0;
705 }
706 
707 static int vsp1_remove(struct platform_device *pdev)
708 {
709         struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
710 
711         vsp1_destroy_entities(vsp1);
712 
713         return 0;
714 }
715 
716 static const struct of_device_id vsp1_of_match[] = {
717         { .compatible = "renesas,vsp1" },
718         { .compatible = "renesas,vsp2" },
719         { },
720 };
721 
722 static struct platform_driver vsp1_platform_driver = {
723         .probe          = vsp1_probe,
724         .remove         = vsp1_remove,
725         .driver         = {
726                 .name   = "vsp1",
727                 .pm     = &vsp1_pm_ops,
728                 .of_match_table = vsp1_of_match,
729         },
730 };
731 
732 module_platform_driver(vsp1_platform_driver);
733 
734 MODULE_ALIAS("vsp1");
735 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
736 MODULE_DESCRIPTION("Renesas VSP1 Driver");
737 MODULE_LICENSE("GPL");
738 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us