// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Renesas R-Car VIN
*
* Copyright (C) 2016 Renesas Electronics Corp.
* Copyright (C) 2011-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
* Copyright (C) 2008 Magnus Damm
*
* Based on the soc-camera rcar_vin driver
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-mc.h>
#include "rcar-vin.h"
/*
* The companion CSI-2 receiver driver (rcar-csi2) is known
* and we know it has one source pad (pad 0) and four sink
* pads (pad 1-4). So to translate a pad on the remote
* CSI-2 receiver to/from the VIN internal channel number simply
* subtract/add one from the pad/channel number.
*/
#define rvin_group_csi_pad_to_channel(pad) ((pad) - 1)
#define rvin_group_csi_channel_to_pad(channel) ((channel) + 1)
/*
* Not all VINs are created equal, master VINs control the
* routing for other VIN's. We can figure out which VIN is
* master by looking at a VINs id.
*/
#define rvin_group_id_to_master(vin) ((vin) < 4 ? 0 : 4)
#define v4l2_dev_to_vin(d) container_of(d, struct rvin_dev, v4l2_dev)
/* -----------------------------------------------------------------------------
* Gen3 Group Allocator
*/
/* FIXME: This should if we find a system that supports more
* than one group for the whole system be replaced with a linked
* list of groups. And eventually all of this should be replaced
* with a global device allocator API.
*
* But for now this works as on all supported systems there will
* be only one group for all instances.
*/
static DEFINE_MUTEX(rvin_group_lock);
static struct rvin_group *rvin_group_data;
static void rvin_group_cleanup(struct rvin_group *group)
{
media_device_cleanup(&group->mdev);
mutex_destroy(&group->lock);
}
static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin,
int (*link_setup)(struct rvin_dev *),
const struct media_device_ops *ops)
{
struct media_device *mdev = &group->mdev;
const struct of_device_id *match;
struct device_node *np;
mutex_init(&group->lock