linux/drivers/media/platform/xilinx/xilinx-rgb2yuv.c
<<
>>
Prefs
   1/*
   2 * Xilinx RGB to YUV Convertor
   3 *
   4 * Copyright (C) 2013-2015 Ideas on Board
   5 * Copyright (C) 2013-2015 Xilinx, Inc.
   6 *
   7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
   8 *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
   9 *
  10 * This software is licensed under the terms of the GNU General Public
  11 * License version 2, as published by the Free Software Foundation, and
  12 * may be copied, distributed, and modified under those terms.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 */
  19
  20#include <linux/device.h>
  21#include <linux/module.h>
  22#include <linux/of.h>
  23#include <linux/platform_device.h>
  24#include <linux/xilinx-v4l2-controls.h>
  25
  26#include <media/v4l2-async.h>
  27#include <media/v4l2-ctrls.h>
  28#include <media/v4l2-subdev.h>
  29
  30#include "xilinx-vip.h"
  31
  32#define XRGB2YUV_YMAX                                   0x100
  33#define XRGB2YUV_YMIN                                   0x104
  34#define XRGB2YUV_CBMAX                                  0x108
  35#define XRGB2YUV_CBMIN                                  0x10c
  36#define XRGB2YUV_CRMAX                                  0x110
  37#define XRGB2YUV_CRMIN                                  0x114
  38#define XRGB2YUV_YOFFSET                                0x118
  39#define XRGB2YUV_CBOFFSET                               0x11c
  40#define XRGB2YUV_CROFFSET                               0x120
  41#define XRGB2YUV_ACOEF                                  0x124
  42#define XRGB2YUV_BCOEF                                  0x128
  43#define XRGB2YUV_CCOEF                                  0x12c
  44#define XRGB2YUV_DCOEF                                  0x130
  45
  46/**
  47 * struct xrgb2yuv_device - Xilinx RGB2YUV device structure
  48 * @xvip: Xilinx Video IP device
  49 * @pads: media pads
  50 * @formats: V4L2 media bus formats at the sink and source pads
  51 * @default_formats: default V4L2 media bus formats
  52 * @vip_formats: Xilinx Video IP formats
  53 * @ctrl_handler: control handler
  54 */
  55struct xrgb2yuv_device {
  56        struct xvip_device xvip;
  57
  58        struct media_pad pads[2];
  59
  60        struct v4l2_mbus_framefmt formats[2];
  61        struct v4l2_mbus_framefmt default_formats[2];
  62        const struct xvip_video_format *vip_formats[2];
  63
  64        struct v4l2_ctrl_handler ctrl_handler;
  65};
  66
  67static inline struct xrgb2yuv_device *to_rgb2yuv(struct v4l2_subdev *subdev)
  68{
  69        return container_of(subdev, struct xrgb2yuv_device, xvip.subdev);
  70}
  71
  72/*
  73 * V4L2 Subdevice Video Operations
  74 */
  75
  76static int xrgb2yuv_s_stream(struct v4l2_subdev *subdev, int enable)
  77{
  78        struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
  79
  80        if (!enable) {
  81                xvip_stop(&xrgb2yuv->xvip);
  82                return 0;
  83        }
  84
  85        xvip_set_frame_size(&xrgb2yuv->xvip, &xrgb2yuv->formats[XVIP_PAD_SINK]);
  86
  87        xvip_start(&xrgb2yuv->xvip);
  88
  89        return 0;
  90}
  91
  92/*
  93 * V4L2 Subdevice Pad Operations
  94 */
  95
  96static struct v4l2_mbus_framefmt *
  97__xrgb2yuv_get_pad_format(struct xrgb2yuv_device *xrgb2yuv,
  98                          struct v4l2_subdev_state *sd_state,
  99                          unsigned int pad, u32 which)
 100{
 101        struct v4l2_mbus_framefmt *format;
 102
 103        switch (which) {
 104        case V4L2_SUBDEV_FORMAT_TRY:
 105                format = v4l2_subdev_get_try_format(&xrgb2yuv->xvip.subdev,
 106                                                    sd_state, pad);
 107                break;
 108        case V4L2_SUBDEV_FORMAT_ACTIVE:
 109                format = &xrgb2yuv->formats[pad];
 110                break;
 111        default:
 112                format = NULL;
 113                break;
 114        }
 115
 116        return format;
 117}
 118
 119static int xrgb2yuv_get_format(struct v4l2_subdev *subdev,
 120                               struct v4l2_subdev_state *sd_state,
 121                               struct v4l2_subdev_format *fmt)
 122{
 123        struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
 124        struct v4l2_mbus_framefmt *format;
 125
 126        format = __xrgb2yuv_get_pad_format(xrgb2yuv, sd_state, fmt->pad,
 127                                           fmt->which);
 128        if (!format)
 129                return -EINVAL;
 130
 131        fmt->format = *format;
 132
 133        return 0;
 134}
 135
 136static int xrgb2yuv_set_format(struct v4l2_subdev *subdev,
 137                               struct v4l2_subdev_state *sd_state,
 138                               struct v4l2_subdev_format *fmt)
 139{
 140        struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
 141        struct v4l2_mbus_framefmt *format;
 142
 143        format = __xrgb2yuv_get_pad_format(xrgb2yuv, sd_state, fmt->pad,
 144                                           fmt->which);
 145        if (!format)
 146                return -EINVAL;
 147
 148        if (fmt->pad == XVIP_PAD_SOURCE) {
 149                fmt->format = *format;
 150                return 0;
 151        }
 152
 153        xvip_set_format_size(format, fmt);
 154
 155        fmt->format = *format;
 156
 157        /* Propagate the format to the source pad. */
 158        format = __xrgb2yuv_get_pad_format(xrgb2yuv, sd_state, XVIP_PAD_SOURCE,
 159                                             fmt->which);
 160
 161        xvip_set_format_size(format, fmt);
 162
 163        return 0;
 164}
 165
 166/*
 167 * V4L2 Subdevice Operations
 168 */
 169
 170static int xrgb2yuv_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
 171{
 172        struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
 173        struct v4l2_mbus_framefmt *format;
 174
 175        /* Initialize with default formats */
 176        format = v4l2_subdev_get_try_format(subdev, fh->state, XVIP_PAD_SINK);
 177        *format = xrgb2yuv->default_formats[XVIP_PAD_SINK];
 178
 179        format = v4l2_subdev_get_try_format(subdev, fh->state, XVIP_PAD_SOURCE);
 180        *format = xrgb2yuv->default_formats[XVIP_PAD_SOURCE];
 181
 182        return 0;
 183}
 184
 185static int xrgb2yuv_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
 186{
 187        return 0;
 188}
 189
 190static int xrgb2yuv_s_ctrl(struct v4l2_ctrl *ctrl)
 191{
 192        struct xrgb2yuv_device *xrgb2yuv =
 193                container_of(ctrl->handler, struct xrgb2yuv_device,
 194                             ctrl_handler);
 195
 196        switch (ctrl->id) {
 197        case V4L2_CID_XILINX_RGB2YUV_YMAX:
 198                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_YMAX, ctrl->val);
 199                return 0;
 200        case V4L2_CID_XILINX_RGB2YUV_YMIN:
 201                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_YMIN, ctrl->val);
 202                return 0;
 203        case V4L2_CID_XILINX_RGB2YUV_CBMAX:
 204                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CBMAX, ctrl->val);
 205                return 0;
 206        case V4L2_CID_XILINX_RGB2YUV_CBMIN:
 207                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CBMIN, ctrl->val);
 208                return 0;
 209        case V4L2_CID_XILINX_RGB2YUV_CRMAX:
 210                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CRMAX, ctrl->val);
 211                return 0;
 212        case V4L2_CID_XILINX_RGB2YUV_CRMIN:
 213                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CRMIN, ctrl->val);
 214                return 0;
 215        case V4L2_CID_XILINX_RGB2YUV_YOFFSET:
 216                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_YOFFSET, ctrl->val);
 217                return 0;
 218        case V4L2_CID_XILINX_RGB2YUV_CBOFFSET:
 219                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CBOFFSET, ctrl->val);
 220                return 0;
 221        case V4L2_CID_XILINX_RGB2YUV_CROFFSET:
 222                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CROFFSET, ctrl->val);
 223                return 0;
 224        case V4L2_CID_XILINX_RGB2YUV_ACOEF:
 225                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_ACOEF, ctrl->val);
 226                return 0;
 227        case V4L2_CID_XILINX_RGB2YUV_BCOEF:
 228                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_BCOEF, ctrl->val);
 229                return 0;
 230        case V4L2_CID_XILINX_RGB2YUV_CCOEF:
 231                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CCOEF, ctrl->val);
 232                return 0;
 233        case V4L2_CID_XILINX_RGB2YUV_DCOEF:
 234                xvip_write(&xrgb2yuv->xvip, XRGB2YUV_DCOEF, ctrl->val);
 235                return 0;
 236        }
 237
 238        return -EINVAL;
 239}
 240
 241static const struct v4l2_ctrl_ops xrgb2yuv_ctrl_ops = {
 242        .s_ctrl = xrgb2yuv_s_ctrl,
 243};
 244
 245static struct v4l2_subdev_video_ops xrgb2yuv_video_ops = {
 246        .s_stream = xrgb2yuv_s_stream,
 247};
 248
 249static struct v4l2_subdev_pad_ops xrgb2yuv_pad_ops = {
 250        .enum_mbus_code         = xvip_enum_mbus_code,
 251        .enum_frame_size        = xvip_enum_frame_size,
 252        .get_fmt                = xrgb2yuv_get_format,
 253        .set_fmt                = xrgb2yuv_set_format,
 254};
 255
 256static struct v4l2_subdev_ops xrgb2yuv_ops = {
 257        .video  = &xrgb2yuv_video_ops,
 258        .pad    = &xrgb2yuv_pad_ops,
 259};
 260
 261static const struct v4l2_subdev_internal_ops xrgb2yuv_internal_ops = {
 262        .open   = xrgb2yuv_open,
 263        .close  = xrgb2yuv_close,
 264};
 265
 266/*
 267 * Control Configs
 268 */
 269
 270static struct v4l2_ctrl_config xrgb2yuv_ctrls[] = {
 271        {
 272                .ops    = &xrgb2yuv_ctrl_ops,
 273                .id     = V4L2_CID_XILINX_RGB2YUV_YMAX,
 274                .name   = "RGB to YUV: Maximum Y value",
 275                .type   = V4L2_CTRL_TYPE_INTEGER,
 276                .min    = 0,
 277                .max    = (1 << 16) - 1,
 278                .step   = 1,
 279        }, {
 280                .ops    = &xrgb2yuv_ctrl_ops,
 281                .id     = V4L2_CID_XILINX_RGB2YUV_YMIN,
 282                .name   = "RGB to YUV: Minimum Y value",
 283                .type   = V4L2_CTRL_TYPE_INTEGER,
 284                .min    = 0,
 285                .max    = (1 << 16) - 1,
 286                .step   = 1,
 287        }, {
 288                .ops    = &xrgb2yuv_ctrl_ops,
 289                .id     = V4L2_CID_XILINX_RGB2YUV_CBMAX,
 290                .name   = "RGB to YUV: Maximum Cb value",
 291                .type   = V4L2_CTRL_TYPE_INTEGER,
 292                .min    = 0,
 293                .max    = (1 << 16) - 1,
 294                .step   = 1,
 295        }, {
 296                .ops    = &xrgb2yuv_ctrl_ops,
 297                .id     = V4L2_CID_XILINX_RGB2YUV_CBMIN,
 298                .name   = "RGB to YUV: Minimum Cb value",
 299                .type   = V4L2_CTRL_TYPE_INTEGER,
 300                .min    = 0,
 301                .max    = (1 << 16) - 1,
 302                .step   = 1,
 303        }, {
 304                .ops    = &xrgb2yuv_ctrl_ops,
 305                .id     = V4L2_CID_XILINX_RGB2YUV_CRMAX,
 306                .name   = "RGB to YUV: Maximum Cr value",
 307                .type   = V4L2_CTRL_TYPE_INTEGER,
 308                .min    = 0,
 309                .max    = (1 << 16) - 1,
 310                .step   = 1,
 311        }, {
 312                .ops    = &xrgb2yuv_ctrl_ops,
 313                .id     = V4L2_CID_XILINX_RGB2YUV_CRMIN,
 314                .name   = "RGB to YUV: Minimum Cr value",
 315                .type   = V4L2_CTRL_TYPE_INTEGER,
 316                .min    = 0,
 317                .max    = (1 << 16) - 1,
 318                .step   = 1,
 319        }, {
 320                .ops    = &xrgb2yuv_ctrl_ops,
 321                .id     = V4L2_CID_XILINX_RGB2YUV_YOFFSET,
 322                .name   = "RGB to YUV: Luma offset",
 323                .type   = V4L2_CTRL_TYPE_INTEGER,
 324                .min    = 0,
 325                .max    = (1 << 17) - 1,
 326                .step   = 1,
 327        }, {
 328                .ops    = &xrgb2yuv_ctrl_ops,
 329                .id     = V4L2_CID_XILINX_RGB2YUV_CBOFFSET,
 330                .name   = "RGB to YUV: Chroma Cb offset",
 331                .type   = V4L2_CTRL_TYPE_INTEGER,
 332                .min    = 0,
 333                .max    = (1 << 17) - 1,
 334                .step   = 1,
 335        }, {
 336                .ops    = &xrgb2yuv_ctrl_ops,
 337                .id     = V4L2_CID_XILINX_RGB2YUV_CROFFSET,
 338                .name   = "RGB to YUV: Chroma Cr offset",
 339                .type   = V4L2_CTRL_TYPE_INTEGER,
 340                .min    = 0,
 341                .max    = (1 << 17) - 1,
 342                .step   = 1,
 343        }, {
 344                .ops    = &xrgb2yuv_ctrl_ops,
 345                .id     = V4L2_CID_XILINX_RGB2YUV_ACOEF,
 346                .name   = "RGB to YUV: CA coefficient",
 347                .type   = V4L2_CTRL_TYPE_INTEGER,
 348                .min    = -((1 << 17) - 1),
 349                .max    = (1 << 17) - 1,
 350                .step   = 1,
 351        }, {
 352                .ops    = &xrgb2yuv_ctrl_ops,
 353                .id     = V4L2_CID_XILINX_RGB2YUV_BCOEF,
 354                .name   = "RGB to YUV: CB coefficient",
 355                .type   = V4L2_CTRL_TYPE_INTEGER,
 356                .min    = -((1 << 17) - 1),
 357                .max    = (1 << 17) - 1,
 358                .step   = 1,
 359        }, {
 360                .ops    = &xrgb2yuv_ctrl_ops,
 361                .id     = V4L2_CID_XILINX_RGB2YUV_CCOEF,
 362                .name   = "RGB to YUV: CC coefficient",
 363                .type   = V4L2_CTRL_TYPE_INTEGER,
 364                .min    = -((1 << 17) - 1),
 365                .max    = (1 << 17) - 1,
 366                .step   = 1,
 367        }, {
 368                .ops    = &xrgb2yuv_ctrl_ops,
 369                .id     = V4L2_CID_XILINX_RGB2YUV_DCOEF,
 370                .name   = "RGB to YUV: CD coefficient",
 371                .type   = V4L2_CTRL_TYPE_INTEGER,
 372                .min    = -((1 << 17) - 1),
 373                .max    = (1 << 17) - 1,
 374                .step   = 1,
 375        },
 376};
 377
 378/*
 379 * Media Operations
 380 */
 381
 382static const struct media_entity_operations xrgb2yuv_media_ops = {
 383        .link_validate = v4l2_subdev_link_validate,
 384};
 385
 386/*
 387 * Power Management
 388 */
 389
 390static int __maybe_unused xrgb2yuv_pm_suspend(struct device *dev)
 391{
 392        struct xrgb2yuv_device *xrgb2yuv = dev_get_drvdata(dev);
 393
 394        xvip_suspend(&xrgb2yuv->xvip);
 395
 396        return 0;
 397}
 398
 399static int __maybe_unused xrgb2yuv_pm_resume(struct device *dev)
 400{
 401        struct xrgb2yuv_device *xrgb2yuv = dev_get_drvdata(dev);
 402
 403        xvip_resume(&xrgb2yuv->xvip);
 404
 405        return 0;
 406}
 407
 408/*
 409 * Platform Device Driver
 410 */
 411
 412static int xrgb2yuv_parse_of(struct xrgb2yuv_device *xrgb2yuv)
 413{
 414        struct device *dev = xrgb2yuv->xvip.dev;
 415        struct device_node *node = xrgb2yuv->xvip.dev->of_node;
 416        struct device_node *ports;
 417        struct device_node *port;
 418        u32 port_id;
 419        int ret;
 420
 421        ports = of_get_child_by_name(node, "ports");
 422        if (ports == NULL)
 423                ports = node;
 424
 425        /* Get the format description for each pad */
 426        for_each_child_of_node(ports, port) {
 427                if (port->name && (of_node_cmp(port->name, "port") == 0)) {
 428                        const struct xvip_video_format *vip_format;
 429
 430                        vip_format = xvip_of_get_format(port);
 431                        if (IS_ERR(vip_format)) {
 432                                dev_err(dev, "invalid format in DT");
 433                                return PTR_ERR(vip_format);
 434                        }
 435
 436                        ret = of_property_read_u32(port, "reg", &port_id);
 437                        if (ret < 0) {
 438                                dev_err(dev, "no reg in DT");
 439                                return ret;
 440                        }
 441
 442                        if (port_id != 0 && port_id != 1) {
 443                                dev_err(dev, "invalid reg in DT");
 444                                return -EINVAL;
 445                        }
 446
 447                        xrgb2yuv->vip_formats[port_id] = vip_format;
 448                }
 449        }
 450
 451        return 0;
 452}
 453
 454static int xrgb2yuv_probe(struct platform_device *pdev)
 455{
 456        struct xrgb2yuv_device *xrgb2yuv;
 457        struct v4l2_subdev *subdev;
 458        struct v4l2_mbus_framefmt *default_format;
 459        unsigned int i;
 460        int ret;
 461
 462        xrgb2yuv = devm_kzalloc(&pdev->dev, sizeof(*xrgb2yuv), GFP_KERNEL);
 463        if (!xrgb2yuv)
 464                return -ENOMEM;
 465
 466        xrgb2yuv->xvip.dev = &pdev->dev;
 467
 468        ret = xrgb2yuv_parse_of(xrgb2yuv);
 469        if (ret < 0)
 470                return ret;
 471
 472        ret = xvip_init_resources(&xrgb2yuv->xvip);
 473        if (ret < 0)
 474                return ret;
 475
 476        /* Reset and initialize the core */
 477        xvip_reset(&xrgb2yuv->xvip);
 478
 479        /* Initialize V4L2 subdevice and media entity */
 480        subdev = &xrgb2yuv->xvip.subdev;
 481        v4l2_subdev_init(subdev, &xrgb2yuv_ops);
 482        subdev->dev = &pdev->dev;
 483        subdev->internal_ops = &xrgb2yuv_internal_ops;
 484        strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
 485        v4l2_set_subdevdata(subdev, xrgb2yuv);
 486        subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 487
 488        /* Initialize default and active formats */
 489        default_format = &xrgb2yuv->default_formats[XVIP_PAD_SINK];
 490        default_format->code = xrgb2yuv->vip_formats[XVIP_PAD_SINK]->code;
 491        default_format->field = V4L2_FIELD_NONE;
 492        default_format->colorspace = V4L2_COLORSPACE_SRGB;
 493        xvip_get_frame_size(&xrgb2yuv->xvip, default_format);
 494
 495        xrgb2yuv->formats[XVIP_PAD_SINK] = *default_format;
 496
 497        default_format = &xrgb2yuv->default_formats[XVIP_PAD_SOURCE];
 498        *default_format = xrgb2yuv->default_formats[XVIP_PAD_SINK];
 499        default_format->code = xrgb2yuv->vip_formats[XVIP_PAD_SOURCE]->code;
 500
 501        xrgb2yuv->formats[XVIP_PAD_SOURCE] = *default_format;
 502
 503        xrgb2yuv->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
 504        xrgb2yuv->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
 505        subdev->entity.ops = &xrgb2yuv_media_ops;
 506        ret = media_entity_pads_init(&subdev->entity, 2, xrgb2yuv->pads);
 507        if (ret < 0)
 508                goto error;
 509
 510        v4l2_ctrl_handler_init(&xrgb2yuv->ctrl_handler, 13);
 511
 512        for (i = 0; i < ARRAY_SIZE(xrgb2yuv_ctrls); i++) {
 513                xrgb2yuv_ctrls[i].def = xvip_read(&xrgb2yuv->xvip,
 514                                                  XRGB2YUV_YMAX + i * 4);
 515                v4l2_ctrl_new_custom(&xrgb2yuv->ctrl_handler,
 516                                     &xrgb2yuv_ctrls[i], NULL);
 517        }
 518
 519        if (xrgb2yuv->ctrl_handler.error) {
 520                dev_err(&pdev->dev, "failed to add controls\n");
 521                ret = xrgb2yuv->ctrl_handler.error;
 522                goto error;
 523        }
 524        subdev->ctrl_handler = &xrgb2yuv->ctrl_handler;
 525
 526        platform_set_drvdata(pdev, xrgb2yuv);
 527
 528        xvip_print_version(&xrgb2yuv->xvip);
 529
 530        ret = v4l2_async_register_subdev(subdev);
 531        if (ret < 0) {
 532                dev_err(&pdev->dev, "failed to register subdev\n");
 533                goto error;
 534        }
 535
 536        return 0;
 537
 538error:
 539        v4l2_ctrl_handler_free(&xrgb2yuv->ctrl_handler);
 540        media_entity_cleanup(&subdev->entity);
 541        xvip_cleanup_resources(&xrgb2yuv->xvip);
 542        return ret;
 543}
 544
 545static int xrgb2yuv_remove(struct platform_device *pdev)
 546{
 547        struct xrgb2yuv_device *xrgb2yuv = platform_get_drvdata(pdev);
 548        struct v4l2_subdev *subdev = &xrgb2yuv->xvip.subdev;
 549
 550        v4l2_async_unregister_subdev(subdev);
 551        v4l2_ctrl_handler_free(&xrgb2yuv->ctrl_handler);
 552        media_entity_cleanup(&subdev->entity);
 553
 554        xvip_cleanup_resources(&xrgb2yuv->xvip);
 555
 556        return 0;
 557}
 558
 559static SIMPLE_DEV_PM_OPS(xrgb2yuv_pm_ops, xrgb2yuv_pm_suspend,
 560                         xrgb2yuv_pm_resume);
 561
 562static const struct of_device_id xrgb2yuv_of_id_table[] = {
 563        { .compatible = "xlnx,v-rgb2yuv-7.1" },
 564        { }
 565};
 566MODULE_DEVICE_TABLE(of, xrgb2yuv_of_id_table);
 567
 568static struct platform_driver xrgb2yuv_driver = {
 569        .driver                 = {
 570                .name           = "xilinx-rgb2yuv",
 571                .pm             = &xrgb2yuv_pm_ops,
 572                .of_match_table = xrgb2yuv_of_id_table,
 573        },
 574        .probe                  = xrgb2yuv_probe,
 575        .remove                 = xrgb2yuv_remove,
 576};
 577
 578module_platform_driver(xrgb2yuv_driver);
 579
 580MODULE_DESCRIPTION("Xilinx RGB to YUV Converter Driver");
 581MODULE_LICENSE("GPL v2");
 582