1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
4  * Author: Yong Deng <yong.deng@magewell.com>
5  * Copyright 2021-2022 Bootlin
6  * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/err.h>
11 #include <linux/interrupt.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/regmap.h>
18 #include <linux/reset.h>
19 #include <media/v4l2-device.h>
20 #include <media/v4l2-mc.h>
21 
22 #include "sun6i_csi.h"
23 #include "sun6i_csi_bridge.h"
24 #include "sun6i_csi_capture.h"
25 #include "sun6i_csi_reg.h"
26 
27 /* Media */
28 
29 static const struct media_device_ops sun6i_csi_media_ops = {
30 	.link_notify = v4l2_pipeline_link_notify,
31 };
32 
33 /* V4L2 */
34 
35 static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev)
36 {
37 	struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
38 	struct media_device *media_dev = &v4l2->media_dev;
39 	struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
40 	struct device *dev = csi_dev->dev;
41 	int ret;
42 
43 	/* Media Device */
44 
45 	strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION,
46 		sizeof(media_dev->model));
47 	media_dev->hw_revision = 0;
48 	media_dev->ops = &sun6i_csi_media_ops;
49 	media_dev->dev = dev;
50 
51 	media_device_init(media_dev);
52 
53 	ret = media_device_register(media_dev);
54 	if (ret) {
55 		dev_err(dev, "failed to register media device: %d\n", ret);
56 		goto error_media;
57 	}
58 
59 	/* V4L2 Device */
60 
61 	v4l2_dev->mdev = media_dev;
62 
63 	ret = v4l2_device_register(dev, v4l2_dev);
64 	if (ret) {
65 		dev_err(dev, "failed to register v4l2 device: %d\n", ret);
66 		goto error_media;
67 	}
68 
69 	return 0;
70 
71 error_media:
72 	media_device_unregister(media_dev);
73 	media_device_cleanup(media_dev);
74 
75 	return ret;
76 }
77 
78 static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev)
79 {
80 	struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2;
81 
82 	media_device_unregister(&v4l2->media_dev);
83 	v4l2_device_unregister(&v4l2->v4l2_dev);
84 	media_device_cleanup(&v4l2->media_dev);
85 }
86 
87 /* Platform */
88 
89 static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
90 {
91 	struct sun6i_csi_device *csi_dev = private;
92 	bool capture_streaming = csi_dev->capture.state.streaming;
93 	struct regmap *regmap = csi_dev->regmap;
94 	u32 status = 0, enable = 0;
95 
96 	regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status);
97 	regmap_read(regmap, SUN6I_CSI_CH_INT_EN_REG, &enable);
98 
99 	if (!status)
100 		return IRQ_NONE;
101 	else if (!(status & enable) || !capture_streaming)
102 		goto complete;
103 
104 	if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) ||
105 	    (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) ||
106 	    (status & SUN6I_CSI_CH_INT_STA_FIFO2_OF) ||
107 	    (status & SUN6I_CSI_CH_INT_STA_HB_OF)) {
108 		regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status);
109 
110 		regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
111 				   SUN6I_CSI_EN_CSI_EN, 0);
112 		regmap_update_bits(regmap, SUN6I_CSI_EN_REG,
113 				   SUN6I_CSI_EN_CSI_EN, SUN6I_CSI_EN_CSI_EN);
114 		return IRQ_HANDLED;
115 	}
116 
117 	if (status & SUN6I_CSI_CH_INT_STA_FD)
118 		sun6i_csi_capture_frame_done(csi_dev);
119 
120 	if (status & SUN6I_CSI_CH_INT_STA_VS)
121 		sun6i_csi_capture_sync(csi_dev);
122 
123 complete:
124 	regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status);
125 
126 	return IRQ_HANDLED;
127 }
128 
129 static int sun6i_csi_suspend(struct device *dev)
130 {
131 	struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
132 
133 	reset_control_assert(csi_dev->reset);
134 	clk_disable_unprepare(csi_dev->clock_ram);
135 	clk_disable_unprepare(csi_dev->clock_mod);
136 
137 	return 0;
138 }
139 
140 static int sun6i_csi_resume(struct device *dev)
141 {
142 	struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev);
143 	int ret;
144 
145 	ret = reset_control_deassert(csi_dev->reset);
146 	if (ret) {
147 		dev_err(dev, "failed to deassert reset\n");
148 		return ret;
149 	}
150 
151 	ret = clk_prepare_enable(csi_dev->clock_mod);
152 	if (ret) {
153 		dev_err(dev, "failed to enable module clock\n");
154 		goto error_reset;
155 	}
156 
157 	ret = clk_prepare_enable(csi_dev->clock_ram);
158 	if (ret) {
159 		dev_err(dev, "failed to enable ram clock\n");
160 		goto error_clock_mod;
161 	}
162 
163 	return 0;
164 
165 error_clock_mod:
166 	clk_disable_unprepare(csi_dev->clock_mod);
167 
168 error_reset:
169 	reset_control_assert(csi_dev->reset);
170 
171 	return ret;
172 }
173 
174 static const struct dev_pm_ops sun6i_csi_pm_ops = {
175 	.runtime_suspend	= sun6i_csi_suspend,
176 	.runtime_resume		= sun6i_csi_resume,
177 };
178 
179 static const struct regmap_config sun6i_csi_regmap_config = {
180 	.reg_bits       = 32,
181 	.reg_stride     = 4,
182 	.val_bits       = 32,
183 	.max_register	= 0x9c,
184 };
185 
186 static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev,
187 				     struct platform_device *platform_dev)
188 {
189 	struct device *dev = csi_dev->dev;
190 	const struct sun6i_csi_variant *variant;
191 	void __iomem *io_base;
192 	int ret;
193 	int irq;
194 
195 	variant = of_device_get_match_data(dev);
196 	if (!variant)
197 		return -EINVAL;
198 
199 	/* Registers */
200 
201 	io_base = devm_platform_ioremap_resource(platform_dev, 0);
202 	if (IS_ERR(io_base))
203 		return PTR_ERR(io_base);
204 
205 	csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base,
206 						    &sun6i_csi_regmap_config);
207 	if (IS_ERR(csi_dev->regmap)) {
208 		dev_err(dev, "failed to init register map\n");
209 		return PTR_ERR(csi_dev->regmap);
210 	}
211 
212 	/* Clocks */
213 
214 	csi_dev->clock_mod = devm_clk_get(dev, "mod");
215 	if (IS_ERR(csi_dev->clock_mod)) {
216 		dev_err(dev, "failed to acquire module clock\n");
217 		return PTR_ERR(csi_dev->clock_mod);
218 	}
219 
220 	csi_dev->clock_ram = devm_clk_get(dev, "ram");
221 	if (IS_ERR(csi_dev->clock_ram)) {
222 		dev_err(dev, "failed to acquire ram clock\n");
223 		return PTR_ERR(csi_dev->clock_ram);
224 	}
225 
226 	ret = clk_set_rate_exclusive(csi_dev->clock_mod,
227 				     variant->clock_mod_rate);
228 	if (ret) {
229 		dev_err(dev, "failed to set mod clock rate\n");
230 		return ret;
231 	}
232 
233 	/* Reset */
234 
235 	csi_dev->reset = devm_reset_control_get_shared(dev, NULL);
236 	if (IS_ERR(csi_dev->reset)) {
237 		dev_err(dev, "failed to acquire reset\n");
238 		ret = PTR_ERR(csi_dev->reset);
239 		goto error_clock_rate_exclusive;
240 	}
241 
242 	/* Interrupt */
243 
244 	irq = platform_get_irq(platform_dev, 0);
245 	if (irq < 0) {
246 		ret = -ENXIO;
247 		goto error_clock_rate_exclusive;
248 	}
249 
250 	ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME,
251 			       csi_dev);
252 	if (ret) {
253 		dev_err(dev, "failed to request interrupt\n");
254 		goto error_clock_rate_exclusive;
255 	}
256 
257 	/* Runtime PM */
258 
259 	pm_runtime_enable(dev);
260 
261 	return 0;
262 
263 error_clock_rate_exclusive:
264 	clk_rate_exclusive_put(csi_dev->clock_mod);
265 
266 	return ret;
267 }
268 
269 static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev)
270 {
271 	pm_runtime_disable(csi_dev->dev);
272 	clk_rate_exclusive_put(csi_dev->clock_mod);
273 }
274 
275 static int sun6i_csi_probe(struct platform_device *platform_dev)
276 {
277 	struct sun6i_csi_device *csi_dev;
278 	struct device *dev = &platform_dev->dev;
279 	int ret;
280 
281 	csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL);
282 	if (!csi_dev)
283 		return -ENOMEM;
284 
285 	csi_dev->dev = &platform_dev->dev;
286 	platform_set_drvdata(platform_dev, csi_dev);
287 
288 	ret = sun6i_csi_resources_setup(csi_dev, platform_dev);
289 	if (ret)
290 		return ret;
291 
292 	ret = sun6i_csi_v4l2_setup(csi_dev);
293 	if (ret)
294 		goto error_resources;
295 
296 	ret = sun6i_csi_bridge_setup(csi_dev);
297 	if (ret)
298 		goto error_v4l2;
299 
300 	ret = sun6i_csi_capture_setup(csi_dev);
301 	if (ret)
302 		goto error_bridge;
303 
304 	return 0;
305 
306 error_bridge:
307 	sun6i_csi_bridge_cleanup(csi_dev);
308 
309 error_v4l2:
310 	sun6i_csi_v4l2_cleanup(csi_dev);
311 
312 error_resources:
313 	sun6i_csi_resources_cleanup(csi_dev);
314 
315 	return ret;
316 }
317 
318 static int sun6i_csi_remove(struct platform_device *pdev)
319 {
320 	struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev);
321 
322 	sun6i_csi_capture_cleanup(csi_dev);
323 	sun6i_csi_bridge_cleanup(csi_dev);
324 	sun6i_csi_v4l2_cleanup(csi_dev);
325 	sun6i_csi_resources_cleanup(csi_dev);
326 
327 	return 0;
328 }
329 
330 static const struct sun6i_csi_variant sun6i_a31_csi_variant = {
331 	.clock_mod_rate	= 297000000,
332 };
333 
334 static const struct sun6i_csi_variant sun50i_a64_csi_variant = {
335 	.clock_mod_rate	= 300000000,
336 };
337 
338 static const struct of_device_id sun6i_csi_of_match[] = {
339 	{
340 		.compatible	= "allwinner,sun6i-a31-csi",
341 		.data		= &sun6i_a31_csi_variant,
342 	},
343 	{
344 		.compatible	= "allwinner,sun8i-a83t-csi",
345 		.data		= &sun6i_a31_csi_variant,
346 	},
347 	{
348 		.compatible	= "allwinner,sun8i-h3-csi",
349 		.data		= &sun6i_a31_csi_variant,
350 	},
351 	{
352 		.compatible	= "allwinner,sun8i-v3s-csi",
353 		.data		= &sun6i_a31_csi_variant,
354 	},
355 	{
356 		.compatible	= "allwinner,sun50i-a64-csi",
357 		.data		= &sun50i_a64_csi_variant,
358 	},
359 	{},
360 };
361 
362 MODULE_DEVICE_TABLE(of, sun6i_csi_of_match);
363 
364 static struct platform_driver sun6i_csi_platform_driver = {
365 	.probe	= sun6i_csi_probe,
366 	.remove	= sun6i_csi_remove,
367 	.driver	= {
368 		.name		= SUN6I_CSI_NAME,
369 		.of_match_table	= of_match_ptr(sun6i_csi_of_match),
370 		.pm		= &sun6i_csi_pm_ops,
371 	},
372 };
373 
374 module_platform_driver(sun6i_csi_platform_driver);
375 
376 MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver");
377 MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>");
378 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
379 MODULE_LICENSE("GPL");
380