cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cdns-csi2tx.c (16328B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Driver for Cadence MIPI-CSI2 TX Controller
      4 *
      5 * Copyright (C) 2017-2019 Cadence Design Systems Inc.
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/delay.h>
     10#include <linux/io.h>
     11#include <linux/module.h>
     12#include <linux/mutex.h>
     13#include <linux/of.h>
     14#include <linux/of_graph.h>
     15#include <linux/platform_device.h>
     16#include <linux/slab.h>
     17
     18#include <media/mipi-csi2.h>
     19#include <media/v4l2-ctrls.h>
     20#include <media/v4l2-device.h>
     21#include <media/v4l2-fwnode.h>
     22#include <media/v4l2-subdev.h>
     23
     24#define CSI2TX_DEVICE_CONFIG_REG	0x00
     25#define CSI2TX_DEVICE_CONFIG_STREAMS_MASK	GENMASK(6, 4)
     26#define CSI2TX_DEVICE_CONFIG_HAS_DPHY		BIT(3)
     27#define CSI2TX_DEVICE_CONFIG_LANES_MASK		GENMASK(2, 0)
     28
     29#define CSI2TX_CONFIG_REG		0x20
     30#define CSI2TX_CONFIG_CFG_REQ			BIT(2)
     31#define CSI2TX_CONFIG_SRST_REQ			BIT(1)
     32
     33#define CSI2TX_DPHY_CFG_REG		0x28
     34#define CSI2TX_DPHY_CFG_CLK_RESET		BIT(16)
     35#define CSI2TX_DPHY_CFG_LANE_RESET(n)		BIT((n) + 12)
     36#define CSI2TX_DPHY_CFG_MODE_MASK		GENMASK(9, 8)
     37#define CSI2TX_DPHY_CFG_MODE_LPDT		(2 << 8)
     38#define CSI2TX_DPHY_CFG_MODE_HS			(1 << 8)
     39#define CSI2TX_DPHY_CFG_MODE_ULPS		(0 << 8)
     40#define CSI2TX_DPHY_CFG_CLK_ENABLE		BIT(4)
     41#define CSI2TX_DPHY_CFG_LANE_ENABLE(n)		BIT(n)
     42
     43#define CSI2TX_DPHY_CLK_WAKEUP_REG	0x2c
     44#define CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(n)	((n) & 0xffff)
     45
     46#define CSI2TX_DT_CFG_REG(n)		(0x80 + (n) * 8)
     47#define CSI2TX_DT_CFG_DT(n)			(((n) & 0x3f) << 2)
     48
     49#define CSI2TX_DT_FORMAT_REG(n)		(0x84 + (n) * 8)
     50#define CSI2TX_DT_FORMAT_BYTES_PER_LINE(n)	(((n) & 0xffff) << 16)
     51#define CSI2TX_DT_FORMAT_MAX_LINE_NUM(n)	((n) & 0xffff)
     52
     53#define CSI2TX_STREAM_IF_CFG_REG(n)	(0x100 + (n) * 4)
     54#define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n)	((n) & 0x1f)
     55
     56/* CSI2TX V2 Registers */
     57#define CSI2TX_V2_DPHY_CFG_REG			0x28
     58#define CSI2TX_V2_DPHY_CFG_RESET		BIT(16)
     59#define CSI2TX_V2_DPHY_CFG_CLOCK_MODE		BIT(10)
     60#define CSI2TX_V2_DPHY_CFG_MODE_MASK		GENMASK(9, 8)
     61#define CSI2TX_V2_DPHY_CFG_MODE_LPDT		(2 << 8)
     62#define CSI2TX_V2_DPHY_CFG_MODE_HS		(1 << 8)
     63#define CSI2TX_V2_DPHY_CFG_MODE_ULPS		(0 << 8)
     64#define CSI2TX_V2_DPHY_CFG_CLK_ENABLE		BIT(4)
     65#define CSI2TX_V2_DPHY_CFG_LANE_ENABLE(n)	BIT(n)
     66
     67#define CSI2TX_LANES_MAX	4
     68#define CSI2TX_STREAMS_MAX	4
     69
     70enum csi2tx_pads {
     71	CSI2TX_PAD_SOURCE,
     72	CSI2TX_PAD_SINK_STREAM0,
     73	CSI2TX_PAD_SINK_STREAM1,
     74	CSI2TX_PAD_SINK_STREAM2,
     75	CSI2TX_PAD_SINK_STREAM3,
     76	CSI2TX_PAD_MAX,
     77};
     78
     79struct csi2tx_fmt {
     80	u32	mbus;
     81	u32	dt;
     82	u32	bpp;
     83};
     84
     85struct csi2tx_priv;
     86
     87/* CSI2TX Variant Operations */
     88struct csi2tx_vops {
     89	void (*dphy_setup)(struct csi2tx_priv *csi2tx);
     90};
     91
     92struct csi2tx_priv {
     93	struct device			*dev;
     94	unsigned int			count;
     95
     96	/*
     97	 * Used to prevent race conditions between multiple,
     98	 * concurrent calls to start and stop.
     99	 */
    100	struct mutex			lock;
    101
    102	void __iomem			*base;
    103
    104	struct csi2tx_vops		*vops;
    105
    106	struct clk			*esc_clk;
    107	struct clk			*p_clk;
    108	struct clk			*pixel_clk[CSI2TX_STREAMS_MAX];
    109
    110	struct v4l2_subdev		subdev;
    111	struct media_pad		pads[CSI2TX_PAD_MAX];
    112	struct v4l2_mbus_framefmt	pad_fmts[CSI2TX_PAD_MAX];
    113
    114	bool				has_internal_dphy;
    115	u8				lanes[CSI2TX_LANES_MAX];
    116	unsigned int			num_lanes;
    117	unsigned int			max_lanes;
    118	unsigned int			max_streams;
    119};
    120
    121static const struct csi2tx_fmt csi2tx_formats[] = {
    122	{
    123		.mbus	= MEDIA_BUS_FMT_UYVY8_1X16,
    124		.bpp	= 2,
    125		.dt	= MIPI_CSI2_DT_YUV422_8B,
    126	},
    127	{
    128		.mbus	= MEDIA_BUS_FMT_RGB888_1X24,
    129		.bpp	= 3,
    130		.dt	= MIPI_CSI2_DT_RGB888,
    131	},
    132};
    133
    134static const struct v4l2_mbus_framefmt fmt_default = {
    135	.width		= 1280,
    136	.height		= 720,
    137	.code		= MEDIA_BUS_FMT_RGB888_1X24,
    138	.field		= V4L2_FIELD_NONE,
    139	.colorspace	= V4L2_COLORSPACE_DEFAULT,
    140};
    141
    142static inline
    143struct csi2tx_priv *v4l2_subdev_to_csi2tx(struct v4l2_subdev *subdev)
    144{
    145	return container_of(subdev, struct csi2tx_priv, subdev);
    146}
    147
    148static const struct csi2tx_fmt *csi2tx_get_fmt_from_mbus(u32 mbus)
    149{
    150	unsigned int i;
    151
    152	for (i = 0; i < ARRAY_SIZE(csi2tx_formats); i++)
    153		if (csi2tx_formats[i].mbus == mbus)
    154			return &csi2tx_formats[i];
    155
    156	return NULL;
    157}
    158
    159static int csi2tx_enum_mbus_code(struct v4l2_subdev *subdev,
    160				 struct v4l2_subdev_state *sd_state,
    161				 struct v4l2_subdev_mbus_code_enum *code)
    162{
    163	if (code->pad || code->index >= ARRAY_SIZE(csi2tx_formats))
    164		return -EINVAL;
    165
    166	code->code = csi2tx_formats[code->index].mbus;
    167
    168	return 0;
    169}
    170
    171static struct v4l2_mbus_framefmt *
    172__csi2tx_get_pad_format(struct v4l2_subdev *subdev,
    173			struct v4l2_subdev_state *sd_state,
    174			struct v4l2_subdev_format *fmt)
    175{
    176	struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev);
    177
    178	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
    179		return v4l2_subdev_get_try_format(subdev, sd_state,
    180						  fmt->pad);
    181
    182	return &csi2tx->pad_fmts[fmt->pad];
    183}
    184
    185static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
    186				 struct v4l2_subdev_state *sd_state,
    187				 struct v4l2_subdev_format *fmt)
    188{
    189	const struct v4l2_mbus_framefmt *format;
    190
    191	/* Multiplexed pad? */
    192	if (fmt->pad == CSI2TX_PAD_SOURCE)
    193		return -EINVAL;
    194
    195	format = __csi2tx_get_pad_format(subdev, sd_state, fmt);
    196	if (!format)
    197		return -EINVAL;
    198
    199	fmt->format = *format;
    200
    201	return 0;
    202}
    203
    204static int csi2tx_set_pad_format(struct v4l2_subdev *subdev,
    205				 struct v4l2_subdev_state *sd_state,
    206				 struct v4l2_subdev_format *fmt)
    207{
    208	const struct v4l2_mbus_framefmt *src_format = &fmt->format;
    209	struct v4l2_mbus_framefmt *dst_format;
    210
    211	/* Multiplexed pad? */
    212	if (fmt->pad == CSI2TX_PAD_SOURCE)
    213		return -EINVAL;
    214
    215	if (!csi2tx_get_fmt_from_mbus(fmt->format.code))
    216		src_format = &fmt_default;
    217
    218	dst_format = __csi2tx_get_pad_format(subdev, sd_state, fmt);
    219	if (!dst_format)
    220		return -EINVAL;
    221
    222	*dst_format = *src_format;
    223
    224	return 0;
    225}
    226
    227static const struct v4l2_subdev_pad_ops csi2tx_pad_ops = {
    228	.enum_mbus_code	= csi2tx_enum_mbus_code,
    229	.get_fmt	= csi2tx_get_pad_format,
    230	.set_fmt	= csi2tx_set_pad_format,
    231};
    232
    233/* Set Wake Up value in the D-PHY */
    234static void csi2tx_dphy_set_wakeup(struct csi2tx_priv *csi2tx)
    235{
    236	writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
    237	       csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
    238}
    239
    240/*
    241 * Finishes the D-PHY initialization
    242 * reg dphy cfg value to be used
    243 */
    244static void csi2tx_dphy_init_finish(struct csi2tx_priv *csi2tx, u32 reg)
    245{
    246	unsigned int i;
    247
    248	udelay(10);
    249
    250	/* Enable our (clock and data) lanes */
    251	reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
    252	for (i = 0; i < csi2tx->num_lanes; i++)
    253		reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1);
    254	writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
    255
    256	udelay(10);
    257
    258	/* Switch to HS mode */
    259	reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
    260	writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
    261	       csi2tx->base + CSI2TX_DPHY_CFG_REG);
    262}
    263
    264/* Configures D-PHY in CSIv1.3 */
    265static void csi2tx_dphy_setup(struct csi2tx_priv *csi2tx)
    266{
    267	u32 reg;
    268	unsigned int i;
    269
    270	csi2tx_dphy_set_wakeup(csi2tx);
    271
    272	/* Put our lanes (clock and data) out of reset */
    273	reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT;
    274	for (i = 0; i < csi2tx->num_lanes; i++)
    275		reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1);
    276	writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
    277
    278	csi2tx_dphy_init_finish(csi2tx, reg);
    279}
    280
    281/* Configures D-PHY in CSIv2 */
    282static void csi2tx_v2_dphy_setup(struct csi2tx_priv *csi2tx)
    283{
    284	u32 reg;
    285
    286	csi2tx_dphy_set_wakeup(csi2tx);
    287
    288	/* Put our lanes (clock and data) out of reset */
    289	reg = CSI2TX_V2_DPHY_CFG_RESET | CSI2TX_V2_DPHY_CFG_MODE_LPDT;
    290	writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG);
    291
    292	csi2tx_dphy_init_finish(csi2tx, reg);
    293}
    294
    295static void csi2tx_reset(struct csi2tx_priv *csi2tx)
    296{
    297	writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
    298
    299	udelay(10);
    300}
    301
    302static int csi2tx_start(struct csi2tx_priv *csi2tx)
    303{
    304	struct media_entity *entity = &csi2tx->subdev.entity;
    305	struct media_link *link;
    306	unsigned int i;
    307
    308	csi2tx_reset(csi2tx);
    309
    310	writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
    311
    312	udelay(10);
    313
    314	if (csi2tx->vops && csi2tx->vops->dphy_setup) {
    315		csi2tx->vops->dphy_setup(csi2tx);
    316		udelay(10);
    317	}
    318
    319	/*
    320	 * Create a static mapping between the CSI virtual channels
    321	 * and the input streams.
    322	 *
    323	 * This should be enhanced, but v4l2 lacks the support for
    324	 * changing that mapping dynamically at the moment.
    325	 *
    326	 * We're protected from the userspace setting up links at the
    327	 * same time by the upper layer having called
    328	 * media_pipeline_start().
    329	 */
    330	list_for_each_entry(link, &entity->links, list) {
    331		struct v4l2_mbus_framefmt *mfmt;
    332		const struct csi2tx_fmt *fmt;
    333		unsigned int stream;
    334		int pad_idx = -1;
    335
    336		/* Only consider our enabled input pads */
    337		for (i = CSI2TX_PAD_SINK_STREAM0; i < CSI2TX_PAD_MAX; i++) {
    338			struct media_pad *pad = &csi2tx->pads[i];
    339
    340			if ((pad == link->sink) &&
    341			    (link->flags & MEDIA_LNK_FL_ENABLED)) {
    342				pad_idx = i;
    343				break;
    344			}
    345		}
    346
    347		if (pad_idx < 0)
    348			continue;
    349
    350		mfmt = &csi2tx->pad_fmts[pad_idx];
    351		fmt = csi2tx_get_fmt_from_mbus(mfmt->code);
    352		if (!fmt)
    353			continue;
    354
    355		stream = pad_idx - CSI2TX_PAD_SINK_STREAM0;
    356
    357		/*
    358		 * We use the stream ID there, but it's wrong.
    359		 *
    360		 * A stream could very well send a data type that is
    361		 * not equal to its stream ID. We need to find a
    362		 * proper way to address it.
    363		 */
    364		writel(CSI2TX_DT_CFG_DT(fmt->dt),
    365		       csi2tx->base + CSI2TX_DT_CFG_REG(stream));
    366
    367		writel(CSI2TX_DT_FORMAT_BYTES_PER_LINE(mfmt->width * fmt->bpp) |
    368		       CSI2TX_DT_FORMAT_MAX_LINE_NUM(mfmt->height + 1),
    369		       csi2tx->base + CSI2TX_DT_FORMAT_REG(stream));
    370
    371		/*
    372		 * TODO: This needs to be calculated based on the
    373		 * output CSI2 clock rate.
    374		 */
    375		writel(CSI2TX_STREAM_IF_CFG_FILL_LEVEL(4),
    376		       csi2tx->base + CSI2TX_STREAM_IF_CFG_REG(stream));
    377	}
    378
    379	/* Disable the configuration mode */
    380	writel(0, csi2tx->base + CSI2TX_CONFIG_REG);
    381
    382	return 0;
    383}
    384
    385static void csi2tx_stop(struct csi2tx_priv *csi2tx)
    386{
    387	writel(CSI2TX_CONFIG_CFG_REQ | CSI2TX_CONFIG_SRST_REQ,
    388	       csi2tx->base + CSI2TX_CONFIG_REG);
    389}
    390
    391static int csi2tx_s_stream(struct v4l2_subdev *subdev, int enable)
    392{
    393	struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev);
    394	int ret = 0;
    395
    396	mutex_lock(&csi2tx->lock);
    397
    398	if (enable) {
    399		/*
    400		 * If we're not the first users, there's no need to
    401		 * enable the whole controller.
    402		 */
    403		if (!csi2tx->count) {
    404			ret = csi2tx_start(csi2tx);
    405			if (ret)
    406				goto out;
    407		}
    408
    409		csi2tx->count++;
    410	} else {
    411		csi2tx->count--;
    412
    413		/*
    414		 * Let the last user turn off the lights.
    415		 */
    416		if (!csi2tx->count)
    417			csi2tx_stop(csi2tx);
    418	}
    419
    420out:
    421	mutex_unlock(&csi2tx->lock);
    422	return ret;
    423}
    424
    425static const struct v4l2_subdev_video_ops csi2tx_video_ops = {
    426	.s_stream	= csi2tx_s_stream,
    427};
    428
    429static const struct v4l2_subdev_ops csi2tx_subdev_ops = {
    430	.pad		= &csi2tx_pad_ops,
    431	.video		= &csi2tx_video_ops,
    432};
    433
    434static int csi2tx_get_resources(struct csi2tx_priv *csi2tx,
    435				struct platform_device *pdev)
    436{
    437	unsigned int i;
    438	u32 dev_cfg;
    439	int ret;
    440
    441	csi2tx->base = devm_platform_ioremap_resource(pdev, 0);
    442	if (IS_ERR(csi2tx->base))
    443		return PTR_ERR(csi2tx->base);
    444
    445	csi2tx->p_clk = devm_clk_get(&pdev->dev, "p_clk");
    446	if (IS_ERR(csi2tx->p_clk)) {
    447		dev_err(&pdev->dev, "Couldn't get p_clk\n");
    448		return PTR_ERR(csi2tx->p_clk);
    449	}
    450
    451	csi2tx->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
    452	if (IS_ERR(csi2tx->esc_clk)) {
    453		dev_err(&pdev->dev, "Couldn't get the esc_clk\n");
    454		return PTR_ERR(csi2tx->esc_clk);
    455	}
    456
    457	ret = clk_prepare_enable(csi2tx->p_clk);
    458	if (ret) {
    459		dev_err(&pdev->dev, "Couldn't prepare and enable p_clk\n");
    460		return ret;
    461	}
    462
    463	dev_cfg = readl(csi2tx->base + CSI2TX_DEVICE_CONFIG_REG);
    464	clk_disable_unprepare(csi2tx->p_clk);
    465
    466	csi2tx->max_lanes = dev_cfg & CSI2TX_DEVICE_CONFIG_LANES_MASK;
    467	if (csi2tx->max_lanes > CSI2TX_LANES_MAX) {
    468		dev_err(&pdev->dev, "Invalid number of lanes: %u\n",
    469			csi2tx->max_lanes);
    470		return -EINVAL;
    471	}
    472
    473	csi2tx->max_streams = (dev_cfg & CSI2TX_DEVICE_CONFIG_STREAMS_MASK) >> 4;
    474	if (csi2tx->max_streams > CSI2TX_STREAMS_MAX) {
    475		dev_err(&pdev->dev, "Invalid number of streams: %u\n",
    476			csi2tx->max_streams);
    477		return -EINVAL;
    478	}
    479
    480	csi2tx->has_internal_dphy = !!(dev_cfg & CSI2TX_DEVICE_CONFIG_HAS_DPHY);
    481
    482	for (i = 0; i < csi2tx->max_streams; i++) {
    483		char clk_name[16];
    484
    485		snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i);
    486		csi2tx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name);
    487		if (IS_ERR(csi2tx->pixel_clk[i])) {
    488			dev_err(&pdev->dev, "Couldn't get clock %s\n",
    489				clk_name);
    490			return PTR_ERR(csi2tx->pixel_clk[i]);
    491		}
    492	}
    493
    494	return 0;
    495}
    496
    497static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx)
    498{
    499	struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
    500	struct device_node *ep;
    501	int ret, i;
    502
    503	ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0);
    504	if (!ep)
    505		return -EINVAL;
    506
    507	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
    508	if (ret) {
    509		dev_err(csi2tx->dev, "Could not parse v4l2 endpoint\n");
    510		goto out;
    511	}
    512
    513	if (v4l2_ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
    514		dev_err(csi2tx->dev, "Unsupported media bus type: 0x%x\n",
    515			v4l2_ep.bus_type);
    516		ret = -EINVAL;
    517		goto out;
    518	}
    519
    520	csi2tx->num_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
    521	if (csi2tx->num_lanes > csi2tx->max_lanes) {
    522		dev_err(csi2tx->dev,
    523			"Current configuration uses more lanes than supported\n");
    524		ret = -EINVAL;
    525		goto out;
    526	}
    527
    528	for (i = 0; i < csi2tx->num_lanes; i++) {
    529		if (v4l2_ep.bus.mipi_csi2.data_lanes[i] < 1) {
    530			dev_err(csi2tx->dev, "Invalid lane[%d] number: %u\n",
    531				i, v4l2_ep.bus.mipi_csi2.data_lanes[i]);
    532			ret = -EINVAL;
    533			goto out;
    534		}
    535	}
    536
    537	memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes,
    538	       sizeof(csi2tx->lanes));
    539
    540out:
    541	of_node_put(ep);
    542	return ret;
    543}
    544
    545static const struct csi2tx_vops csi2tx_vops = {
    546	.dphy_setup = csi2tx_dphy_setup,
    547};
    548
    549static const struct csi2tx_vops csi2tx_v2_vops = {
    550	.dphy_setup = csi2tx_v2_dphy_setup,
    551};
    552
    553static const struct of_device_id csi2tx_of_table[] = {
    554	{
    555		.compatible = "cdns,csi2tx",
    556		.data = &csi2tx_vops
    557	},
    558	{
    559		.compatible = "cdns,csi2tx-1.3",
    560		.data = &csi2tx_vops
    561	},
    562	{
    563		.compatible = "cdns,csi2tx-2.1",
    564		.data = &csi2tx_v2_vops
    565	},
    566	{ }
    567};
    568MODULE_DEVICE_TABLE(of, csi2tx_of_table);
    569
    570static int csi2tx_probe(struct platform_device *pdev)
    571{
    572	struct csi2tx_priv *csi2tx;
    573	const struct of_device_id *of_id;
    574	unsigned int i;
    575	int ret;
    576
    577	csi2tx = kzalloc(sizeof(*csi2tx), GFP_KERNEL);
    578	if (!csi2tx)
    579		return -ENOMEM;
    580	platform_set_drvdata(pdev, csi2tx);
    581	mutex_init(&csi2tx->lock);
    582	csi2tx->dev = &pdev->dev;
    583
    584	ret = csi2tx_get_resources(csi2tx, pdev);
    585	if (ret)
    586		goto err_free_priv;
    587
    588	of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node);
    589	csi2tx->vops = (struct csi2tx_vops *)of_id->data;
    590
    591	v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops);
    592	csi2tx->subdev.owner = THIS_MODULE;
    593	csi2tx->subdev.dev = &pdev->dev;
    594	csi2tx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
    595	snprintf(csi2tx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s",
    596		 KBUILD_MODNAME, dev_name(&pdev->dev));
    597
    598	ret = csi2tx_check_lanes(csi2tx);
    599	if (ret)
    600		goto err_free_priv;
    601
    602	/* Create our media pads */
    603	csi2tx->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
    604	csi2tx->pads[CSI2TX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
    605	for (i = CSI2TX_PAD_SINK_STREAM0; i < CSI2TX_PAD_MAX; i++)
    606		csi2tx->pads[i].flags = MEDIA_PAD_FL_SINK;
    607
    608	/*
    609	 * Only the input pads are considered to have a format at the
    610	 * moment. The CSI link can multiplex various streams with
    611	 * different formats, and we can't expose this in v4l2 right
    612	 * now.
    613	 */
    614	for (i = CSI2TX_PAD_SINK_STREAM0; i < CSI2TX_PAD_MAX; i++)
    615		csi2tx->pad_fmts[i] = fmt_default;
    616
    617	ret = media_entity_pads_init(&csi2tx->subdev.entity, CSI2TX_PAD_MAX,
    618				     csi2tx->pads);
    619	if (ret)
    620		goto err_free_priv;
    621
    622	ret = v4l2_async_register_subdev(&csi2tx->subdev);
    623	if (ret < 0)
    624		goto err_free_priv;
    625
    626	dev_info(&pdev->dev,
    627		 "Probed CSI2TX with %u/%u lanes, %u streams, %s D-PHY\n",
    628		 csi2tx->num_lanes, csi2tx->max_lanes, csi2tx->max_streams,
    629		 csi2tx->has_internal_dphy ? "internal" : "no");
    630
    631	return 0;
    632
    633err_free_priv:
    634	kfree(csi2tx);
    635	return ret;
    636}
    637
    638static int csi2tx_remove(struct platform_device *pdev)
    639{
    640	struct csi2tx_priv *csi2tx = platform_get_drvdata(pdev);
    641
    642	v4l2_async_unregister_subdev(&csi2tx->subdev);
    643	kfree(csi2tx);
    644
    645	return 0;
    646}
    647
    648static struct platform_driver csi2tx_driver = {
    649	.probe	= csi2tx_probe,
    650	.remove	= csi2tx_remove,
    651
    652	.driver	= {
    653		.name		= "cdns-csi2tx",
    654		.of_match_table	= csi2tx_of_table,
    655	},
    656};
    657module_platform_driver(csi2tx_driver);
    658MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
    659MODULE_DESCRIPTION("Cadence CSI2-TX controller");
    660MODULE_LICENSE("GPL");