// SPDX-License-Identifier: GPL-2.0-only
/*
* V4L2 fwnode binding parsing library
*
* The origins of the V4L2 fwnode library are in V4L2 OF library that
* formerly was located in v4l2-of.c.
*
* Copyright (c) 2016 Intel Corporation.
* Author: Sakari Ailus <sakari.ailus@linux.intel.com>
*
* Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* Copyright (C) 2012 Renesas Electronics Corp.
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <media/v4l2-async.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
enum v4l2_fwnode_bus_type {
V4L2_FWNODE_BUS_TYPE_GUESS = 0,
V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
V4L2_FWNODE_BUS_TYPE_CSI1,
V4L2_FWNODE_BUS_TYPE_CCP2,
V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
V4L2_FWNODE_BUS_TYPE_PARALLEL,
V4L2_FWNODE_BUS_TYPE_BT656,
NR_OF_V4L2_FWNODE_BUS_TYPE,
};
static const struct v4l2_fwnode_bus_conv {
enum v4l2_fwnode_bus_type fwnode_bus_type;
enum v4l2_mbus_type mbus_type;
const char *name;
} buses[] = {
{
V4L2_FWNODE_BUS_TYPE_GUESS,
V4L2_MBUS_UNKNOWN,
"not specified",
}, {
V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
V4L2_MBUS_CSI2_CPHY,
"MIPI CSI-2 C-PHY",
}, {
V4L2_FWNODE_BUS_TYPE_CSI1,
V4L2_MBUS_CSI1,
"MIPI CSI-1",
}, {
V4L2_FWNODE_BUS_TYPE_CCP2,
V4L2_MBUS_CCP2,
"compact camera port 2",
}, {
V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
V4L2_MBUS_CSI2_DPHY,
"MIPI CSI-2 D-PHY",
}, {
V4L2_FWNODE_BUS_TYPE_PARALLEL,
V4L2_MBUS_PARALLEL,
"parallel",
}, {
V4L2_FWNODE_BUS_TYPE_BT656,
V4L2_MBUS_BT656,
"Bt.656",
}
};
static const struct v4l2_fwnode_bus_conv *
get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(buses); i++)
if (buses[i].fwnode_bus_type == type)
return &buses[i];
return NULL;
}
static enum v4l2_mbus_type
v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
{
const struct v4l2_fwnode_bus_conv *conv =
get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN;
}
static const char *
v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
{
const struct v4l2_fwnode_bus_conv *conv =
get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
return conv ? conv->name : "not found";
}
static const struct v4l2_fwnode_bus_conv *
get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(buses); i++)
if (buses[i].mbus_type == type)
return &buses[i];
return NULL;
}
static const char *
v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
{
const struct v4l2_fwnode_bus_conv *conv =
get_v4l2_fwnode_bus_conv_by_mbus(type);
return conv ? conv->name : "not found";
}
static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep,
enum v4l2_mbus_type bus_type)
{
struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
bool have_clk_lane = false, have_data_lanes = false,
have_lane_polarities = false;
unsigned int flags = 0, lanes_used = 0;
u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
u32 clock_lane = 0;
unsigned int num_data_lanes = 0;