xref: /linux/drivers/media/platform/rockchip/rkcif/rkcif-dev.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockchip Camera Interface (CIF) Driver
4  *
5  * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
6  * Copyright (C) 2020 Maxime Chevallier <maxime.chevallier@bootlin.com>
7  * Copyright (C) 2023 Mehdi Djait <mehdi.djait@bootlin.com>
8  * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net>
9  * Copyright (C) 2025 Collabora, Ltd.
10  */
11 
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <linux/interrupt.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/of_graph.h>
19 #include <linux/of_platform.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/reset.h>
22 
23 #include <media/v4l2-fwnode.h>
24 #include <media/v4l2-mc.h>
25 
26 #include "rkcif-capture-dvp.h"
27 #include "rkcif-capture-mipi.h"
28 #include "rkcif-common.h"
29 
30 static const char *const px30_vip_clks[] = {
31 	"aclk",
32 	"hclk",
33 	"pclk",
34 };
35 
36 static const struct rkcif_match_data px30_vip_match_data = {
37 	.clks = px30_vip_clks,
38 	.clks_num = ARRAY_SIZE(px30_vip_clks),
39 	.dvp = &rkcif_px30_vip_dvp_match_data,
40 };
41 
42 static const char *const rk3568_vicap_clks[] = {
43 	"aclk",
44 	"hclk",
45 	"dclk",
46 	"iclk",
47 };
48 
49 static const struct rkcif_match_data rk3568_vicap_match_data = {
50 	.clks = rk3568_vicap_clks,
51 	.clks_num = ARRAY_SIZE(rk3568_vicap_clks),
52 	.dvp = &rkcif_rk3568_vicap_dvp_match_data,
53 	.mipi = &rkcif_rk3568_vicap_mipi_match_data,
54 };
55 
56 static const struct of_device_id rkcif_plat_of_match[] = {
57 	{
58 		.compatible = "rockchip,px30-vip",
59 		.data = &px30_vip_match_data,
60 	},
61 	{
62 		.compatible = "rockchip,rk3568-vicap",
63 		.data = &rk3568_vicap_match_data,
64 	},
65 	{}
66 };
67 MODULE_DEVICE_TABLE(of, rkcif_plat_of_match);
68 
69 static int rkcif_register(struct rkcif_device *rkcif)
70 {
71 	int ret;
72 
73 	ret = rkcif_dvp_register(rkcif);
74 	if (ret && ret != -ENODEV)
75 		goto err;
76 
77 	ret = rkcif_mipi_register(rkcif);
78 	if (ret && ret != -ENODEV)
79 		goto err_dvp_unregister;
80 
81 	return 0;
82 
83 err_dvp_unregister:
84 	rkcif_dvp_unregister(rkcif);
85 err:
86 	return ret;
87 }
88 
89 static void rkcif_unregister(struct rkcif_device *rkcif)
90 {
91 	rkcif_mipi_unregister(rkcif);
92 	rkcif_dvp_unregister(rkcif);
93 }
94 
95 static int rkcif_notifier_bound(struct v4l2_async_notifier *notifier,
96 				struct v4l2_subdev *sd,
97 				struct v4l2_async_connection *asd)
98 {
99 	struct rkcif_device *rkcif =
100 		container_of(notifier, struct rkcif_device, notifier);
101 	struct rkcif_remote *remote =
102 		container_of(asd, struct rkcif_remote, async_conn);
103 	struct media_pad *sink_pad =
104 		&remote->interface->pads[RKCIF_IF_PAD_SINK];
105 	int ret;
106 
107 	ret = v4l2_create_fwnode_links_to_pad(sd, sink_pad,
108 					      MEDIA_LNK_FL_ENABLED);
109 	if (ret) {
110 		dev_err(rkcif->dev, "failed to link source pad of %s\n",
111 			sd->name);
112 		return ret;
113 	}
114 
115 	remote->sd = sd;
116 
117 	return 0;
118 }
119 
120 static int rkcif_notifier_complete(struct v4l2_async_notifier *notifier)
121 {
122 	struct rkcif_device *rkcif =
123 		container_of(notifier, struct rkcif_device, notifier);
124 
125 	return v4l2_device_register_subdev_nodes(&rkcif->v4l2_dev);
126 }
127 
128 static const struct v4l2_async_notifier_operations rkcif_notifier_ops = {
129 	.bound = rkcif_notifier_bound,
130 	.complete = rkcif_notifier_complete,
131 };
132 
133 static irqreturn_t rkcif_isr(int irq, void *ctx)
134 {
135 	irqreturn_t ret = IRQ_NONE;
136 
137 	if (rkcif_dvp_isr(irq, ctx) == IRQ_HANDLED)
138 		ret = IRQ_HANDLED;
139 
140 	if (rkcif_mipi_isr(irq, ctx) == IRQ_HANDLED)
141 		ret = IRQ_HANDLED;
142 
143 	return ret;
144 }
145 
146 static int rkcif_probe(struct platform_device *pdev)
147 {
148 	struct device *dev = &pdev->dev;
149 	struct rkcif_device *rkcif;
150 	int ret, irq;
151 
152 	rkcif = devm_kzalloc(dev, sizeof(*rkcif), GFP_KERNEL);
153 	if (!rkcif)
154 		return -ENOMEM;
155 
156 	rkcif->match_data = of_device_get_match_data(dev);
157 	if (!rkcif->match_data)
158 		return -ENODEV;
159 
160 	dev_set_drvdata(dev, rkcif);
161 	rkcif->dev = dev;
162 
163 	rkcif->base_addr = devm_platform_ioremap_resource(pdev, 0);
164 	if (IS_ERR(rkcif->base_addr))
165 		return PTR_ERR(rkcif->base_addr);
166 
167 	irq = platform_get_irq(pdev, 0);
168 	if (irq < 0)
169 		return irq;
170 
171 	ret = devm_request_irq(dev, irq, rkcif_isr, IRQF_SHARED,
172 			       dev_driver_string(dev), dev);
173 	if (ret)
174 		return dev_err_probe(dev, ret, "failed to request irq\n");
175 
176 	if (rkcif->match_data->clks_num > RKCIF_CLK_MAX)
177 		return dev_err_probe(dev, -EINVAL, "invalid number of clocks\n");
178 
179 	rkcif->clks_num = rkcif->match_data->clks_num;
180 	for (unsigned int i = 0; i < rkcif->clks_num; i++)
181 		rkcif->clks[i].id = rkcif->match_data->clks[i];
182 	ret = devm_clk_bulk_get(dev, rkcif->clks_num, rkcif->clks);
183 	if (ret)
184 		return dev_err_probe(dev, ret, "failed to get clocks\n");
185 
186 	rkcif->reset = devm_reset_control_array_get_exclusive(dev);
187 	if (IS_ERR(rkcif->reset))
188 		return PTR_ERR(rkcif->reset);
189 
190 	rkcif->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
191 						     "rockchip,grf");
192 	if (IS_ERR(rkcif->grf))
193 		rkcif->grf = NULL;
194 
195 	pm_runtime_enable(&pdev->dev);
196 
197 	rkcif->media_dev.dev = dev;
198 	strscpy(rkcif->media_dev.model, RKCIF_DRIVER_NAME,
199 		sizeof(rkcif->media_dev.model));
200 	media_device_init(&rkcif->media_dev);
201 
202 	rkcif->v4l2_dev.mdev = &rkcif->media_dev;
203 	ret = v4l2_device_register(dev, &rkcif->v4l2_dev);
204 	if (ret)
205 		goto err_media_dev_cleanup;
206 
207 	ret = media_device_register(&rkcif->media_dev);
208 	if (ret < 0) {
209 		dev_err(dev, "failed to register media device: %d\n", ret);
210 		goto err_v4l2_dev_unregister;
211 	}
212 
213 	v4l2_async_nf_init(&rkcif->notifier, &rkcif->v4l2_dev);
214 	rkcif->notifier.ops = &rkcif_notifier_ops;
215 
216 	ret = rkcif_register(rkcif);
217 	if (ret) {
218 		dev_err(dev, "failed to register media entities: %d\n", ret);
219 		goto err_notifier_cleanup;
220 	}
221 
222 	ret = v4l2_async_nf_register(&rkcif->notifier);
223 	if (ret)
224 		goto err_rkcif_unregister;
225 
226 	return 0;
227 
228 err_rkcif_unregister:
229 	rkcif_unregister(rkcif);
230 err_notifier_cleanup:
231 	v4l2_async_nf_cleanup(&rkcif->notifier);
232 	media_device_unregister(&rkcif->media_dev);
233 err_v4l2_dev_unregister:
234 	v4l2_device_unregister(&rkcif->v4l2_dev);
235 err_media_dev_cleanup:
236 	media_device_cleanup(&rkcif->media_dev);
237 	pm_runtime_disable(&pdev->dev);
238 	return ret;
239 }
240 
241 static void rkcif_remove(struct platform_device *pdev)
242 {
243 	struct rkcif_device *rkcif = platform_get_drvdata(pdev);
244 
245 	v4l2_async_nf_unregister(&rkcif->notifier);
246 	rkcif_unregister(rkcif);
247 	v4l2_async_nf_cleanup(&rkcif->notifier);
248 	media_device_unregister(&rkcif->media_dev);
249 	v4l2_device_unregister(&rkcif->v4l2_dev);
250 	media_device_cleanup(&rkcif->media_dev);
251 	pm_runtime_disable(&pdev->dev);
252 }
253 
254 static int rkcif_runtime_suspend(struct device *dev)
255 {
256 	struct rkcif_device *rkcif = dev_get_drvdata(dev);
257 
258 	/*
259 	 * Reset CIF (CRU, DMA, FIFOs) to allow a clean resume.
260 	 * Since this resets the IOMMU too, we cannot issue this reset when
261 	 * resuming.
262 	 */
263 	reset_control_assert(rkcif->reset);
264 	udelay(5);
265 	reset_control_deassert(rkcif->reset);
266 
267 	clk_bulk_disable_unprepare(rkcif->clks_num, rkcif->clks);
268 
269 	return 0;
270 }
271 
272 static int rkcif_runtime_resume(struct device *dev)
273 {
274 	struct rkcif_device *rkcif = dev_get_drvdata(dev);
275 	int ret;
276 
277 	ret = clk_bulk_prepare_enable(rkcif->clks_num, rkcif->clks);
278 	if (ret) {
279 		dev_err(dev, "failed to enable clocks\n");
280 		return ret;
281 	}
282 
283 	return 0;
284 }
285 
286 static const struct dev_pm_ops rkcif_plat_pm_ops = {
287 	.runtime_suspend = rkcif_runtime_suspend,
288 	.runtime_resume = rkcif_runtime_resume,
289 };
290 
291 static struct platform_driver rkcif_plat_drv = {
292 	.driver = {
293 		   .name = RKCIF_DRIVER_NAME,
294 		   .of_match_table = rkcif_plat_of_match,
295 		   .pm = &rkcif_plat_pm_ops,
296 	},
297 	.probe = rkcif_probe,
298 	.remove = rkcif_remove,
299 };
300 module_platform_driver(rkcif_plat_drv);
301 
302 MODULE_DESCRIPTION("Rockchip Camera Interface (CIF) platform driver");
303 MODULE_LICENSE("GPL");
304