linux/drivers/media/platform/rcar-vin/rcar-v4l2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Driver for Renesas R-Car VIN
   4 *
   5 * Copyright (C) 2016 Renesas Electronics Corp.
   6 * Copyright (C) 2011-2013 Renesas Solutions Corp.
   7 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
   8 * Copyright (C) 2008 Magnus Damm
   9 *
  10 * Based on the soc-camera rcar_vin driver
  11 */
  12
  13#include <linux/pm_runtime.h>
  14
  15#include <media/v4l2-event.h>
  16#include <media/v4l2-ioctl.h>
  17#include <media/v4l2-mc.h>
  18#include <media/v4l2-rect.h>
  19
  20#include "rcar-vin.h"
  21
  22#define RVIN_DEFAULT_FORMAT     V4L2_PIX_FMT_YUYV
  23#define RVIN_DEFAULT_WIDTH      800
  24#define RVIN_DEFAULT_HEIGHT     600
  25#define RVIN_DEFAULT_FIELD      V4L2_FIELD_NONE
  26#define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB
  27
  28/* -----------------------------------------------------------------------------
  29 * Format Conversions
  30 */
  31
  32static const struct rvin_video_format rvin_formats[] = {
  33        {
  34                .fourcc                 = V4L2_PIX_FMT_NV16,
  35                .bpp                    = 1,
  36        },
  37        {
  38                .fourcc                 = V4L2_PIX_FMT_YUYV,
  39                .bpp                    = 2,
  40        },
  41        {
  42                .fourcc                 = V4L2_PIX_FMT_UYVY,
  43                .bpp                    = 2,
  44        },
  45        {
  46                .fourcc                 = V4L2_PIX_FMT_RGB565,
  47                .bpp                    = 2,
  48        },
  49        {
  50                .fourcc                 = V4L2_PIX_FMT_XRGB555,
  51                .bpp                    = 2,
  52        },
  53        {
  54                .fourcc                 = V4L2_PIX_FMT_XBGR32,
  55                .bpp                    = 4,
  56        },
  57};
  58
  59const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat)
  60{
  61        int i;
  62
  63        for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
  64                if (rvin_formats[i].fourcc == pixelformat)
  65                        return rvin_formats + i;
  66
  67        return NULL;
  68}
  69
  70static u32 rvin_format_bytesperline(struct v4l2_pix_format *pix)
  71{
  72        const struct rvin_video_format *fmt;
  73
  74        fmt = rvin_format_from_pixel(pix->pixelformat);
  75
  76        if (WARN_ON(!fmt))
  77                return -EINVAL;
  78
  79        return pix->width * fmt->bpp;
  80}
  81
  82static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
  83{
  84        if (pix->pixelformat == V4L2_PIX_FMT_NV16)
  85                return pix->bytesperline * pix->height * 2;
  86
  87        return pix->bytesperline * pix->height;
  88}
  89
  90static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
  91{
  92        u32 walign;
  93
  94        if (!rvin_format_from_pixel(pix->pixelformat) ||
  95            (vin->info->model == RCAR_M1 &&
  96             pix->pixelformat == V4L2_PIX_FMT_XBGR32))
  97                pix->pixelformat = RVIN_DEFAULT_FORMAT;
  98
  99        switch (pix->field) {
 100        case V4L2_FIELD_TOP:
 101        case V4L2_FIELD_BOTTOM:
 102        case V4L2_FIELD_NONE:
 103        case V4L2_FIELD_INTERLACED_TB:
 104        case V4L2_FIELD_INTERLACED_BT:
 105        case V4L2_FIELD_INTERLACED:
 106                break;
 107        case V4L2_FIELD_ALTERNATE:
 108                /*
 109                 * Driver does not (yet) support outputting ALTERNATE to a
 110                 * userspace. It does support outputting INTERLACED so use
 111                 * the VIN hardware to combine the two fields.
 112                 */
 113                pix->field = V4L2_FIELD_INTERLACED;
 114                pix->height *= 2;
 115                break;
 116        default:
 117                pix->field = RVIN_DEFAULT_FIELD;
 118                break;
 119        }
 120
 121        /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */
 122        walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1;
 123
 124        /* Limit to VIN capabilities */
 125        v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
 126                              &pix->height, 4, vin->info->max_height, 2, 0);
 127
 128        pix->bytesperline = rvin_format_bytesperline(pix);
 129        pix->sizeimage = rvin_format_sizeimage(pix);
 130
 131        vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
 132                pix->width, pix->height, pix->bytesperline, pix->sizeimage);
 133}
 134
 135/* -----------------------------------------------------------------------------
 136 * V4L2
 137 */
 138
 139static int rvin_reset_format(struct rvin_dev *vin)
 140{
 141        struct v4l2_subdev_format fmt = {
 142                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
 143                .pad = vin->parallel->source_pad,
 144        };
 145        int ret;
 146
 147        ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
 148        if (ret)
 149                return ret;
 150
 151        v4l2_fill_pix_format(&vin->format, &fmt.format);
 152
 153        rvin_format_align(vin, &vin->format);
 154
 155        vin->source.top = 0;
 156        vin->source.left = 0;
 157        vin->source.width = vin->format.width;
 158        vin->source.height = vin->format.height;
 159
 160        vin->crop = vin->source;
 161        vin->compose = vin->source;
 162
 163        return 0;
 164}
 165
 166static int rvin_try_format(struct rvin_dev *vin, u32 which,
 167                           struct v4l2_pix_format *pix,
 168                           struct v4l2_rect *crop, struct v4l2_rect *compose)
 169{
 170        struct v4l2_subdev *sd = vin_to_source(vin);
 171        struct v4l2_subdev_pad_config *pad_cfg;
 172        struct v4l2_subdev_format format = {
 173                .which = which,
 174                .pad = vin->parallel->source_pad,
 175        };
 176        enum v4l2_field field;
 177        u32 width, height;
 178        int ret;
 179
 180        pad_cfg = v4l2_subdev_alloc_pad_config(sd);
 181        if (pad_cfg == NULL)
 182                return -ENOMEM;
 183
 184        if (!rvin_format_from_pixel(pix->pixelformat) ||
 185            (vin->info->model == RCAR_M1 &&
 186             pix->pixelformat == V4L2_PIX_FMT_XBGR32))
 187                pix->pixelformat = RVIN_DEFAULT_FORMAT;
 188
 189        v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
 190
 191        /* Allow the video device to override field and to scale */
 192        field = pix->field;
 193        width = pix->width;
 194        height = pix->height;
 195
 196        ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
 197        if (ret < 0 && ret != -ENOIOCTLCMD)
 198                goto done;
 199
 200        v4l2_fill_pix_format(pix, &format.format);
 201
 202        if (crop) {
 203                crop->top = 0;
 204                crop->left = 0;
 205                crop->width = pix->width;
 206                crop->height = pix->height;
 207
 208                /*
 209                 * If source is ALTERNATE the driver will use the VIN hardware
 210                 * to INTERLACE it. The crop height then needs to be doubled.
 211                 */
 212                if (pix->field == V4L2_FIELD_ALTERNATE)
 213                        crop->height *= 2;
 214        }
 215
 216        if (field != V4L2_FIELD_ANY)
 217                pix->field = field;
 218
 219        pix->width = width;
 220        pix->height = height;
 221
 222        rvin_format_align(vin, pix);
 223
 224        if (compose) {
 225                compose->top = 0;
 226                compose->left = 0;
 227                compose->width = pix->width;
 228                compose->height = pix->height;
 229        }
 230done:
 231        v4l2_subdev_free_pad_config(pad_cfg);
 232
 233        return 0;
 234}
 235
 236static int rvin_querycap(struct file *file, void *priv,
 237                         struct v4l2_capability *cap)
 238{
 239        struct rvin_dev *vin = video_drvdata(file);
 240
 241        strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
 242        strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
 243        snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
 244                 dev_name(vin->dev));
 245        return 0;
 246}
 247
 248static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
 249                                struct v4l2_format *f)
 250{
 251        struct rvin_dev *vin = video_drvdata(file);
 252
 253        return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
 254                               NULL);
 255}
 256
 257static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
 258                              struct v4l2_format *f)
 259{
 260        struct rvin_dev *vin = video_drvdata(file);
 261        struct v4l2_rect crop, compose;
 262        int ret;
 263
 264        if (vb2_is_busy(&vin->queue))
 265                return -EBUSY;
 266
 267        ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
 268                              &crop, &compose);
 269        if (ret)
 270                return ret;
 271
 272        vin->format = f->fmt.pix;
 273        vin->crop = crop;
 274        vin->compose = compose;
 275        vin->source = crop;
 276
 277        return 0;
 278}
 279
 280static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
 281                              struct v4l2_format *f)
 282{
 283        struct rvin_dev *vin = video_drvdata(file);
 284
 285        f->fmt.pix = vin->format;
 286
 287        return 0;
 288}
 289
 290static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
 291                                 struct v4l2_fmtdesc *f)
 292{
 293        if (f->index >= ARRAY_SIZE(rvin_formats))
 294                return -EINVAL;
 295
 296        f->pixelformat = rvin_formats[f->index].fourcc;
 297
 298        return 0;
 299}
 300
 301static int rvin_g_selection(struct file *file, void *fh,
 302                            struct v4l2_selection *s)
 303{
 304        struct rvin_dev *vin = video_drvdata(file);
 305
 306        if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 307                return -EINVAL;
 308
 309        switch (s->target) {
 310        case V4L2_SEL_TGT_CROP_BOUNDS:
 311        case V4L2_SEL_TGT_CROP_DEFAULT:
 312                s->r.left = s->r.top = 0;
 313                s->r.width = vin->source.width;
 314                s->r.height = vin->source.height;
 315                break;
 316        case V4L2_SEL_TGT_CROP:
 317                s->r = vin->crop;
 318                break;
 319        case V4L2_SEL_TGT_COMPOSE_BOUNDS:
 320        case V4L2_SEL_TGT_COMPOSE_DEFAULT:
 321                s->r.left = s->r.top = 0;
 322                s->r.width = vin->format.width;
 323                s->r.height = vin->format.height;
 324                break;
 325        case V4L2_SEL_TGT_COMPOSE:
 326                s->r = vin->compose;
 327                break;
 328        default:
 329                return -EINVAL;
 330        }
 331
 332        return 0;
 333}
 334
 335static int rvin_s_selection(struct file *file, void *fh,
 336                            struct v4l2_selection *s)
 337{
 338        struct rvin_dev *vin = video_drvdata(file);
 339        const struct rvin_video_format *fmt;
 340        struct v4l2_rect r = s->r;
 341        struct v4l2_rect max_rect;
 342        struct v4l2_rect min_rect = {
 343                .width = 6,
 344                .height = 2,
 345        };
 346
 347        if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 348                return -EINVAL;
 349
 350        v4l2_rect_set_min_size(&r, &min_rect);
 351
 352        switch (s->target) {
 353        case V4L2_SEL_TGT_CROP:
 354                /* Can't crop outside of source input */
 355                max_rect.top = max_rect.left = 0;
 356                max_rect.width = vin->source.width;
 357                max_rect.height = vin->source.height;
 358                v4l2_rect_map_inside(&r, &max_rect);
 359
 360                v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
 361                                      &r.height, 2, vin->source.height, 0, 0);
 362
 363                r.top  = clamp_t(s32, r.top, 0, vin->source.height - r.height);
 364                r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);
 365
 366                vin->crop = s->r = r;
 367
 368                vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
 369                        r.width, r.height, r.left, r.top,
 370                        vin->source.width, vin->source.height);
 371                break;
 372        case V4L2_SEL_TGT_COMPOSE:
 373                /* Make sure compose rect fits inside output format */
 374                max_rect.top = max_rect.left = 0;
 375                max_rect.width = vin->format.width;
 376                max_rect.height = vin->format.height;
 377                v4l2_rect_map_inside(&r, &max_rect);
 378
 379                /*
 380                 * Composing is done by adding a offset to the buffer address,
 381                 * the HW wants this address to be aligned to HW_BUFFER_MASK.
 382                 * Make sure the top and left values meets this requirement.
 383                 */
 384                while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
 385                        r.top--;
 386
 387                fmt = rvin_format_from_pixel(vin->format.pixelformat);
 388                while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
 389                        r.left--;
 390
 391                vin->compose = s->r = r;
 392
 393                vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
 394                        r.width, r.height, r.left, r.top,
 395                        vin->format.width, vin->format.height);
 396                break;
 397        default:
 398                return -EINVAL;
 399        }
 400
 401        /* HW supports modifying configuration while running */
 402        rvin_crop_scale_comp(vin);
 403
 404        return 0;
 405}
 406
 407static int rvin_g_pixelaspect(struct file *file, void *priv,
 408                              int type, struct v4l2_fract *f)
 409{
 410        struct rvin_dev *vin = video_drvdata(file);
 411        struct v4l2_subdev *sd = vin_to_source(vin);
 412
 413        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 414                return -EINVAL;
 415
 416        return v4l2_subdev_call(sd, video, g_pixelaspect, f);
 417}
 418
 419static int rvin_enum_input(struct file *file, void *priv,
 420                           struct v4l2_input *i)
 421{
 422        struct rvin_dev *vin = video_drvdata(file);
 423        struct v4l2_subdev *sd = vin_to_source(vin);
 424        int ret;
 425
 426        if (i->index != 0)
 427                return -EINVAL;
 428
 429        ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
 430        if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
 431                return ret;
 432
 433        i->type = V4L2_INPUT_TYPE_CAMERA;
 434
 435        if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
 436                i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
 437                i->std = 0;
 438        } else {
 439                i->capabilities = V4L2_IN_CAP_STD;
 440                i->std = vin->vdev.tvnorms;
 441        }
 442
 443        strscpy(i->name, "Camera", sizeof(i->name));
 444
 445        return 0;
 446}
 447
 448static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
 449{
 450        *i = 0;
 451        return 0;
 452}
 453
 454static int rvin_s_input(struct file *file, void *priv, unsigned int i)
 455{
 456        if (i > 0)
 457                return -EINVAL;
 458        return 0;
 459}
 460
 461static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
 462{
 463        struct rvin_dev *vin = video_drvdata(file);
 464        struct v4l2_subdev *sd = vin_to_source(vin);
 465
 466        return v4l2_subdev_call(sd, video, querystd, a);
 467}
 468
 469static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
 470{
 471        struct rvin_dev *vin = video_drvdata(file);
 472        int ret;
 473
 474        ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
 475        if (ret < 0)
 476                return ret;
 477
 478        vin->std = a;
 479
 480        /* Changing the standard will change the width/height */
 481        return rvin_reset_format(vin);
 482}
 483
 484static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
 485{
 486        struct rvin_dev *vin = video_drvdata(file);
 487
 488        if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
 489                return -ENOIOCTLCMD;
 490
 491        *a = vin->std;
 492
 493        return 0;
 494}
 495
 496static int rvin_subscribe_event(struct v4l2_fh *fh,
 497                                const struct v4l2_event_subscription *sub)
 498{
 499        switch (sub->type) {
 500        case V4L2_EVENT_SOURCE_CHANGE:
 501                return v4l2_event_subscribe(fh, sub, 4, NULL);
 502        }
 503        return v4l2_ctrl_subscribe_event(fh, sub);
 504}
 505
 506static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
 507                                struct v4l2_enum_dv_timings *timings)
 508{
 509        struct rvin_dev *vin = video_drvdata(file);
 510        struct v4l2_subdev *sd = vin_to_source(vin);
 511        int ret;
 512
 513        if (timings->pad)
 514                return -EINVAL;
 515
 516        timings->pad = vin->parallel->sink_pad;
 517
 518        ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
 519
 520        timings->pad = 0;
 521
 522        return ret;
 523}
 524
 525static int rvin_s_dv_timings(struct file *file, void *priv_fh,
 526                             struct v4l2_dv_timings *timings)
 527{
 528        struct rvin_dev *vin = video_drvdata(file);
 529        struct v4l2_subdev *sd = vin_to_source(vin);
 530        int ret;
 531
 532        ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
 533        if (ret)
 534                return ret;
 535
 536        /* Changing the timings will change the width/height */
 537        return rvin_reset_format(vin);
 538}
 539
 540static int rvin_g_dv_timings(struct file *file, void *priv_fh,
 541                             struct v4l2_dv_timings *timings)
 542{
 543        struct rvin_dev *vin = video_drvdata(file);
 544        struct v4l2_subdev *sd = vin_to_source(vin);
 545
 546        return v4l2_subdev_call(sd, video, g_dv_timings, timings);
 547}
 548
 549static int rvin_query_dv_timings(struct file *file, void *priv_fh,
 550                                 struct v4l2_dv_timings *timings)
 551{
 552        struct rvin_dev *vin = video_drvdata(file);
 553        struct v4l2_subdev *sd = vin_to_source(vin);
 554
 555        return v4l2_subdev_call(sd, video, query_dv_timings, timings);
 556}
 557
 558static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
 559                               struct v4l2_dv_timings_cap *cap)
 560{
 561        struct rvin_dev *vin = video_drvdata(file);
 562        struct v4l2_subdev *sd = vin_to_source(vin);
 563        int ret;
 564
 565        if (cap->pad)
 566                return -EINVAL;
 567
 568        cap->pad = vin->parallel->sink_pad;
 569
 570        ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
 571
 572        cap->pad = 0;
 573
 574        return ret;
 575}
 576
 577static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
 578{
 579        struct rvin_dev *vin = video_drvdata(file);
 580        struct v4l2_subdev *sd = vin_to_source(vin);
 581        int ret;
 582
 583        if (edid->pad)
 584                return -EINVAL;
 585
 586        edid->pad = vin->parallel->sink_pad;
 587
 588        ret = v4l2_subdev_call(sd, pad, get_edid, edid);
 589
 590        edid->pad = 0;
 591
 592        return ret;
 593}
 594
 595static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
 596{
 597        struct rvin_dev *vin = video_drvdata(file);
 598        struct v4l2_subdev *sd = vin_to_source(vin);
 599        int ret;
 600
 601        if (edid->pad)
 602                return -EINVAL;
 603
 604        edid->pad = vin->parallel->sink_pad;
 605
 606        ret = v4l2_subdev_call(sd, pad, set_edid, edid);
 607
 608        edid->pad = 0;
 609
 610        return ret;
 611}
 612
 613static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
 614        .vidioc_querycap                = rvin_querycap,
 615        .vidioc_try_fmt_vid_cap         = rvin_try_fmt_vid_cap,
 616        .vidioc_g_fmt_vid_cap           = rvin_g_fmt_vid_cap,
 617        .vidioc_s_fmt_vid_cap           = rvin_s_fmt_vid_cap,
 618        .vidioc_enum_fmt_vid_cap        = rvin_enum_fmt_vid_cap,
 619
 620        .vidioc_g_selection             = rvin_g_selection,
 621        .vidioc_s_selection             = rvin_s_selection,
 622
 623        .vidioc_g_pixelaspect           = rvin_g_pixelaspect,
 624
 625        .vidioc_enum_input              = rvin_enum_input,
 626        .vidioc_g_input                 = rvin_g_input,
 627        .vidioc_s_input                 = rvin_s_input,
 628
 629        .vidioc_dv_timings_cap          = rvin_dv_timings_cap,
 630        .vidioc_enum_dv_timings         = rvin_enum_dv_timings,
 631        .vidioc_g_dv_timings            = rvin_g_dv_timings,
 632        .vidioc_s_dv_timings            = rvin_s_dv_timings,
 633        .vidioc_query_dv_timings        = rvin_query_dv_timings,
 634
 635        .vidioc_g_edid                  = rvin_g_edid,
 636        .vidioc_s_edid                  = rvin_s_edid,
 637
 638        .vidioc_querystd                = rvin_querystd,
 639        .vidioc_g_std                   = rvin_g_std,
 640        .vidioc_s_std                   = rvin_s_std,
 641
 642        .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
 643        .vidioc_create_bufs             = vb2_ioctl_create_bufs,
 644        .vidioc_querybuf                = vb2_ioctl_querybuf,
 645        .vidioc_qbuf                    = vb2_ioctl_qbuf,
 646        .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
 647        .vidioc_expbuf                  = vb2_ioctl_expbuf,
 648        .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
 649        .vidioc_streamon                = vb2_ioctl_streamon,
 650        .vidioc_streamoff               = vb2_ioctl_streamoff,
 651
 652        .vidioc_log_status              = v4l2_ctrl_log_status,
 653        .vidioc_subscribe_event         = rvin_subscribe_event,
 654        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 655};
 656
 657/* -----------------------------------------------------------------------------
 658 * V4L2 Media Controller
 659 */
 660
 661static void rvin_mc_try_format(struct rvin_dev *vin,
 662                               struct v4l2_pix_format *pix)
 663{
 664        /*
 665         * The V4L2 specification clearly documents the colorspace fields
 666         * as being set by drivers for capture devices. Using the values
 667         * supplied by userspace thus wouldn't comply with the API. Until
 668         * the API is updated force fixed values.
 669         */
 670        pix->colorspace = RVIN_DEFAULT_COLORSPACE;
 671        pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
 672        pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
 673        pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
 674                                                          pix->ycbcr_enc);
 675
 676        rvin_format_align(vin, pix);
 677}
 678
 679static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
 680                                   struct v4l2_format *f)
 681{
 682        struct rvin_dev *vin = video_drvdata(file);
 683
 684        rvin_mc_try_format(vin, &f->fmt.pix);
 685
 686        return 0;
 687}
 688
 689static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
 690                                 struct v4l2_format *f)
 691{
 692        struct rvin_dev *vin = video_drvdata(file);
 693
 694        if (vb2_is_busy(&vin->queue))
 695                return -EBUSY;
 696
 697        rvin_mc_try_format(vin, &f->fmt.pix);
 698
 699        vin->format = f->fmt.pix;
 700
 701        vin->crop.top = 0;
 702        vin->crop.left = 0;
 703        vin->crop.width = vin->format.width;
 704        vin->crop.height = vin->format.height;
 705        vin->compose = vin->crop;
 706
 707        return 0;
 708}
 709
 710static int rvin_mc_enum_input(struct file *file, void *priv,
 711                              struct v4l2_input *i)
 712{
 713        if (i->index != 0)
 714                return -EINVAL;
 715
 716        i->type = V4L2_INPUT_TYPE_CAMERA;
 717        strscpy(i->name, "Camera", sizeof(i->name));
 718
 719        return 0;
 720}
 721
 722static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
 723        .vidioc_querycap                = rvin_querycap,
 724        .vidioc_try_fmt_vid_cap         = rvin_mc_try_fmt_vid_cap,
 725        .vidioc_g_fmt_vid_cap           = rvin_g_fmt_vid_cap,
 726        .vidioc_s_fmt_vid_cap           = rvin_mc_s_fmt_vid_cap,
 727        .vidioc_enum_fmt_vid_cap        = rvin_enum_fmt_vid_cap,
 728
 729        .vidioc_enum_input              = rvin_mc_enum_input,
 730        .vidioc_g_input                 = rvin_g_input,
 731        .vidioc_s_input                 = rvin_s_input,
 732
 733        .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
 734        .vidioc_create_bufs             = vb2_ioctl_create_bufs,
 735        .vidioc_querybuf                = vb2_ioctl_querybuf,
 736        .vidioc_qbuf                    = vb2_ioctl_qbuf,
 737        .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
 738        .vidioc_expbuf                  = vb2_ioctl_expbuf,
 739        .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
 740        .vidioc_streamon                = vb2_ioctl_streamon,
 741        .vidioc_streamoff               = vb2_ioctl_streamoff,
 742
 743        .vidioc_log_status              = v4l2_ctrl_log_status,
 744        .vidioc_subscribe_event         = rvin_subscribe_event,
 745        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 746};
 747
 748/* -----------------------------------------------------------------------------
 749 * File Operations
 750 */
 751
 752static int rvin_power_on(struct rvin_dev *vin)
 753{
 754        int ret;
 755        struct v4l2_subdev *sd = vin_to_source(vin);
 756
 757        pm_runtime_get_sync(vin->v4l2_dev.dev);
 758
 759        ret = v4l2_subdev_call(sd, core, s_power, 1);
 760        if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
 761                return ret;
 762        return 0;
 763}
 764
 765static int rvin_power_off(struct rvin_dev *vin)
 766{
 767        int ret;
 768        struct v4l2_subdev *sd = vin_to_source(vin);
 769
 770        ret = v4l2_subdev_call(sd, core, s_power, 0);
 771
 772        pm_runtime_put(vin->v4l2_dev.dev);
 773
 774        if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
 775                return ret;
 776
 777        return 0;
 778}
 779
 780static int rvin_initialize_device(struct file *file)
 781{
 782        struct rvin_dev *vin = video_drvdata(file);
 783        int ret;
 784
 785        struct v4l2_format f = {
 786                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 787                .fmt.pix = {
 788                        .width          = vin->format.width,
 789                        .height         = vin->format.height,
 790                        .field          = vin->format.field,
 791                        .colorspace     = vin->format.colorspace,
 792                        .pixelformat    = vin->format.pixelformat,
 793                },
 794        };
 795
 796        ret = rvin_power_on(vin);
 797        if (ret < 0)
 798                return ret;
 799
 800        pm_runtime_enable(&vin->vdev.dev);
 801        ret = pm_runtime_resume(&vin->vdev.dev);
 802        if (ret < 0 && ret != -ENOSYS)
 803                goto eresume;
 804
 805        /*
 806         * Try to configure with default parameters. Notice: this is the
 807         * very first open, so, we cannot race against other calls,
 808         * apart from someone else calling open() simultaneously, but
 809         * .host_lock is protecting us against it.
 810         */
 811        ret = rvin_s_fmt_vid_cap(file, NULL, &f);
 812        if (ret < 0)
 813                goto esfmt;
 814
 815        v4l2_ctrl_handler_setup(&vin->ctrl_handler);
 816
 817        return 0;
 818esfmt:
 819        pm_runtime_disable(&vin->vdev.dev);
 820eresume:
 821        rvin_power_off(vin);
 822
 823        return ret;
 824}
 825
 826static int rvin_open(struct file *file)
 827{
 828        struct rvin_dev *vin = video_drvdata(file);
 829        int ret;
 830
 831        mutex_lock(&vin->lock);
 832
 833        file->private_data = vin;
 834
 835        ret = v4l2_fh_open(file);
 836        if (ret)
 837                goto unlock;
 838
 839        if (!v4l2_fh_is_singular_file(file))
 840                goto unlock;
 841
 842        if (rvin_initialize_device(file)) {
 843                v4l2_fh_release(file);
 844                ret = -ENODEV;
 845        }
 846
 847unlock:
 848        mutex_unlock(&vin->lock);
 849        return ret;
 850}
 851
 852static int rvin_release(struct file *file)
 853{
 854        struct rvin_dev *vin = video_drvdata(file);
 855        bool fh_singular;
 856        int ret;
 857
 858        mutex_lock(&vin->lock);
 859
 860        /* Save the singular status before we call the clean-up helper */
 861        fh_singular = v4l2_fh_is_singular_file(file);
 862
 863        /* the release helper will cleanup any on-going streaming */
 864        ret = _vb2_fop_release(file, NULL);
 865
 866        /*
 867         * If this was the last open file.
 868         * Then de-initialize hw module.
 869         */
 870        if (fh_singular) {
 871                pm_runtime_suspend(&vin->vdev.dev);
 872                pm_runtime_disable(&vin->vdev.dev);
 873                rvin_power_off(vin);
 874        }
 875
 876        mutex_unlock(&vin->lock);
 877
 878        return ret;
 879}
 880
 881static const struct v4l2_file_operations rvin_fops = {
 882        .owner          = THIS_MODULE,
 883        .unlocked_ioctl = video_ioctl2,
 884        .open           = rvin_open,
 885        .release        = rvin_release,
 886        .poll           = vb2_fop_poll,
 887        .mmap           = vb2_fop_mmap,
 888        .read           = vb2_fop_read,
 889};
 890
 891/* -----------------------------------------------------------------------------
 892 * Media controller file operations
 893 */
 894
 895static int rvin_mc_open(struct file *file)
 896{
 897        struct rvin_dev *vin = video_drvdata(file);
 898        int ret;
 899
 900        ret = mutex_lock_interruptible(&vin->lock);
 901        if (ret)
 902                return ret;
 903
 904        ret = pm_runtime_get_sync(vin->dev);
 905        if (ret < 0)
 906                goto err_unlock;
 907
 908        ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
 909        if (ret < 0)
 910                goto err_pm;
 911
 912        file->private_data = vin;
 913
 914        ret = v4l2_fh_open(file);
 915        if (ret)
 916                goto err_v4l2pm;
 917
 918        mutex_unlock(&vin->lock);
 919
 920        return 0;
 921err_v4l2pm:
 922        v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
 923err_pm:
 924        pm_runtime_put(vin->dev);
 925err_unlock:
 926        mutex_unlock(&vin->lock);
 927
 928        return ret;
 929}
 930
 931static int rvin_mc_release(struct file *file)
 932{
 933        struct rvin_dev *vin = video_drvdata(file);
 934        int ret;
 935
 936        mutex_lock(&vin->lock);
 937
 938        /* the release helper will cleanup any on-going streaming. */
 939        ret = _vb2_fop_release(file, NULL);
 940
 941        v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
 942        pm_runtime_put(vin->dev);
 943
 944        mutex_unlock(&vin->lock);
 945
 946        return ret;
 947}
 948
 949static const struct v4l2_file_operations rvin_mc_fops = {
 950        .owner          = THIS_MODULE,
 951        .unlocked_ioctl = video_ioctl2,
 952        .open           = rvin_mc_open,
 953        .release        = rvin_mc_release,
 954        .poll           = vb2_fop_poll,
 955        .mmap           = vb2_fop_mmap,
 956        .read           = vb2_fop_read,
 957};
 958
 959void rvin_v4l2_unregister(struct rvin_dev *vin)
 960{
 961        if (!video_is_registered(&vin->vdev))
 962                return;
 963
 964        v4l2_info(&vin->v4l2_dev, "Removing %s\n",
 965                  video_device_node_name(&vin->vdev));
 966
 967        /* Checks internally if vdev have been init or not */
 968        video_unregister_device(&vin->vdev);
 969}
 970
 971static void rvin_notify(struct v4l2_subdev *sd,
 972                        unsigned int notification, void *arg)
 973{
 974        struct rvin_dev *vin =
 975                container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
 976
 977        switch (notification) {
 978        case V4L2_DEVICE_NOTIFY_EVENT:
 979                v4l2_event_queue(&vin->vdev, arg);
 980                break;
 981        default:
 982                break;
 983        }
 984}
 985
 986int rvin_v4l2_register(struct rvin_dev *vin)
 987{
 988        struct video_device *vdev = &vin->vdev;
 989        int ret;
 990
 991        vin->v4l2_dev.notify = rvin_notify;
 992
 993        /* video node */
 994        vdev->v4l2_dev = &vin->v4l2_dev;
 995        vdev->queue = &vin->queue;
 996        snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
 997        vdev->release = video_device_release_empty;
 998        vdev->lock = &vin->lock;
 999        vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
1000                V4L2_CAP_READWRITE;
1001
1002        /* Set a default format */
1003        vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
1004        vin->format.width = RVIN_DEFAULT_WIDTH;
1005        vin->format.height = RVIN_DEFAULT_HEIGHT;
1006        vin->format.field = RVIN_DEFAULT_FIELD;
1007        vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
1008
1009        if (vin->info->use_mc) {
1010                vdev->fops = &rvin_mc_fops;
1011                vdev->ioctl_ops = &rvin_mc_ioctl_ops;
1012        } else {
1013                vdev->fops = &rvin_fops;
1014                vdev->ioctl_ops = &rvin_ioctl_ops;
1015                rvin_reset_format(vin);
1016        }
1017
1018        rvin_format_align(vin, &vin->format);
1019
1020        ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
1021        if (ret) {
1022                vin_err(vin, "Failed to register video device\n");
1023                return ret;
1024        }
1025
1026        video_set_drvdata(&vin->vdev, vin);
1027
1028        v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
1029                  video_device_node_name(&vin->vdev));
1030
1031        return ret;
1032}
1033