162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci au0828-vbi.c - VBI driver for au0828 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci This work was sponsored by GetWellNetwork Inc. 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "au0828.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <media/v4l2-mc.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int vbi_queue_setup(struct vb2_queue *vq, 2262306a36Sopenharmony_ci unsigned int *nbuffers, unsigned int *nplanes, 2362306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct au0828_dev *dev = vb2_get_drv_priv(vq); 2662306a36Sopenharmony_ci unsigned long size = dev->vbi_width * dev->vbi_height * 2; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (*nplanes) 2962306a36Sopenharmony_ci return sizes[0] < size ? -EINVAL : 0; 3062306a36Sopenharmony_ci *nplanes = 1; 3162306a36Sopenharmony_ci sizes[0] = size; 3262306a36Sopenharmony_ci return 0; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int vbi_buffer_prepare(struct vb2_buffer *vb) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 3862306a36Sopenharmony_ci unsigned long size; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci size = dev->vbi_width * dev->vbi_height * 2; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) { 4362306a36Sopenharmony_ci pr_err("%s data will not fit into plane (%lu < %lu)\n", 4462306a36Sopenharmony_ci __func__, vb2_plane_size(vb, 0), size); 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void 5362306a36Sopenharmony_civbi_buffer_queue(struct vb2_buffer *vb) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 5662306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 5762306a36Sopenharmony_ci struct au0828_buffer *buf = 5862306a36Sopenharmony_ci container_of(vbuf, struct au0828_buffer, vb); 5962306a36Sopenharmony_ci struct au0828_dmaqueue *vbiq = &dev->vbiq; 6062306a36Sopenharmony_ci unsigned long flags = 0; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci buf->mem = vb2_plane_vaddr(vb, 0); 6362306a36Sopenharmony_ci buf->length = vb2_plane_size(vb, 0); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 6662306a36Sopenharmony_ci list_add_tail(&buf->list, &vbiq->active); 6762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciconst struct vb2_ops au0828_vbi_qops = { 7162306a36Sopenharmony_ci .queue_setup = vbi_queue_setup, 7262306a36Sopenharmony_ci .buf_prepare = vbi_buffer_prepare, 7362306a36Sopenharmony_ci .buf_queue = vbi_buffer_queue, 7462306a36Sopenharmony_ci .prepare_streaming = v4l_vb2q_enable_media_source, 7562306a36Sopenharmony_ci .start_streaming = au0828_start_analog_streaming, 7662306a36Sopenharmony_ci .stop_streaming = au0828_stop_vbi_streaming, 7762306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 7862306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 7962306a36Sopenharmony_ci}; 80