From patchwork Thu Feb 22 11:31:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jai Luthra X-Patchwork-Id: 204709 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:aa16:b0:108:e6aa:91d0 with SMTP id by22csp192643dyb; Thu, 22 Feb 2024 03:42:04 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCWsfR7oEhBo35tYGp5JBQWIJ8E+36thYwhw5RyMx9X7hnQhNHXIdeJHKnF2CrkdRhErIxBmwRa9OS8CuUu4rdW4nPfM1A== X-Google-Smtp-Source: AGHT+IGj1Jzp0n66vTmCeH879ufe1pJhBELhx05q8XoGPWyoD8QbtYTz2Z9lkJCT53TUa+sY9S/V X-Received: by 2002:a17:906:abcf:b0:a3f:2ffd:c683 with SMTP id kq15-20020a170906abcf00b00a3f2ffdc683mr3558596ejb.62.1708602123922; Thu, 22 Feb 2024 03:42:03 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1708602123; cv=pass; d=google.com; s=arc-20160816; b=ZCmcaNItTAlq4nfc4mhrYpiOYBq4EsTxyXC/qzzQxlcbWbgKovYlo3pwAFetOtnt3w iigLwYLZOd6pBQ/FmuOc3c1Y1Cj7sUlMR9/gwyMUBMM6nRddMODoigoL2pjDx2Y8LB7C 3IQNywPlFxpHGIK7ie6lkC6F5ocE33w/J9nvcoeOxyqyB8n/W3KCm61YCAE4TG+/JiCa POctlXCVMqd4XTYFmJ8bX5ZBdL+V/On3jsv/xX8uQ7+d/ENeL6+W/GpNHjdyOxzBKjM5 yx09HOD8X+1rRG2YLLBtRdjlB7UmPY8ArotAvAZDMJcxj7Coe/ga1KwG5RspUhrKUm8G 8DDA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=FK4vACELRejD1soTNVVYsWj9/vO5TJ0UV4lYpPXtF0o=; fh=7Ze5xPQXuwRxFNHD2ILqwMPZ5wjg3PcSuREjIh8VhDo=; b=VYSwidr+NH2ghIuC5TsLziZlIrbnY3MA6TTtp/+e43dpVMgJIw9q8kTNoUa6FmGrh0 hEfIsi+JqALAQC+++1XXewA9wFaP6lD55XcOpd/6szdcqEI2LfxetO9PBM5ZhC21hfBx Tlw2K987Lu8iYjsB+Supe7WSizDof9hMsY3Kozs46OFmQlDS47N3RQliG/slnL/Nj3No lPUsGPcTsbBBfhsW6rkNBIPNE5pfbc2Odv41vz/aX6rKo+7MDa6L+GPc3oZBT0dkKkPa lBdcaTZJmCyh8ZQjljbk1APVT35BG6hX9jE1XnboyujzZZdxbuRhe+9OiQTDnvBNTTw9 dLiw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=k2TNu+U6; arc=pass (i=1 spf=pass spfdomain=ti.com dkim=pass dkdomain=ti.com dmarc=pass fromdomain=ti.com); spf=pass (google.com: domain of linux-kernel+bounces-76420-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-76420-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [147.75.80.249]) by mx.google.com with ESMTPS id i24-20020a170906265800b00a3e5aa9bb7dsi4432607ejc.436.2024.02.22.03.42.03 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 22 Feb 2024 03:42:03 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-76420-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) client-ip=147.75.80.249; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=k2TNu+U6; arc=pass (i=1 spf=pass spfdomain=ti.com dkim=pass dkdomain=ti.com dmarc=pass fromdomain=ti.com); spf=pass (google.com: domain of linux-kernel+bounces-76420-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-76420-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 51BCE1F26EC3 for ; Thu, 22 Feb 2024 11:36:17 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E956B4F20E; Thu, 22 Feb 2024 11:33:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="k2TNu+U6" Received: from lelv0143.ext.ti.com (lelv0143.ext.ti.com [198.47.23.248]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B64D45010; Thu, 22 Feb 2024 11:33:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.248 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708601617; cv=none; b=g7NNuMeiL0SYs88jPssG+8jjBxzyUGLvYqScEoovmyjo+9l9jtZYE4E0Zkrl4or/26a91lBPFrhGJgL8kvQXslHmhIFGvt87z18ferHL1+29bcLEMJdXq0FZFJ43KxC/9HXWjeR9ooCFU4OpcOi7WD5NRz5tzp+Q2DICAqzACRQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708601617; c=relaxed/simple; bh=Dca0Koq/zfrrUf9kobNjuQW8iIT2NcxY2qulOqqgK5A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=IO6Ybn8Cz5B10N97GGgE4TzhL5lQADuM8Zw+zdkPfacHOuiX7WkOlAhaqIkyUve9R7gd9CEBDM5tA3Axu/1w0y1EAMdZqJeF+yri9LPBxE63rniJjJvy8CcxbxH8Jg5og01rWPi5nJqoXQcvrgK0S9tncSiPhNQRBZbWBhNy3YI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=k2TNu+U6; arc=none smtp.client-ip=198.47.23.248 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Received: from lelv0265.itg.ti.com ([10.180.67.224]) by lelv0143.ext.ti.com (8.15.2/8.15.2) with ESMTP id 41MBXLFp018054; Thu, 22 Feb 2024 05:33:21 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1708601601; bh=FK4vACELRejD1soTNVVYsWj9/vO5TJ0UV4lYpPXtF0o=; h=From:Date:Subject:References:In-Reply-To:To:CC; b=k2TNu+U68xWJ2Isx7K1HgVBRL4aKUKVimHiDcVK87TMCq7TMNywhsVZCiIoq2YjcI ILsQi/BSOQL/oLMi094MAMQVlPjiVvQUfgtM+uo5UI6KTvUvbN4ituphl1n6xRaZPP kvX6DzNZLvCF5NuAvZIVrZUoEUDpna5oOjiqwVz8= Received: from DLEE108.ent.ti.com (dlee108.ent.ti.com [157.170.170.38]) by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 41MBXLjA007539 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 22 Feb 2024 05:33:21 -0600 Received: from DLEE107.ent.ti.com (157.170.170.37) by DLEE108.ent.ti.com (157.170.170.38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Thu, 22 Feb 2024 05:33:21 -0600 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE107.ent.ti.com (157.170.170.37) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Thu, 22 Feb 2024 05:33:21 -0600 Received: from localhost (jluthra.dhcp.ti.com [172.24.227.217]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 41MBXJRQ128677; Thu, 22 Feb 2024 05:33:20 -0600 From: Jai Luthra Date: Thu, 22 Feb 2024 17:01:24 +0530 Subject: [PATCH RFC 08/21] media: ti: j721e-csi2rx: add a subdev for the core device Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20240222-multistream-v1-8-1837ed916eeb@ti.com> References: <20240222-multistream-v1-0-1837ed916eeb@ti.com> In-Reply-To: <20240222-multistream-v1-0-1837ed916eeb@ti.com> To: Tomi Valkeinen , Mauro Carvalho Chehab , Sakari Ailus , Hans Verkuil , Vaishnav Achath , Maxime Ripard , Rob Herring , Krzysztof Kozlowski , Conor Dooley CC: , , , Vignesh Raghavendra , Aradhya Bhatia , Devarsh Thakkar , Changhuang Liang , Jack Zhu , Julien Massot , Jayshri Pawar , Jai Luthra X-Mailer: b4 0.12.4 X-Developer-Signature: v=1; a=openpgp-sha256; l=11380; i=j-luthra@ti.com; h=from:subject:message-id; bh=Dca0Koq/zfrrUf9kobNjuQW8iIT2NcxY2qulOqqgK5A=; b=owEBbQKS/ZANAwAIAUPekfkkmnFFAcsmYgBl1zDhF7UrYNVPFQ1DNmqkiXFQeqGCo+0Bhm24q qv+hJgVy32JAjMEAAEIAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCZdcw4QAKCRBD3pH5JJpx RXGYEADTvovif4tTyDlmv4kSdxSwRHTnVnaqIkllRQiH1OtDGRm57cj46ylQh+RdWQ+4ZvJMo6c lnwB5sAHhFTrcOMTPn44i+FPzD7UtwldAPDp+SzTm2wmqlODMZjFL7uz2O3NHkTeNDsfmGFFWnm ywt99ma/HRibXzNrhMfNsaGgIY0fWT0CjyJKfxN1WL8nk8okzemEerh1ZTjqpfnz9CKqApZO3pf JszAyhrEuyibZdX7Xoic8WUj0Gae6PpIjPW53yZzQBsKoP5d/byEg7RBz/UX9arhiLBf+d/BYQN 45sfxrzj/MiAlK3Au2qpt7Trcqg1G1FTLBPixQrwZKJXwBQ74eXiclEvDxyy0ro+4jrILOx1V8g n8SFLt09lFEU94IrXY/svqghY6D/UKs/GWwbNXhrtDakigWaJ8JlJjXFZD0F/UhyMz7lI3gprVI YzefAO3pjyPALsbnpkGd5Cn4noVozG4JFHAB3Pp662V+jFT5xxZv4ZG77YfjNO8Tec//lNZsv0X WXMgShdHNvkHFosepTD2zC9IseNCIcgZtwXy+lUx7Px/D3Ybkchc1MI85QBu5awkNGOa6u5GxI2 yK9MzGun0QfszRWsBiex1OIAEtpwKkzi8VaAYvluyP3grnqyC35UwdYdVNvyYMIKYz00H3y7I06 F9DDXWzK03tvK1A== X-Developer-Key: i=j-luthra@ti.com; a=openpgp; fpr=4DE0D818E5D575E8D45AAFC543DE91F9249A7145 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1791599180759153693 X-GMAIL-MSGID: 1791599180759153693 With single stream capture, it was simpler to use the video device as the media entity representing the main TI CSI2RX device. Now with multi stream capture coming into the picture, the model has shifted to each video device having a link to the main device's subdev. The routing would then be set on this subdev. Add this subdev, link each context to this subdev's entity and link the subdev's entity to the source. Also add an array of media pads. It will have one sink pad and source pads equal to the number of contexts. Co-developed-by: Pratyush Yadav Signed-off-by: Pratyush Yadav Signed-off-by: Jai Luthra --- .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 217 +++++++++++++++++++-- 1 file changed, 198 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 80d7066100bf..42eb1bff21e2 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -51,6 +51,11 @@ #define MAX_WIDTH_BYTES SZ_16K #define MAX_HEIGHT_LINES SZ_16K +#define TI_CSI2RX_PAD_SINK 0 +#define TI_CSI2RX_PAD_FIRST_SOURCE 1 +#define TI_CSI2RX_NUM_SOURCE_PADS 1 +#define TI_CSI2RX_NUM_PADS (1 + TI_CSI2RX_NUM_SOURCE_PADS) + #define DRAIN_TIMEOUT_MS 50 #define DRAIN_BUFFER_SIZE SZ_32K @@ -97,6 +102,7 @@ struct ti_csi2rx_ctx { struct mutex mutex; /* To serialize ioctls. */ struct v4l2_format v_fmt; struct ti_csi2rx_dma dma; + struct media_pad pad; u32 sequence; u32 idx; }; @@ -104,12 +110,15 @@ struct ti_csi2rx_ctx { struct ti_csi2rx_dev { struct device *dev; void __iomem *shim; + struct mutex mutex; /* To serialize ioctls. */ + unsigned int enable_count; struct v4l2_device v4l2_dev; struct media_device mdev; struct media_pipeline pipe; - struct media_pad pad; + struct media_pad pads[TI_CSI2RX_NUM_PADS]; struct v4l2_async_notifier notifier; struct v4l2_subdev *source; + struct v4l2_subdev subdev; struct ti_csi2rx_ctx ctx[TI_CSI2RX_NUM_CTX]; /* Buffer to drain stale data from PSI-L endpoint */ struct { @@ -455,6 +464,15 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); int ret, i; + /* Create link from source to subdev */ + ret = v4l2_create_fwnode_links_to_pad(csi->source, + &csi->pads[TI_CSI2RX_PAD_SINK], + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + /* Create and link video nodes for all DMA contexts */ for (i = 0; i < TI_CSI2RX_NUM_CTX; i++) { struct ti_csi2rx_ctx *ctx = &csi->ctx[i]; struct video_device *vdev = &ctx->vdev; @@ -462,13 +480,17 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) goto unregister_dev; - } - ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) - goto unregister_dev; + ret = media_create_pad_link(&csi->subdev.entity, + TI_CSI2RX_PAD_FIRST_SOURCE + ctx->idx, + &vdev->entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + video_unregister_device(vdev); + goto unregister_dev; + } + } ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); if (ret) @@ -883,7 +905,7 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) dma->state = TI_CSI2RX_DMA_ACTIVE; spin_unlock_irqrestore(&dma->lock, flags); - ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 1); if (ret) goto err_dma; @@ -911,7 +933,7 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) writel(0, csi->shim + SHIM_CNTL); writel(0, csi->shim + SHIM_DMACNTX(ctx->idx)); - ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + ret = v4l2_subdev_call(&csi->subdev, video, s_stream, 0); if (ret) dev_err(csi->dev, "Failed to stop subdev stream\n"); @@ -929,6 +951,119 @@ static const struct vb2_ops csi_vb2_qops = { .wait_finish = vb2_ops_wait_finish, }; +static inline struct ti_csi2rx_dev *to_csi2rx_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ti_csi2rx_dev, subdev); +} + +static int ti_csi2rx_sd_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + int ret = 0; + + /* No transcoding, don't allow setting source fmt */ + if (format->pad >= TI_CSI2RX_PAD_FIRST_SOURCE) + return v4l2_subdev_get_fmt(sd, state, format); + + if (!find_format_by_code(format->format.code)) + format->format.code = ti_csi2rx_formats[0].code; + + format->format.field = V4L2_FIELD_NONE; + + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); + if (!fmt) { + ret = -EINVAL; + goto out; + } + *fmt = format->format; + + fmt = v4l2_subdev_state_get_format(state, TI_CSI2RX_PAD_FIRST_SOURCE, + format->stream); + if (!fmt) { + ret = -EINVAL; + goto out; + } + *fmt = format->format; + +out: + return ret; +} + +static int ti_csi2rx_sd_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format format = { + .pad = TI_CSI2RX_PAD_SINK, + .format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }, + }; + + return ti_csi2rx_sd_set_fmt(sd, state, &format); +} + +static int ti_csi2rx_sd_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd); + int ret = 0; + + mutex_lock(&csi->mutex); + + if (enable) { + if (csi->enable_count > 0) { + csi->enable_count++; + goto out; + } + + ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + if (ret) + goto out; + + csi->enable_count++; + } else { + if (csi->enable_count == 0) { + ret = -EINVAL; + goto out; + } + + if (--csi->enable_count > 0) + goto out; + + ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + } + +out: + mutex_unlock(&csi->mutex); + return ret; +} + +static const struct v4l2_subdev_pad_ops ti_csi2rx_subdev_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ti_csi2rx_sd_set_fmt, +}; + +static const struct v4l2_subdev_video_ops ti_csi2rx_subdev_video_ops = { + .s_stream = ti_csi2rx_sd_s_stream, +}; + +static const struct v4l2_subdev_ops ti_csi2rx_subdev_ops = { + .video = &ti_csi2rx_subdev_video_ops, + .pad = &ti_csi2rx_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ti_csi2rx_internal_ops = { + .init_state = ti_csi2rx_sd_init_state, +}; + static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_ctx *ctx) { dma_release_channel(ctx->dma.chan); @@ -936,6 +1071,7 @@ static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_ctx *ctx) static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) { + v4l2_subdev_cleanup(&csi->subdev); media_device_unregister(&csi->mdev); v4l2_device_unregister(&csi->v4l2_dev); media_device_cleanup(&csi->mdev); @@ -1001,7 +1137,7 @@ static int ti_csi2rx_link_validate(struct media_link *link) const struct ti_csi2rx_fmt *ti_fmt; int ret; - ret = v4l2_subdev_call_state_active(csi->source, pad, + ret = v4l2_subdev_call_state_active(&csi->subdev, pad, get_fmt, &source_fmt); if (ret) return ret; @@ -1046,6 +1182,10 @@ static const struct media_entity_operations ti_csi2rx_video_entity_ops = { .link_validate = ti_csi2rx_link_validate, }; +static const struct media_entity_operations ti_csi2rx_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) { struct dma_slave_config cfg = { @@ -1077,7 +1217,8 @@ static int ti_csi2rx_init_dma(struct ti_csi2rx_ctx *ctx) static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) { struct media_device *mdev = &csi->mdev; - int ret; + struct v4l2_subdev *sd = &csi->subdev; + int ret, i; mdev->dev = csi->dev; mdev->hw_revision = 1; @@ -1089,16 +1230,50 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); if (ret) - return ret; + goto cleanup_media; ret = media_device_register(mdev); - if (ret) { - v4l2_device_unregister(&csi->v4l2_dev); - media_device_cleanup(mdev); - return ret; - } + if (ret) + goto unregister_v4l2; + + v4l2_subdev_init(sd, &ti_csi2rx_subdev_ops); + sd->internal_ops = &ti_csi2rx_internal_ops; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + strscpy(sd->name, dev_name(csi->dev), sizeof(sd->name)); + sd->dev = csi->dev; + sd->entity.ops = &ti_csi2rx_subdev_entity_ops; + + csi->pads[TI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + + for (i = TI_CSI2RX_PAD_FIRST_SOURCE; i < TI_CSI2RX_NUM_PADS; i++) + csi->pads[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(csi->pads), + csi->pads); + if (ret) + goto unregister_media; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto unregister_media; + + ret = v4l2_device_register_subdev(&csi->v4l2_dev, sd); + if (ret) + goto cleanup_subdev; return 0; + +cleanup_subdev: + v4l2_subdev_cleanup(sd); +unregister_media: + media_device_unregister(mdev); +unregister_v4l2: + v4l2_device_unregister(&csi->v4l2_dev); +cleanup_media: + media_device_cleanup(mdev); + + return ret; } static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) @@ -1125,9 +1300,9 @@ static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) ti_csi2rx_fill_fmt(fmt, &ctx->v_fmt); - csi->pad.flags = MEDIA_PAD_FL_SINK; + ctx->pad.flags = MEDIA_PAD_FL_SINK; vdev->entity.ops = &ti_csi2rx_video_entity_ops; - ret = media_entity_pads_init(&ctx->vdev.entity, 1, &csi->pad); + ret = media_entity_pads_init(&ctx->vdev.entity, 1, &ctx->pad); if (ret) return ret; @@ -1183,6 +1358,8 @@ static int ti_csi2rx_probe(struct platform_device *pdev) if (!csi->drain.vaddr) return -ENOMEM; + mutex_init(&csi->mutex); + ret = ti_csi2rx_v4l2_init(csi); if (ret) goto err_v4l2; @@ -1215,6 +1392,7 @@ static int ti_csi2rx_probe(struct platform_device *pdev) ti_csi2rx_cleanup_ctx(&csi->ctx[i]); err_v4l2: + mutex_destroy(&csi->mutex); dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, csi->drain.paddr); return ret; @@ -1235,6 +1413,7 @@ static int ti_csi2rx_remove(struct platform_device *pdev) ti_csi2rx_cleanup_notifier(csi); ti_csi2rx_cleanup_v4l2(csi); + mutex_destroy(&csi->mutex); dma_free_coherent(csi->dev, csi->drain.len, csi->drain.vaddr, csi->drain.paddr);