linux/drivers/media/platform/renesas/rcar_drif.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * R-Car Gen3 Digital Radio Interface (DRIF) driver
 *
 * Copyright (C) 2017 Renesas Electronics Corporation
 */

/*
 * The R-Car DRIF is a receive only MSIOF like controller with an
 * external master device driving the SCK. It receives data into a FIFO,
 * then this driver uses the SYS-DMAC engine to move the data from
 * the device to memory.
 *
 * Each DRIF channel DRIFx (as per datasheet) contains two internal
 * channels DRIFx0 & DRIFx1 within itself with each having its own resources
 * like module clk, register set, irq and dma. These internal channels share
 * common CLK & SYNC from master. The two data pins D0 & D1 shall be
 * considered to represent the two internal channels. This internal split
 * is not visible to the master device.
 *
 * Depending on the master device, a DRIF channel can use
 *  (1) both internal channels (D0 & D1) to receive data in parallel (or)
 *  (2) one internal channel (D0 or D1) to receive data
 *
 * The primary design goal of this controller is to act as a Digital Radio
 * Interface that receives digital samples from a tuner device. Hence the
 * driver exposes the device as a V4L2 SDR device. In order to qualify as
 * a V4L2 SDR device, it should possess a tuner interface as mandated by the
 * framework. This driver expects a tuner driver (sub-device) to bind
 * asynchronously with this device and the combined drivers shall expose
 * a V4L2 compliant SDR device. The DRIF driver is independent of the
 * tuner vendor.
 *
 * The DRIF h/w can support I2S mode and Frame start synchronization pulse mode.
 * This driver is tested for I2S mode only because of the availability of
 * suitable master devices. Hence, not all configurable options of DRIF h/w
 * like lsb/msb first, syncdl, dtdl etc. are exposed via DT and I2S defaults
 * are used. These can be exposed later if needed after testing.
 */
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/ioctl.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>

/* DRIF register offsets */
#define RCAR_DRIF_SITMDR1
#define RCAR_DRIF_SITMDR2
#define RCAR_DRIF_SITMDR3
#define RCAR_DRIF_SIRMDR1
#define RCAR_DRIF_SIRMDR2
#define RCAR_DRIF_SIRMDR3
#define RCAR_DRIF_SICTR
#define RCAR_DRIF_SIFCTR
#define RCAR_DRIF_SISTR
#define RCAR_DRIF_SIIER
#define RCAR_DRIF_SIRFDR

#define RCAR_DRIF_RFOVF
#define RCAR_DRIF_RFUDF
#define RCAR_DRIF_RFSERR
#define RCAR_DRIF_REOF
#define RCAR_DRIF_RDREQ
#define RCAR_DRIF_RFFUL

/* SIRMDR1 */
#define RCAR_DRIF_SIRMDR1_SYNCMD_FRAME
#define RCAR_DRIF_SIRMDR1_SYNCMD_LR

#define RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH
#define RCAR_DRIF_SIRMDR1_SYNCAC_POL_LOW

#define RCAR_DRIF_SIRMDR1_MSB_FIRST
#define RCAR_DRIF_SIRMDR1_LSB_FIRST

#define RCAR_DRIF_SIRMDR1_DTDL_0
#define RCAR_DRIF_SIRMDR1_DTDL_1
#define RCAR_DRIF_SIRMDR1_DTDL_2
#define RCAR_DRIF_SIRMDR1_DTDL_0PT5
#define RCAR_DRIF_SIRMDR1_DTDL_1PT5

#define RCAR_DRIF_SIRMDR1_SYNCDL_0
#define RCAR_DRIF_SIRMDR1_SYNCDL_1
#define RCAR_DRIF_SIRMDR1_SYNCDL_2
#define RCAR_DRIF_SIRMDR1_SYNCDL_3
#define RCAR_DRIF_SIRMDR1_SYNCDL_0PT5
#define RCAR_DRIF_SIRMDR1_SYNCDL_1PT5

#define RCAR_DRIF_MDR_GRPCNT(n)
#define RCAR_DRIF_MDR_BITLEN(n)
#define RCAR_DRIF_MDR_WDCNT(n)

/* Hidden Transmit register that controls CLK & SYNC */
#define RCAR_DRIF_SITMDR1_PCON

#define RCAR_DRIF_SICTR_RX_RISING_EDGE
#define RCAR_DRIF_SICTR_RX_EN
#define RCAR_DRIF_SICTR_RESET

/* Constants */
#define RCAR_DRIF_NUM_HWBUFS
#define RCAR_DRIF_MAX_DEVS
#define RCAR_DRIF_DEFAULT_NUM_HWBUFS
#define RCAR_DRIF_DEFAULT_HWBUF_SIZE
#define RCAR_DRIF_MAX_CHANNEL
#define RCAR_SDR_BUFFER_SIZE

/* Internal buffer status flags */
#define RCAR_DRIF_BUF_DONE
#define RCAR_DRIF_BUF_OVERFLOW

#define to_rcar_drif_buf_pair(sdr, ch_num, idx)

#define for_each_rcar_drif_channel(ch, ch_mask)

/* Debug */
#define rdrif_dbg(sdr, fmt, arg...)

#define rdrif_err(sdr, fmt, arg...)

/* Stream formats */
struct rcar_drif_format {};

/* Format descriptions for capture */
static const struct rcar_drif_format formats[] =;

/* Buffer for a received frame from one or both internal channels */
struct rcar_drif_frame_buf {};

/* OF graph endpoint's V4L2 async data */
struct rcar_drif_graph_ep {};

/* DMA buffer */
struct rcar_drif_hwbuf {};

/* Internal channel */
struct rcar_drif {};

/* DRIF V4L2 SDR */
struct rcar_drif_sdr {};

/* Register access functions */
static void rcar_drif_write(struct rcar_drif *ch, u32 offset, u32 data)
{}

static u32 rcar_drif_read(struct rcar_drif *ch, u32 offset)
{}

/* Release DMA channels */
static void rcar_drif_release_dmachannels(struct rcar_drif_sdr *sdr)
{}

/* Allocate DMA channels */
static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr)
{}

/* Release queued vb2 buffers */
static void rcar_drif_release_queued_bufs(struct rcar_drif_sdr *sdr,
					  enum vb2_buffer_state state)
{}

/* Set MDR defaults */
static inline void rcar_drif_set_mdr1(struct rcar_drif_sdr *sdr)
{}

/* Set DRIF receive format */
static int rcar_drif_set_format(struct rcar_drif_sdr *sdr)
{}

/* Release DMA buffers */
static void rcar_drif_release_buf(struct rcar_drif_sdr *sdr)
{}

/* Request DMA buffers */
static int rcar_drif_request_buf(struct rcar_drif_sdr *sdr)
{}

/* Setup vb_queue minimum buffer requirements */
static int rcar_drif_queue_setup(struct vb2_queue *vq,
			unsigned int *num_buffers, unsigned int *num_planes,
			unsigned int sizes[], struct device *alloc_devs[])
{}

/* Enqueue buffer */
static void rcar_drif_buf_queue(struct vb2_buffer *vb)
{}

/* Get a frame buf from list */
static struct rcar_drif_frame_buf *
rcar_drif_get_fbuf(struct rcar_drif_sdr *sdr)
{}

/* Helpers to set/clear buf pair status */
static inline bool rcar_drif_bufs_done(struct rcar_drif_hwbuf **buf)
{}

static inline bool rcar_drif_bufs_overflow(struct rcar_drif_hwbuf **buf)
{}

static inline void rcar_drif_bufs_clear(struct rcar_drif_hwbuf **buf,
					unsigned int bit)
{}

/* Channel DMA complete */
static void rcar_drif_channel_complete(struct rcar_drif *ch, u32 idx)
{}

/* DMA callback for each stage */
static void rcar_drif_dma_complete(void *dma_async_param)
{}

static int rcar_drif_qbuf(struct rcar_drif *ch)
{}

/* Enable reception */
static int rcar_drif_enable_rx(struct rcar_drif_sdr *sdr)
{}

/* Disable reception */
static void rcar_drif_disable_rx(struct rcar_drif_sdr *sdr)
{}

/* Stop channel */
static void rcar_drif_stop_channel(struct rcar_drif *ch)
{}

/* Stop receive operation */
static void rcar_drif_stop(struct rcar_drif_sdr *sdr)
{}

/* Start channel */
static int rcar_drif_start_channel(struct rcar_drif *ch)
{}

/* Start receive operation */
static int rcar_drif_start(struct rcar_drif_sdr *sdr)
{}

/* Start streaming */
static int rcar_drif_start_streaming(struct vb2_queue *vq, unsigned int count)
{}

/* Stop streaming */
static void rcar_drif_stop_streaming(struct vb2_queue *vq)
{}

/* Vb2 ops */
static const struct vb2_ops rcar_drif_vb2_ops =;

static int rcar_drif_querycap(struct file *file, void *fh,
			      struct v4l2_capability *cap)
{}

static int rcar_drif_set_default_format(struct rcar_drif_sdr *sdr)
{}

static int rcar_drif_enum_fmt_sdr_cap(struct file *file, void *priv,
				      struct v4l2_fmtdesc *f)
{}

static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv,
				   struct v4l2_format *f)
{}

static int rcar_drif_s_fmt_sdr_cap(struct file *file, void *priv,
				   struct v4l2_format *f)
{}

static int rcar_drif_try_fmt_sdr_cap(struct file *file, void *priv,
				     struct v4l2_format *f)
{}

/* Tuner subdev ioctls */
static int rcar_drif_enum_freq_bands(struct file *file, void *priv,
				     struct v4l2_frequency_band *band)
{}

static int rcar_drif_g_frequency(struct file *file, void *priv,
				 struct v4l2_frequency *f)
{}

static int rcar_drif_s_frequency(struct file *file, void *priv,
				 const struct v4l2_frequency *f)
{}

static int rcar_drif_g_tuner(struct file *file, void *priv,
			     struct v4l2_tuner *vt)
{}

static int rcar_drif_s_tuner(struct file *file, void *priv,
			     const struct v4l2_tuner *vt)
{}

static const struct v4l2_ioctl_ops rcar_drif_ioctl_ops =;

static const struct v4l2_file_operations rcar_drif_fops =;

static int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr)
{}

static void rcar_drif_sdr_unregister(struct rcar_drif_sdr *sdr)
{}

/* Sub-device bound callback */
static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier,
				   struct v4l2_subdev *subdev,
				   struct v4l2_async_connection *asd)
{}

/* Sub-device unbind callback */
static void rcar_drif_notify_unbind(struct v4l2_async_notifier *notifier,
				   struct v4l2_subdev *subdev,
				   struct v4l2_async_connection *asd)
{}

/* Sub-device registered notification callback */
static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
{}

static const struct v4l2_async_notifier_operations rcar_drif_notify_ops =;

/* Read endpoint properties */
static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr,
					struct fwnode_handle *fwnode)
{}

/* Parse sub-devs (tuner) to find a matching device */
static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
{}

/* Check if the given device is the primary bond */
static bool rcar_drif_primary_bond(struct platform_device *pdev)
{}

/* Check if both devices of the bond are enabled */
static struct device_node *rcar_drif_bond_enabled(struct platform_device *p)
{}

/* Check if the bonded device is probed */
static int rcar_drif_bond_available(struct rcar_drif_sdr *sdr,
				    struct device_node *np)
{}

/* V4L2 SDR device probe */
static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
{}

/* V4L2 SDR device remove */
static void rcar_drif_sdr_remove(struct rcar_drif_sdr *sdr)
{}

/* DRIF channel probe */
static int rcar_drif_probe(struct platform_device *pdev)
{}

/* DRIF channel remove */
static void rcar_drif_remove(struct platform_device *pdev)
{}

/* FIXME: Implement suspend/resume support */
static int __maybe_unused rcar_drif_suspend(struct device *dev)
{}

static int __maybe_unused rcar_drif_resume(struct device *dev)
{}

static SIMPLE_DEV_PM_OPS(rcar_drif_pm_ops, rcar_drif_suspend,
			 rcar_drif_resume);

static const struct of_device_id rcar_drif_of_table[] =;
MODULE_DEVICE_TABLE(of, rcar_drif_of_table);

#define RCAR_DRIF_DRV_NAME
static struct platform_driver rcar_drif_driver =;

module_platform_driver();

MODULE_DESCRIPTION();
MODULE_ALIAS();
MODULE_LICENSE();
MODULE_AUTHOR();