1*16216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20c0d06caSMauro Carvalho Chehab /* 30c0d06caSMauro Carvalho Chehab au0828-vbi.c - VBI driver for au0828 40c0d06caSMauro Carvalho Chehab 50c0d06caSMauro Carvalho Chehab Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> 60c0d06caSMauro Carvalho Chehab 70c0d06caSMauro Carvalho Chehab This work was sponsored by GetWellNetwork Inc. 80c0d06caSMauro Carvalho Chehab 90c0d06caSMauro Carvalho Chehab */ 100c0d06caSMauro Carvalho Chehab 1183afb32aSMauro Carvalho Chehab #include "au0828.h" 1283afb32aSMauro Carvalho Chehab 130c0d06caSMauro Carvalho Chehab #include <linux/kernel.h> 140c0d06caSMauro Carvalho Chehab #include <linux/module.h> 150c0d06caSMauro Carvalho Chehab #include <linux/init.h> 160c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 170c0d06caSMauro Carvalho Chehab 180c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------ */ 190c0d06caSMauro Carvalho Chehab 20df9ecb0cSHans Verkuil static int vbi_queue_setup(struct vb2_queue *vq, 2105439b1aSShuah Khan unsigned int *nbuffers, unsigned int *nplanes, 2236c0f8b3SHans Verkuil unsigned int sizes[], struct device *alloc_devs[]) 230c0d06caSMauro Carvalho Chehab { 2405439b1aSShuah Khan struct au0828_dev *dev = vb2_get_drv_priv(vq); 25df9ecb0cSHans Verkuil unsigned long size = dev->vbi_width * dev->vbi_height * 2; 260c0d06caSMauro Carvalho Chehab 27df9ecb0cSHans Verkuil if (*nplanes) 28df9ecb0cSHans Verkuil return sizes[0] < size ? -EINVAL : 0; 2905439b1aSShuah Khan *nplanes = 1; 3005439b1aSShuah Khan sizes[0] = size; 3105439b1aSShuah Khan return 0; 320c0d06caSMauro Carvalho Chehab } 330c0d06caSMauro Carvalho Chehab 3405439b1aSShuah Khan static int vbi_buffer_prepare(struct vb2_buffer *vb) 3505439b1aSShuah Khan { 3605439b1aSShuah Khan struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 3705439b1aSShuah Khan unsigned long size; 380c0d06caSMauro Carvalho Chehab 3905439b1aSShuah Khan size = dev->vbi_width * dev->vbi_height * 2; 4005439b1aSShuah Khan 4105439b1aSShuah Khan if (vb2_plane_size(vb, 0) < size) { 4205439b1aSShuah Khan pr_err("%s data will not fit into plane (%lu < %lu)\n", 4305439b1aSShuah Khan __func__, vb2_plane_size(vb, 0), size); 4405439b1aSShuah Khan return -EINVAL; 4505439b1aSShuah Khan } 462d700715SJunghak Sung vb2_set_plane_payload(vb, 0, size); 4705439b1aSShuah Khan 4805439b1aSShuah Khan return 0; 490c0d06caSMauro Carvalho Chehab } 500c0d06caSMauro Carvalho Chehab 510c0d06caSMauro Carvalho Chehab static void 5205439b1aSShuah Khan vbi_buffer_queue(struct vb2_buffer *vb) 530c0d06caSMauro Carvalho Chehab { 5405439b1aSShuah Khan struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 552d700715SJunghak Sung struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 562d700715SJunghak Sung struct au0828_buffer *buf = 572d700715SJunghak Sung container_of(vbuf, struct au0828_buffer, vb); 5805439b1aSShuah Khan struct au0828_dmaqueue *vbiq = &dev->vbiq; 5905439b1aSShuah Khan unsigned long flags = 0; 6005439b1aSShuah Khan 6105439b1aSShuah Khan buf->mem = vb2_plane_vaddr(vb, 0); 6205439b1aSShuah Khan buf->length = vb2_plane_size(vb, 0); 6305439b1aSShuah Khan 6405439b1aSShuah Khan spin_lock_irqsave(&dev->slock, flags); 6505439b1aSShuah Khan list_add_tail(&buf->list, &vbiq->active); 6605439b1aSShuah Khan spin_unlock_irqrestore(&dev->slock, flags); 670c0d06caSMauro Carvalho Chehab } 680c0d06caSMauro Carvalho Chehab 69ac71484eSBhumika Goyal const struct vb2_ops au0828_vbi_qops = { 7005439b1aSShuah Khan .queue_setup = vbi_queue_setup, 7105439b1aSShuah Khan .buf_prepare = vbi_buffer_prepare, 7205439b1aSShuah Khan .buf_queue = vbi_buffer_queue, 7305439b1aSShuah Khan .start_streaming = au0828_start_analog_streaming, 7405439b1aSShuah Khan .stop_streaming = au0828_stop_vbi_streaming, 7505439b1aSShuah Khan .wait_prepare = vb2_ops_wait_prepare, 7605439b1aSShuah Khan .wait_finish = vb2_ops_wait_finish, 770c0d06caSMauro Carvalho Chehab }; 78