1405 lines · c
1/*2 * vpif-display - VPIF display driver3 * Display driver for TI DaVinci VPIF4 *5 * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/6 * Copyright (C) 2014 Lad, Prabhakar <prabhakar.csengg@gmail.com>7 *8 * This program is free software; you can redistribute it and/or9 * modify it under the terms of the GNU General Public License as10 * published by the Free Software Foundation version 2.11 *12 * This program is distributed .as is. WITHOUT ANY WARRANTY of any13 * kind, whether express or implied; without even the implied warranty14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 * GNU General Public License for more details.16 */17 18#include <linux/interrupt.h>19#include <linux/module.h>20#include <linux/platform_device.h>21#include <linux/slab.h>22 23#include <media/v4l2-ioctl.h>24 25#include "vpif.h"26#include "vpif_display.h"27 28MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");29MODULE_LICENSE("GPL");30MODULE_VERSION(VPIF_DISPLAY_VERSION);31 32#define VPIF_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)33 34#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)35#define vpif_dbg(level, debug, fmt, arg...) \36 v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)37 38static int debug = 1;39 40module_param(debug, int, 0644);41 42MODULE_PARM_DESC(debug, "Debug level 0-1");43 44#define VPIF_DRIVER_NAME "vpif_display"45MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);46 47/* Is set to 1 in case of SDTV formats, 2 in case of HDTV formats. */48static int ycmux_mode;49 50static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };51 52static struct vpif_device vpif_obj = { {NULL} };53static struct device *vpif_dev;54static void vpif_calculate_offsets(struct channel_obj *ch);55static void vpif_config_addr(struct channel_obj *ch, int muxmode);56 57static inline58struct vpif_disp_buffer *to_vpif_buffer(struct vb2_v4l2_buffer *vb)59{60 return container_of(vb, struct vpif_disp_buffer, vb);61}62 63/**64 * vpif_buffer_prepare : callback function for buffer prepare65 * @vb: ptr to vb2_buffer66 *67 * This is the callback function for buffer prepare when vb2_qbuf()68 * function is called. The buffer is prepared and user space virtual address69 * or user address is converted into physical address70 */71static int vpif_buffer_prepare(struct vb2_buffer *vb)72{73 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);74 struct channel_obj *ch = vb2_get_drv_priv(vb->vb2_queue);75 struct common_obj *common;76 77 common = &ch->common[VPIF_VIDEO_INDEX];78 79 vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);80 if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))81 return -EINVAL;82 83 vbuf->field = common->fmt.fmt.pix.field;84 85 if (vb->vb2_queue->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {86 unsigned long addr = vb2_dma_contig_plane_dma_addr(vb, 0);87 88 if (!ISALIGNED(addr + common->ytop_off) ||89 !ISALIGNED(addr + common->ybtm_off) ||90 !ISALIGNED(addr + common->ctop_off) ||91 !ISALIGNED(addr + common->cbtm_off)) {92 vpif_err("buffer offset not aligned to 8 bytes\n");93 return -EINVAL;94 }95 }96 97 return 0;98}99 100/**101 * vpif_buffer_queue_setup : Callback function for buffer setup.102 * @vq: vb2_queue ptr103 * @nbuffers: ptr to number of buffers requested by application104 * @nplanes: contains number of distinct video planes needed to hold a frame105 * @sizes: contains the size (in bytes) of each plane.106 * @alloc_devs: ptr to allocation context107 *108 * This callback function is called when reqbuf() is called to adjust109 * the buffer count and buffer size110 */111static int vpif_buffer_queue_setup(struct vb2_queue *vq,112 unsigned int *nbuffers, unsigned int *nplanes,113 unsigned int sizes[], struct device *alloc_devs[])114{115 struct channel_obj *ch = vb2_get_drv_priv(vq);116 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];117 unsigned size = common->fmt.fmt.pix.sizeimage;118 unsigned int q_num_bufs = vb2_get_num_buffers(vq);119 120 if (*nplanes) {121 if (sizes[0] < size)122 return -EINVAL;123 size = sizes[0];124 }125 126 if (q_num_bufs + *nbuffers < 3)127 *nbuffers = 3 - q_num_bufs;128 129 *nplanes = 1;130 sizes[0] = size;131 132 /* Calculate the offset for Y and C data in the buffer */133 vpif_calculate_offsets(ch);134 135 return 0;136}137 138/**139 * vpif_buffer_queue : Callback function to add buffer to DMA queue140 * @vb: ptr to vb2_buffer141 *142 * This callback function queues the buffer to DMA engine143 */144static void vpif_buffer_queue(struct vb2_buffer *vb)145{146 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);147 struct vpif_disp_buffer *buf = to_vpif_buffer(vbuf);148 struct channel_obj *ch = vb2_get_drv_priv(vb->vb2_queue);149 struct common_obj *common;150 unsigned long flags;151 152 common = &ch->common[VPIF_VIDEO_INDEX];153 154 /* add the buffer to the DMA queue */155 spin_lock_irqsave(&common->irqlock, flags);156 list_add_tail(&buf->list, &common->dma_queue);157 spin_unlock_irqrestore(&common->irqlock, flags);158}159 160/**161 * vpif_start_streaming : Starts the DMA engine for streaming162 * @vq: ptr to vb2_buffer163 * @count: number of buffers164 */165static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)166{167 struct vpif_display_config *vpif_config_data =168 vpif_dev->platform_data;169 struct channel_obj *ch = vb2_get_drv_priv(vq);170 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];171 struct vpif_params *vpif = &ch->vpifparams;172 struct vpif_disp_buffer *buf, *tmp;173 unsigned long addr, flags;174 int ret;175 176 spin_lock_irqsave(&common->irqlock, flags);177 178 /* Initialize field_id */179 ch->field_id = 0;180 181 /* clock settings */182 if (vpif_config_data->set_clock) {183 ret = vpif_config_data->set_clock(ch->vpifparams.std_info.184 ycmux_mode, ch->vpifparams.std_info.hd_sd);185 if (ret < 0) {186 vpif_err("can't set clock\n");187 goto err;188 }189 }190 191 /* set the parameters and addresses */192 ret = vpif_set_video_params(vpif, ch->channel_id + 2);193 if (ret < 0)194 goto err;195 196 ycmux_mode = ret;197 vpif_config_addr(ch, ret);198 /* Get the next frame from the buffer queue */199 common->next_frm = common->cur_frm =200 list_entry(common->dma_queue.next,201 struct vpif_disp_buffer, list);202 203 list_del(&common->cur_frm->list);204 spin_unlock_irqrestore(&common->irqlock, flags);205 206 addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb.vb2_buf, 0);207 common->set_addr((addr + common->ytop_off),208 (addr + common->ybtm_off),209 (addr + common->ctop_off),210 (addr + common->cbtm_off));211 212 /*213 * Set interrupt for both the fields in VPIF214 * Register enable channel in VPIF register215 */216 channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;217 if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {218 channel2_intr_assert();219 channel2_intr_enable(1);220 enable_channel2(1);221 if (vpif_config_data->chan_config[VPIF_CHANNEL2_VIDEO].clip_en)222 channel2_clipping_enable(1);223 }224 225 if (VPIF_CHANNEL3_VIDEO == ch->channel_id || ycmux_mode == 2) {226 channel3_intr_assert();227 channel3_intr_enable(1);228 enable_channel3(1);229 if (vpif_config_data->chan_config[VPIF_CHANNEL3_VIDEO].clip_en)230 channel3_clipping_enable(1);231 }232 233 return 0;234 235err:236 list_for_each_entry_safe(buf, tmp, &common->dma_queue, list) {237 list_del(&buf->list);238 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);239 }240 spin_unlock_irqrestore(&common->irqlock, flags);241 242 return ret;243}244 245/**246 * vpif_stop_streaming : Stop the DMA engine247 * @vq: ptr to vb2_queue248 *249 * This callback stops the DMA engine and any remaining buffers250 * in the DMA queue are released.251 */252static void vpif_stop_streaming(struct vb2_queue *vq)253{254 struct channel_obj *ch = vb2_get_drv_priv(vq);255 struct common_obj *common;256 unsigned long flags;257 258 common = &ch->common[VPIF_VIDEO_INDEX];259 260 /* Disable channel */261 if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {262 enable_channel2(0);263 channel2_intr_enable(0);264 }265 if (VPIF_CHANNEL3_VIDEO == ch->channel_id || ycmux_mode == 2) {266 enable_channel3(0);267 channel3_intr_enable(0);268 }269 270 /* release all active buffers */271 spin_lock_irqsave(&common->irqlock, flags);272 if (common->cur_frm == common->next_frm) {273 vb2_buffer_done(&common->cur_frm->vb.vb2_buf,274 VB2_BUF_STATE_ERROR);275 } else {276 if (common->cur_frm)277 vb2_buffer_done(&common->cur_frm->vb.vb2_buf,278 VB2_BUF_STATE_ERROR);279 if (common->next_frm)280 vb2_buffer_done(&common->next_frm->vb.vb2_buf,281 VB2_BUF_STATE_ERROR);282 }283 284 while (!list_empty(&common->dma_queue)) {285 common->next_frm = list_entry(common->dma_queue.next,286 struct vpif_disp_buffer, list);287 list_del(&common->next_frm->list);288 vb2_buffer_done(&common->next_frm->vb.vb2_buf,289 VB2_BUF_STATE_ERROR);290 }291 spin_unlock_irqrestore(&common->irqlock, flags);292}293 294static const struct vb2_ops video_qops = {295 .queue_setup = vpif_buffer_queue_setup,296 .wait_prepare = vb2_ops_wait_prepare,297 .wait_finish = vb2_ops_wait_finish,298 .buf_prepare = vpif_buffer_prepare,299 .start_streaming = vpif_start_streaming,300 .stop_streaming = vpif_stop_streaming,301 .buf_queue = vpif_buffer_queue,302};303 304static void process_progressive_mode(struct common_obj *common)305{306 unsigned long addr;307 308 spin_lock(&common->irqlock);309 /* Get the next buffer from buffer queue */310 common->next_frm = list_entry(common->dma_queue.next,311 struct vpif_disp_buffer, list);312 /* Remove that buffer from the buffer queue */313 list_del(&common->next_frm->list);314 spin_unlock(&common->irqlock);315 316 /* Set top and bottom field addrs in VPIF registers */317 addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb.vb2_buf, 0);318 common->set_addr(addr + common->ytop_off,319 addr + common->ybtm_off,320 addr + common->ctop_off,321 addr + common->cbtm_off);322}323 324static void process_interlaced_mode(int fid, struct common_obj *common)325{326 /* device field id and local field id are in sync */327 /* If this is even field */328 if (0 == fid) {329 if (common->cur_frm == common->next_frm)330 return;331 332 /* one frame is displayed If next frame is333 * available, release cur_frm and move on */334 /* Copy frame display time */335 common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();336 /* Change status of the cur_frm */337 vb2_buffer_done(&common->cur_frm->vb.vb2_buf,338 VB2_BUF_STATE_DONE);339 /* Make cur_frm pointing to next_frm */340 common->cur_frm = common->next_frm;341 342 } else if (1 == fid) { /* odd field */343 spin_lock(&common->irqlock);344 if (list_empty(&common->dma_queue)345 || (common->cur_frm != common->next_frm)) {346 spin_unlock(&common->irqlock);347 return;348 }349 spin_unlock(&common->irqlock);350 /* one field is displayed configure the next351 * frame if it is available else hold on current352 * frame */353 /* Get next from the buffer queue */354 process_progressive_mode(common);355 }356}357 358/*359 * vpif_channel_isr: It changes status of the displayed buffer, takes next360 * buffer from the queue and sets its address in VPIF registers361 */362static irqreturn_t vpif_channel_isr(int irq, void *dev_id)363{364 struct vpif_device *dev = &vpif_obj;365 struct channel_obj *ch;366 struct common_obj *common;367 int fid = -1, i;368 int channel_id;369 370 channel_id = *(int *)(dev_id);371 if (!vpif_intr_status(channel_id + 2))372 return IRQ_NONE;373 374 ch = dev->dev[channel_id];375 for (i = 0; i < VPIF_NUMOBJECTS; i++) {376 common = &ch->common[i];377 /* If streaming is started in this channel */378 379 if (1 == ch->vpifparams.std_info.frm_fmt) {380 spin_lock(&common->irqlock);381 if (list_empty(&common->dma_queue)) {382 spin_unlock(&common->irqlock);383 continue;384 }385 spin_unlock(&common->irqlock);386 387 /* Progressive mode */388 if (!channel_first_int[i][channel_id]) {389 /* Mark status of the cur_frm to390 * done and unlock semaphore on it */391 common->cur_frm->vb.vb2_buf.timestamp =392 ktime_get_ns();393 vb2_buffer_done(&common->cur_frm->vb.vb2_buf,394 VB2_BUF_STATE_DONE);395 /* Make cur_frm pointing to next_frm */396 common->cur_frm = common->next_frm;397 }398 399 channel_first_int[i][channel_id] = 0;400 process_progressive_mode(common);401 } else {402 /* Interlaced mode */403 /* If it is first interrupt, ignore it */404 405 if (channel_first_int[i][channel_id]) {406 channel_first_int[i][channel_id] = 0;407 continue;408 }409 410 if (0 == i) {411 ch->field_id ^= 1;412 /* Get field id from VPIF registers */413 fid = vpif_channel_getfid(ch->channel_id + 2);414 /* If fid does not match with stored field id */415 if (fid != ch->field_id) {416 /* Make them in sync */417 if (0 == fid)418 ch->field_id = fid;419 420 return IRQ_HANDLED;421 }422 }423 process_interlaced_mode(fid, common);424 }425 }426 427 return IRQ_HANDLED;428}429 430static int vpif_update_std_info(struct channel_obj *ch)431{432 struct video_obj *vid_ch = &ch->video;433 struct vpif_params *vpifparams = &ch->vpifparams;434 struct vpif_channel_config_params *std_info = &vpifparams->std_info;435 const struct vpif_channel_config_params *config;436 437 int i;438 439 for (i = 0; i < vpif_ch_params_count; i++) {440 config = &vpif_ch_params[i];441 if (config->hd_sd == 0) {442 vpif_dbg(2, debug, "SD format\n");443 if (config->stdid & vid_ch->stdid) {444 memcpy(std_info, config, sizeof(*config));445 break;446 }447 }448 }449 450 if (i == vpif_ch_params_count) {451 vpif_dbg(1, debug, "Format not found\n");452 return -EINVAL;453 }454 455 return 0;456}457 458static int vpif_update_resolution(struct channel_obj *ch)459{460 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];461 struct video_obj *vid_ch = &ch->video;462 struct vpif_params *vpifparams = &ch->vpifparams;463 struct vpif_channel_config_params *std_info = &vpifparams->std_info;464 465 if (!vid_ch->stdid && !vid_ch->dv_timings.bt.height)466 return -EINVAL;467 468 if (vid_ch->stdid) {469 if (vpif_update_std_info(ch))470 return -EINVAL;471 }472 473 common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;474 common->fmt.fmt.pix.width = std_info->width;475 common->fmt.fmt.pix.height = std_info->height;476 vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",477 common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);478 479 /* Set height and width paramateres */480 common->height = std_info->height;481 common->width = std_info->width;482 common->fmt.fmt.pix.sizeimage = common->height * common->width * 2;483 484 if (vid_ch->stdid)485 common->fmt.fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;486 else487 common->fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;488 489 if (ch->vpifparams.std_info.frm_fmt)490 common->fmt.fmt.pix.field = V4L2_FIELD_NONE;491 else492 common->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;493 494 return 0;495}496 497/*498 * vpif_calculate_offsets: This function calculates buffers offset for Y and C499 * in the top and bottom field500 */501static void vpif_calculate_offsets(struct channel_obj *ch)502{503 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];504 struct vpif_params *vpifparams = &ch->vpifparams;505 enum v4l2_field field = common->fmt.fmt.pix.field;506 struct video_obj *vid_ch = &ch->video;507 unsigned int hpitch, sizeimage;508 509 if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {510 if (ch->vpifparams.std_info.frm_fmt)511 vid_ch->buf_field = V4L2_FIELD_NONE;512 else513 vid_ch->buf_field = V4L2_FIELD_INTERLACED;514 } else {515 vid_ch->buf_field = common->fmt.fmt.pix.field;516 }517 518 sizeimage = common->fmt.fmt.pix.sizeimage;519 520 hpitch = common->fmt.fmt.pix.bytesperline;521 if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||522 (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {523 common->ytop_off = 0;524 common->ybtm_off = hpitch;525 common->ctop_off = sizeimage / 2;526 common->cbtm_off = sizeimage / 2 + hpitch;527 } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {528 common->ytop_off = 0;529 common->ybtm_off = sizeimage / 4;530 common->ctop_off = sizeimage / 2;531 common->cbtm_off = common->ctop_off + sizeimage / 4;532 } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {533 common->ybtm_off = 0;534 common->ytop_off = sizeimage / 4;535 common->cbtm_off = sizeimage / 2;536 common->ctop_off = common->cbtm_off + sizeimage / 4;537 }538 539 if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||540 (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {541 vpifparams->video_params.storage_mode = 1;542 } else {543 vpifparams->video_params.storage_mode = 0;544 }545 546 if (ch->vpifparams.std_info.frm_fmt == 1) {547 vpifparams->video_params.hpitch =548 common->fmt.fmt.pix.bytesperline;549 } else {550 if ((field == V4L2_FIELD_ANY) ||551 (field == V4L2_FIELD_INTERLACED))552 vpifparams->video_params.hpitch =553 common->fmt.fmt.pix.bytesperline * 2;554 else555 vpifparams->video_params.hpitch =556 common->fmt.fmt.pix.bytesperline;557 }558 559 ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;560}561 562static void vpif_config_addr(struct channel_obj *ch, int muxmode)563{564 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];565 566 if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {567 common->set_addr = ch3_set_video_buf_addr;568 } else {569 if (2 == muxmode)570 common->set_addr = ch2_set_video_buf_addr_yc_nmux;571 else572 common->set_addr = ch2_set_video_buf_addr;573 }574}575 576/* functions implementing ioctls */577/**578 * vpif_querycap() - QUERYCAP handler579 * @file: file ptr580 * @priv: file handle581 * @cap: ptr to v4l2_capability structure582 */583static int vpif_querycap(struct file *file, void *priv,584 struct v4l2_capability *cap)585{586 struct vpif_display_config *config = vpif_dev->platform_data;587 588 strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));589 strscpy(cap->card, config->card_name, sizeof(cap->card));590 591 return 0;592}593 594static int vpif_enum_fmt_vid_out(struct file *file, void *priv,595 struct v4l2_fmtdesc *fmt)596{597 if (fmt->index != 0)598 return -EINVAL;599 600 /* Fill in the information about format */601 fmt->pixelformat = V4L2_PIX_FMT_YUV422P;602 return 0;603}604 605static int vpif_g_fmt_vid_out(struct file *file, void *priv,606 struct v4l2_format *fmt)607{608 struct video_device *vdev = video_devdata(file);609 struct channel_obj *ch = video_get_drvdata(vdev);610 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];611 612 /* Check the validity of the buffer type */613 if (common->fmt.type != fmt->type)614 return -EINVAL;615 616 if (vpif_update_resolution(ch))617 return -EINVAL;618 *fmt = common->fmt;619 return 0;620}621 622static int vpif_try_fmt_vid_out(struct file *file, void *priv,623 struct v4l2_format *fmt)624{625 struct video_device *vdev = video_devdata(file);626 struct channel_obj *ch = video_get_drvdata(vdev);627 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];628 struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;629 630 /*631 * to suppress v4l-compliance warnings silently correct632 * the pixelformat633 */634 if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)635 pixfmt->pixelformat = common->fmt.fmt.pix.pixelformat;636 637 if (vpif_update_resolution(ch))638 return -EINVAL;639 640 pixfmt->colorspace = common->fmt.fmt.pix.colorspace;641 pixfmt->field = common->fmt.fmt.pix.field;642 pixfmt->bytesperline = common->fmt.fmt.pix.width;643 pixfmt->width = common->fmt.fmt.pix.width;644 pixfmt->height = common->fmt.fmt.pix.height;645 pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height * 2;646 647 return 0;648}649 650static int vpif_s_fmt_vid_out(struct file *file, void *priv,651 struct v4l2_format *fmt)652{653 struct video_device *vdev = video_devdata(file);654 struct channel_obj *ch = video_get_drvdata(vdev);655 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];656 struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;657 int ret;658 659 if (vb2_is_busy(&common->buffer_queue))660 return -EBUSY;661 662 ret = vpif_try_fmt_vid_out(file, priv, fmt);663 if (ret)664 return ret;665 666 /* store the pix format in the channel object */667 common->fmt.fmt.pix = *pixfmt;668 669 /* store the format in the channel object */670 common->fmt = *fmt;671 return 0;672}673 674static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)675{676 struct vpif_display_config *config = vpif_dev->platform_data;677 struct video_device *vdev = video_devdata(file);678 struct channel_obj *ch = video_get_drvdata(vdev);679 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];680 struct vpif_display_chan_config *chan_cfg;681 struct v4l2_output output;682 int ret;683 684 if (!config->chan_config[ch->channel_id].outputs)685 return -ENODATA;686 687 chan_cfg = &config->chan_config[ch->channel_id];688 output = chan_cfg->outputs[ch->output_idx].output;689 if (output.capabilities != V4L2_OUT_CAP_STD)690 return -ENODATA;691 692 if (vb2_is_busy(&common->buffer_queue))693 return -EBUSY;694 695 696 if (!(std_id & VPIF_V4L2_STD))697 return -EINVAL;698 699 /* Call encoder subdevice function to set the standard */700 ch->video.stdid = std_id;701 memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));702 /* Get the information about the standard */703 if (vpif_update_resolution(ch))704 return -EINVAL;705 706 common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;707 708 ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,709 s_std_output, std_id);710 if (ret < 0) {711 vpif_err("Failed to set output standard\n");712 return ret;713 }714 715 ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,716 s_std, std_id);717 if (ret < 0)718 vpif_err("Failed to set standard for sub devices\n");719 return ret;720}721 722static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)723{724 struct vpif_display_config *config = vpif_dev->platform_data;725 struct video_device *vdev = video_devdata(file);726 struct channel_obj *ch = video_get_drvdata(vdev);727 struct vpif_display_chan_config *chan_cfg;728 struct v4l2_output output;729 730 if (!config->chan_config[ch->channel_id].outputs)731 return -ENODATA;732 733 chan_cfg = &config->chan_config[ch->channel_id];734 output = chan_cfg->outputs[ch->output_idx].output;735 if (output.capabilities != V4L2_OUT_CAP_STD)736 return -ENODATA;737 738 *std = ch->video.stdid;739 return 0;740}741 742static int vpif_enum_output(struct file *file, void *fh,743 struct v4l2_output *output)744{745 746 struct vpif_display_config *config = vpif_dev->platform_data;747 struct video_device *vdev = video_devdata(file);748 struct channel_obj *ch = video_get_drvdata(vdev);749 struct vpif_display_chan_config *chan_cfg;750 751 chan_cfg = &config->chan_config[ch->channel_id];752 if (output->index >= chan_cfg->output_count) {753 vpif_dbg(1, debug, "Invalid output index\n");754 return -EINVAL;755 }756 757 *output = chan_cfg->outputs[output->index].output;758 return 0;759}760 761/**762 * vpif_output_to_subdev() - Maps output to sub device763 * @vpif_cfg: global config ptr764 * @chan_cfg: channel config ptr765 * @index: Given output index from application766 *767 * lookup the sub device information for a given output index.768 * we report all the output to application. output table also769 * has sub device name for the each output770 */771static int772vpif_output_to_subdev(struct vpif_display_config *vpif_cfg,773 struct vpif_display_chan_config *chan_cfg, int index)774{775 struct vpif_subdev_info *subdev_info;776 const char *subdev_name;777 int i;778 779 vpif_dbg(2, debug, "vpif_output_to_subdev\n");780 781 if (!chan_cfg->outputs)782 return -1;783 784 subdev_name = chan_cfg->outputs[index].subdev_name;785 if (!subdev_name)786 return -1;787 788 /* loop through the sub device list to get the sub device info */789 for (i = 0; i < vpif_cfg->subdev_count; i++) {790 subdev_info = &vpif_cfg->subdevinfo[i];791 if (!strcmp(subdev_info->name, subdev_name))792 return i;793 }794 return -1;795}796 797/**798 * vpif_set_output() - Select an output799 * @vpif_cfg: global config ptr800 * @ch: channel801 * @index: Given output index from application802 *803 * Select the given output.804 */805static int vpif_set_output(struct vpif_display_config *vpif_cfg,806 struct channel_obj *ch, int index)807{808 struct vpif_display_chan_config *chan_cfg =809 &vpif_cfg->chan_config[ch->channel_id];810 struct v4l2_subdev *sd = NULL;811 u32 input = 0, output = 0;812 int sd_index;813 int ret;814 815 sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index);816 if (sd_index >= 0)817 sd = vpif_obj.sd[sd_index];818 819 if (sd) {820 input = chan_cfg->outputs[index].input_route;821 output = chan_cfg->outputs[index].output_route;822 ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0);823 if (ret < 0 && ret != -ENOIOCTLCMD) {824 vpif_err("Failed to set output\n");825 return ret;826 }827 828 }829 ch->output_idx = index;830 ch->sd = sd;831 if (chan_cfg->outputs)832 /* update tvnorms from the sub device output info */833 ch->video_dev.tvnorms = chan_cfg->outputs[index].output.std;834 return 0;835}836 837static int vpif_s_output(struct file *file, void *priv, unsigned int i)838{839 struct vpif_display_config *config = vpif_dev->platform_data;840 struct video_device *vdev = video_devdata(file);841 struct channel_obj *ch = video_get_drvdata(vdev);842 struct vpif_display_chan_config *chan_cfg;843 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];844 845 if (vb2_is_busy(&common->buffer_queue))846 return -EBUSY;847 848 chan_cfg = &config->chan_config[ch->channel_id];849 850 if (i >= chan_cfg->output_count)851 return -EINVAL;852 853 return vpif_set_output(config, ch, i);854}855 856static int vpif_g_output(struct file *file, void *priv, unsigned int *i)857{858 struct video_device *vdev = video_devdata(file);859 struct channel_obj *ch = video_get_drvdata(vdev);860 861 *i = ch->output_idx;862 863 return 0;864}865 866/**867 * vpif_enum_dv_timings() - ENUM_DV_TIMINGS handler868 * @file: file ptr869 * @priv: file handle870 * @timings: input timings871 */872static int873vpif_enum_dv_timings(struct file *file, void *priv,874 struct v4l2_enum_dv_timings *timings)875{876 struct vpif_display_config *config = vpif_dev->platform_data;877 struct video_device *vdev = video_devdata(file);878 struct channel_obj *ch = video_get_drvdata(vdev);879 struct vpif_display_chan_config *chan_cfg;880 struct v4l2_output output;881 int ret;882 883 if (!config->chan_config[ch->channel_id].outputs)884 return -ENODATA;885 886 chan_cfg = &config->chan_config[ch->channel_id];887 output = chan_cfg->outputs[ch->output_idx].output;888 if (output.capabilities != V4L2_OUT_CAP_DV_TIMINGS)889 return -ENODATA;890 891 timings->pad = 0;892 893 ret = v4l2_subdev_call(ch->sd, pad, enum_dv_timings, timings);894 if (ret == -ENOIOCTLCMD || ret == -ENODEV)895 return -EINVAL;896 return ret;897}898 899/**900 * vpif_s_dv_timings() - S_DV_TIMINGS handler901 * @file: file ptr902 * @priv: file handle903 * @timings: digital video timings904 */905static int vpif_s_dv_timings(struct file *file, void *priv,906 struct v4l2_dv_timings *timings)907{908 struct vpif_display_config *config = vpif_dev->platform_data;909 struct video_device *vdev = video_devdata(file);910 struct channel_obj *ch = video_get_drvdata(vdev);911 struct vpif_params *vpifparams = &ch->vpifparams;912 struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];913 struct vpif_channel_config_params *std_info = &vpifparams->std_info;914 struct video_obj *vid_ch = &ch->video;915 struct v4l2_bt_timings *bt = &vid_ch->dv_timings.bt;916 struct vpif_display_chan_config *chan_cfg;917 struct v4l2_output output;918 int ret;919 920 if (!config->chan_config[ch->channel_id].outputs)921 return -ENODATA;922 923 chan_cfg = &config->chan_config[ch->channel_id];924 output = chan_cfg->outputs[ch->output_idx].output;925 if (output.capabilities != V4L2_OUT_CAP_DV_TIMINGS)926 return -ENODATA;927 928 if (vb2_is_busy(&common->buffer_queue))929 return -EBUSY;930 931 if (timings->type != V4L2_DV_BT_656_1120) {932 vpif_dbg(2, debug, "Timing type not defined\n");933 return -EINVAL;934 }935 936 /* Configure subdevice timings, if any */937 ret = v4l2_subdev_call(ch->sd, pad, s_dv_timings, 0, timings);938 if (ret == -ENOIOCTLCMD || ret == -ENODEV)939 ret = 0;940 if (ret < 0) {941 vpif_dbg(2, debug, "Error setting custom DV timings\n");942 return ret;943 }944 945 if (!(timings->bt.width && timings->bt.height &&946 (timings->bt.hbackporch ||947 timings->bt.hfrontporch ||948 timings->bt.hsync) &&949 timings->bt.vfrontporch &&950 (timings->bt.vbackporch ||951 timings->bt.vsync))) {952 vpif_dbg(2, debug, "Timings for width, height, horizontal back porch, horizontal sync, horizontal front porch, vertical back porch, vertical sync and vertical back porch must be defined\n");953 return -EINVAL;954 }955 956 vid_ch->dv_timings = *timings;957 958 /* Configure video port timings */959 960 std_info->eav2sav = V4L2_DV_BT_BLANKING_WIDTH(bt) - 8;961 std_info->sav2eav = bt->width;962 963 std_info->l1 = 1;964 std_info->l3 = bt->vsync + bt->vbackporch + 1;965 966 std_info->vsize = V4L2_DV_BT_FRAME_HEIGHT(bt);967 if (bt->interlaced) {968 if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {969 std_info->l5 = std_info->vsize/2 -970 (bt->vfrontporch - 1);971 std_info->l7 = std_info->vsize/2 + 1;972 std_info->l9 = std_info->l7 + bt->il_vsync +973 bt->il_vbackporch + 1;974 std_info->l11 = std_info->vsize -975 (bt->il_vfrontporch - 1);976 } else {977 vpif_dbg(2, debug, "Required timing values for interlaced BT format missing\n");978 return -EINVAL;979 }980 } else {981 std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);982 }983 strscpy(std_info->name, "Custom timings BT656/1120",984 sizeof(std_info->name));985 std_info->width = bt->width;986 std_info->height = bt->height;987 std_info->frm_fmt = bt->interlaced ? 0 : 1;988 std_info->ycmux_mode = 0;989 std_info->capture_format = 0;990 std_info->vbi_supported = 0;991 std_info->hd_sd = 1;992 std_info->stdid = 0;993 vid_ch->stdid = 0;994 995 return 0;996}997 998/**999 * vpif_g_dv_timings() - G_DV_TIMINGS handler1000 * @file: file ptr1001 * @priv: file handle1002 * @timings: digital video timings1003 */1004static int vpif_g_dv_timings(struct file *file, void *priv,1005 struct v4l2_dv_timings *timings)1006{1007 struct vpif_display_config *config = vpif_dev->platform_data;1008 struct video_device *vdev = video_devdata(file);1009 struct channel_obj *ch = video_get_drvdata(vdev);1010 struct vpif_display_chan_config *chan_cfg;1011 struct video_obj *vid_ch = &ch->video;1012 struct v4l2_output output;1013 1014 if (!config->chan_config[ch->channel_id].outputs)1015 goto error;1016 1017 chan_cfg = &config->chan_config[ch->channel_id];1018 output = chan_cfg->outputs[ch->output_idx].output;1019 1020 if (output.capabilities != V4L2_OUT_CAP_DV_TIMINGS)1021 goto error;1022 1023 *timings = vid_ch->dv_timings;1024 1025 return 0;1026error:1027 return -ENODATA;1028}1029 1030/*1031 * vpif_log_status() - Status information1032 * @file: file ptr1033 * @priv: file handle1034 *1035 * Returns zero.1036 */1037static int vpif_log_status(struct file *filep, void *priv)1038{1039 /* status for sub devices */1040 v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);1041 1042 return 0;1043}1044 1045/* vpif display ioctl operations */1046static const struct v4l2_ioctl_ops vpif_ioctl_ops = {1047 .vidioc_querycap = vpif_querycap,1048 .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,1049 .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,1050 .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,1051 .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,1052 1053 .vidioc_reqbufs = vb2_ioctl_reqbufs,1054 .vidioc_create_bufs = vb2_ioctl_create_bufs,1055 .vidioc_querybuf = vb2_ioctl_querybuf,1056 .vidioc_qbuf = vb2_ioctl_qbuf,1057 .vidioc_dqbuf = vb2_ioctl_dqbuf,1058 .vidioc_expbuf = vb2_ioctl_expbuf,1059 .vidioc_streamon = vb2_ioctl_streamon,1060 .vidioc_streamoff = vb2_ioctl_streamoff,1061 1062 .vidioc_s_std = vpif_s_std,1063 .vidioc_g_std = vpif_g_std,1064 1065 .vidioc_enum_output = vpif_enum_output,1066 .vidioc_s_output = vpif_s_output,1067 .vidioc_g_output = vpif_g_output,1068 1069 .vidioc_enum_dv_timings = vpif_enum_dv_timings,1070 .vidioc_s_dv_timings = vpif_s_dv_timings,1071 .vidioc_g_dv_timings = vpif_g_dv_timings,1072 1073 .vidioc_log_status = vpif_log_status,1074};1075 1076static const struct v4l2_file_operations vpif_fops = {1077 .owner = THIS_MODULE,1078 .open = v4l2_fh_open,1079 .release = vb2_fop_release,1080 .unlocked_ioctl = video_ioctl2,1081 .mmap = vb2_fop_mmap,1082 .poll = vb2_fop_poll1083};1084 1085/*Configure the channels, buffer sizei, request irq */1086static int initialize_vpif(void)1087{1088 int free_channel_objects_index;1089 int err, i, j;1090 1091 /* Allocate memory for six channel objects */1092 for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {1093 vpif_obj.dev[i] =1094 kzalloc(sizeof(struct channel_obj), GFP_KERNEL);1095 /* If memory allocation fails, return error */1096 if (!vpif_obj.dev[i]) {1097 free_channel_objects_index = i;1098 err = -ENOMEM;1099 goto vpif_init_free_channel_objects;1100 }1101 }1102 1103 return 0;1104 1105vpif_init_free_channel_objects:1106 for (j = 0; j < free_channel_objects_index; j++)1107 kfree(vpif_obj.dev[j]);1108 return err;1109}1110 1111static void free_vpif_objs(void)1112{1113 int i;1114 1115 for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)1116 kfree(vpif_obj.dev[i]);1117}1118 1119static int vpif_probe_complete(void)1120{1121 struct common_obj *common;1122 struct video_device *vdev;1123 struct channel_obj *ch;1124 struct vb2_queue *q;1125 int j, err, k;1126 1127 for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {1128 ch = vpif_obj.dev[j];1129 /* Initialize field of the channel objects */1130 for (k = 0; k < VPIF_NUMOBJECTS; k++) {1131 common = &ch->common[k];1132 spin_lock_init(&common->irqlock);1133 mutex_init(&common->lock);1134 common->set_addr = NULL;1135 common->ytop_off = 0;1136 common->ybtm_off = 0;1137 common->ctop_off = 0;1138 common->cbtm_off = 0;1139 common->cur_frm = NULL;1140 common->next_frm = NULL;1141 memset(&common->fmt, 0, sizeof(common->fmt));1142 }1143 ch->initialized = 0;1144 if (vpif_obj.config->subdev_count)1145 ch->sd = vpif_obj.sd[0];1146 ch->channel_id = j;1147 1148 memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));1149 1150 ch->common[VPIF_VIDEO_INDEX].fmt.type =1151 V4L2_BUF_TYPE_VIDEO_OUTPUT;1152 1153 /* select output 0 */1154 err = vpif_set_output(vpif_obj.config, ch, 0);1155 if (err)1156 goto probe_out;1157 1158 /* set initial format */1159 ch->video.stdid = V4L2_STD_525_60;1160 memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));1161 vpif_update_resolution(ch);1162 1163 /* Initialize vb2 queue */1164 q = &common->buffer_queue;1165 q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;1166 q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;1167 q->drv_priv = ch;1168 q->ops = &video_qops;1169 q->mem_ops = &vb2_dma_contig_memops;1170 q->buf_struct_size = sizeof(struct vpif_disp_buffer);1171 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;1172 q->min_queued_buffers = 1;1173 q->lock = &common->lock;1174 q->dev = vpif_dev;1175 err = vb2_queue_init(q);1176 if (err) {1177 vpif_err("vpif_display: vb2_queue_init() failed\n");1178 goto probe_out;1179 }1180 1181 INIT_LIST_HEAD(&common->dma_queue);1182 1183 /* register video device */1184 vpif_dbg(1, debug, "channel=%p,channel->video_dev=%p\n",1185 ch, &ch->video_dev);1186 1187 /* Initialize the video_device structure */1188 vdev = &ch->video_dev;1189 strscpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));1190 vdev->release = video_device_release_empty;1191 vdev->fops = &vpif_fops;1192 vdev->ioctl_ops = &vpif_ioctl_ops;1193 vdev->v4l2_dev = &vpif_obj.v4l2_dev;1194 vdev->vfl_dir = VFL_DIR_TX;1195 vdev->queue = q;1196 vdev->lock = &common->lock;1197 vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;1198 video_set_drvdata(&ch->video_dev, ch);1199 err = video_register_device(vdev, VFL_TYPE_VIDEO,1200 (j ? 3 : 2));1201 if (err < 0)1202 goto probe_out;1203 }1204 1205 return 0;1206 1207probe_out:1208 for (k = 0; k < j; k++) {1209 ch = vpif_obj.dev[k];1210 video_unregister_device(&ch->video_dev);1211 }1212 return err;1213}1214 1215/*1216 * vpif_probe: This function creates device entries by register itself to the1217 * V4L2 driver and initializes fields of each channel objects1218 */1219static __init int vpif_probe(struct platform_device *pdev)1220{1221 struct vpif_subdev_info *subdevdata;1222 struct i2c_adapter *i2c_adap;1223 int subdev_count;1224 int res_idx = 0;1225 int i, err;1226 1227 if (!pdev->dev.platform_data) {1228 dev_warn(&pdev->dev, "Missing platform data. Giving up.\n");1229 return -EINVAL;1230 }1231 1232 vpif_dev = &pdev->dev;1233 err = initialize_vpif();1234 1235 if (err) {1236 v4l2_err(vpif_dev->driver, "Error initializing vpif\n");1237 return err;1238 }1239 1240 err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);1241 if (err) {1242 v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");1243 goto vpif_free;1244 }1245 1246 do {1247 int irq;1248 1249 err = platform_get_irq_optional(pdev, res_idx);1250 if (err < 0 && err != -ENXIO)1251 goto vpif_unregister;1252 if (err > 0)1253 irq = err;1254 else1255 break;1256 1257 err = devm_request_irq(&pdev->dev, irq, vpif_channel_isr,1258 IRQF_SHARED, VPIF_DRIVER_NAME,1259 (void *)(&vpif_obj.dev[res_idx]->channel_id));1260 if (err) {1261 vpif_err("VPIF IRQ request failed\n");1262 goto vpif_unregister;1263 }1264 } while (++res_idx);1265 1266 vpif_obj.config = pdev->dev.platform_data;1267 subdev_count = vpif_obj.config->subdev_count;1268 subdevdata = vpif_obj.config->subdevinfo;1269 vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL);1270 if (!vpif_obj.sd) {1271 err = -ENOMEM;1272 goto vpif_unregister;1273 }1274 1275 i2c_adap = i2c_get_adapter(vpif_obj.config->i2c_adapter_id);1276 for (i = 0; i < subdev_count; i++) {1277 vpif_obj.sd[i] =1278 v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,1279 i2c_adap,1280 &subdevdata[i].board_info,1281 NULL);1282 if (!vpif_obj.sd[i]) {1283 vpif_err("Error registering v4l2 subdevice\n");1284 err = -ENODEV;1285 goto probe_subdev_out;1286 }1287 1288 vpif_obj.sd[i]->grp_id = 1 << i;1289 }1290 err = vpif_probe_complete();1291 if (err)1292 goto probe_subdev_out;1293 1294 return 0;1295 1296probe_subdev_out:1297 kfree(vpif_obj.sd);1298vpif_unregister:1299 v4l2_device_unregister(&vpif_obj.v4l2_dev);1300vpif_free:1301 free_vpif_objs();1302 1303 return err;1304}1305 1306/*1307 * vpif_remove: It un-register channels from V4L2 driver1308 */1309static void vpif_remove(struct platform_device *device)1310{1311 struct channel_obj *ch;1312 int i;1313 1314 v4l2_device_unregister(&vpif_obj.v4l2_dev);1315 1316 kfree(vpif_obj.sd);1317 /* un-register device */1318 for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {1319 /* Get the pointer to the channel object */1320 ch = vpif_obj.dev[i];1321 /* Unregister video device */1322 video_unregister_device(&ch->video_dev);1323 }1324 free_vpif_objs();1325}1326 1327#ifdef CONFIG_PM_SLEEP1328static int vpif_suspend(struct device *dev)1329{1330 struct common_obj *common;1331 struct channel_obj *ch;1332 int i;1333 1334 for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {1335 /* Get the pointer to the channel object */1336 ch = vpif_obj.dev[i];1337 common = &ch->common[VPIF_VIDEO_INDEX];1338 1339 if (!vb2_start_streaming_called(&common->buffer_queue))1340 continue;1341 1342 mutex_lock(&common->lock);1343 /* Disable channel */1344 if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {1345 enable_channel2(0);1346 channel2_intr_enable(0);1347 }1348 if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||1349 ycmux_mode == 2) {1350 enable_channel3(0);1351 channel3_intr_enable(0);1352 }1353 mutex_unlock(&common->lock);1354 }1355 1356 return 0;1357}1358 1359static int vpif_resume(struct device *dev)1360{1361 1362 struct common_obj *common;1363 struct channel_obj *ch;1364 int i;1365 1366 for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {1367 /* Get the pointer to the channel object */1368 ch = vpif_obj.dev[i];1369 common = &ch->common[VPIF_VIDEO_INDEX];1370 1371 if (!vb2_start_streaming_called(&common->buffer_queue))1372 continue;1373 1374 mutex_lock(&common->lock);1375 /* Enable channel */1376 if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {1377 enable_channel2(1);1378 channel2_intr_enable(1);1379 }1380 if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||1381 ycmux_mode == 2) {1382 enable_channel3(1);1383 channel3_intr_enable(1);1384 }1385 mutex_unlock(&common->lock);1386 }1387 1388 return 0;1389}1390 1391#endif1392 1393static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume);1394 1395static __refdata struct platform_driver vpif_driver = {1396 .driver = {1397 .name = VPIF_DRIVER_NAME,1398 .pm = &vpif_pm_ops,1399 },1400 .probe = vpif_probe,1401 .remove_new = vpif_remove,1402};1403 1404module_platform_driver(vpif_driver);1405