1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for STM32 Digital Camera Memory Interface Pixel Processor
4  *
5  * Copyright (C) STMicroelectronics SA 2023
6  * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
7  *          Alain Volmat <alain.volmat@foss.st.com>
8  *          for STMicroelectronics.
9  */
10 
11 #include <linux/clk.h>
12 #include <linux/delay.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/pinctrl/consumer.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/property.h>
19 #include <linux/reset.h>
20 #include <media/media-device.h>
21 #include <media/v4l2-device.h>
22 #include <media/v4l2-fwnode.h>
23 
24 #include "dcmipp-common.h"
25 
26 #define DCMIPP_MDEV_MODEL_NAME "DCMIPP MDEV"
27 
28 #define DCMIPP_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) {	\
29 	.src_ent = src,						\
30 	.src_pad = srcpad,					\
31 	.sink_ent = sink,					\
32 	.sink_pad = sinkpad,					\
33 	.flags = link_flags,					\
34 }
35 
36 struct dcmipp_device {
37 	/* The platform device */
38 	struct platform_device		pdev;
39 	struct device			*dev;
40 
41 	/* Hardware resources */
42 	void __iomem			*regs;
43 	struct clk			*mclk;
44 	struct clk			*kclk;
45 
46 	/* The pipeline configuration */
47 	const struct dcmipp_pipeline_config	*pipe_cfg;
48 
49 	/* The Associated media_device parent */
50 	struct media_device		mdev;
51 
52 	/* Internal v4l2 parent device*/
53 	struct v4l2_device		v4l2_dev;
54 
55 	/* Entities */
56 	struct dcmipp_ent_device	**entity;
57 
58 	struct v4l2_async_notifier	notifier;
59 };
60 
61 static inline struct dcmipp_device *
notifier_to_dcmipp(struct v4l2_async_notifier * n)62 notifier_to_dcmipp(struct v4l2_async_notifier *n)
63 {
64 	return container_of(n, struct dcmipp_device, notifier);
65 }
66 
67 /* Structure which describes individual configuration for each entity */
68 struct dcmipp_ent_config {
69 	const char *name;
70 	struct dcmipp_ent_device *(*init)
71 		(struct device *dev, const char *entity_name,
72 		 struct v4l2_device *v4l2_dev, void __iomem *regs);
73 	void (*release)(struct dcmipp_ent_device *ved);
74 };
75 
76 /* Structure which describes links between entities */
77 struct dcmipp_ent_link {
78 	unsigned int src_ent;
79 	u16 src_pad;
80 	unsigned int sink_ent;
81 	u16 sink_pad;
82 	u32 flags;
83 };
84 
85 /* Structure which describes the whole topology */
86 struct dcmipp_pipeline_config {
87 	const struct dcmipp_ent_config *ents;
88 	size_t num_ents;
89 	const struct dcmipp_ent_link *links;
90 	size_t num_links;
91 	u32 hw_revision;
92 	bool has_csi2;
93 	bool needs_mclk;
94 };
95 
96 /* --------------------------------------------------------------------------
97  * Topology Configuration
98  */
99 
100 static const struct dcmipp_ent_config stm32mp13_ent_config[] = {
101 	{
102 		.name = "dcmipp_input",
103 		.init = dcmipp_inp_ent_init,
104 		.release = dcmipp_inp_ent_release,
105 	},
106 	{
107 		.name = "dcmipp_dump_postproc",
108 		.init = dcmipp_byteproc_ent_init,
109 		.release = dcmipp_byteproc_ent_release,
110 	},
111 	{
112 		.name = "dcmipp_dump_capture",
113 		.init = dcmipp_bytecap_ent_init,
114 		.release = dcmipp_bytecap_ent_release,
115 	},
116 };
117 
118 #define ID_INPUT 0
119 #define ID_DUMP_BYTEPROC 1
120 #define ID_DUMP_CAPTURE 2
121 
122 static const struct dcmipp_ent_link stm32mp13_ent_links[] = {
123 	DCMIPP_ENT_LINK(ID_INPUT, 1, ID_DUMP_BYTEPROC, 0,
124 			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
125 	DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE,  0,
126 			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
127 };
128 
129 #define DCMIPP_STM32MP13_VERR	0x10
130 static const struct dcmipp_pipeline_config stm32mp13_pipe_cfg = {
131 	.ents		= stm32mp13_ent_config,
132 	.num_ents	= ARRAY_SIZE(stm32mp13_ent_config),
133 	.links		= stm32mp13_ent_links,
134 	.num_links	= ARRAY_SIZE(stm32mp13_ent_links),
135 	.hw_revision	= DCMIPP_STM32MP13_VERR
136 };
137 
138 static const struct dcmipp_ent_config stm32mp25_ent_config[] = {
139 	{
140 		.name = "dcmipp_input",
141 		.init = dcmipp_inp_ent_init,
142 		.release = dcmipp_inp_ent_release,
143 	},
144 	{
145 		.name = "dcmipp_dump_postproc",
146 		.init = dcmipp_byteproc_ent_init,
147 		.release = dcmipp_byteproc_ent_release,
148 	},
149 	{
150 		.name = "dcmipp_dump_capture",
151 		.init = dcmipp_bytecap_ent_init,
152 		.release = dcmipp_bytecap_ent_release,
153 	},
154 };
155 
156 static const struct dcmipp_ent_link stm32mp25_ent_links[] = {
157 	DCMIPP_ENT_LINK(ID_INPUT, 1, ID_DUMP_BYTEPROC, 0,
158 			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
159 	DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE,  0,
160 			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
161 };
162 
163 #define DCMIPP_STM32MP25_VERR  0x30
164 static const struct dcmipp_pipeline_config stm32mp25_pipe_cfg = {
165 	.ents		= stm32mp25_ent_config,
166 	.num_ents	= ARRAY_SIZE(stm32mp25_ent_config),
167 	.links		= stm32mp25_ent_links,
168 	.num_links	= ARRAY_SIZE(stm32mp25_ent_links),
169 	.hw_revision    = DCMIPP_STM32MP25_VERR,
170 	.has_csi2	= true,
171 	.needs_mclk	= true
172 };
173 
174 #define LINK_FLAG_TO_STR(f) ((f) == 0 ? "" :\
175 			     (f) == MEDIA_LNK_FL_ENABLED ? "ENABLED" :\
176 			     (f) == MEDIA_LNK_FL_IMMUTABLE ? "IMMUTABLE" :\
177 			     (f) == (MEDIA_LNK_FL_ENABLED |\
178 				     MEDIA_LNK_FL_IMMUTABLE) ?\
179 					"ENABLED, IMMUTABLE" :\
180 			     "UNKNOWN")
181 
dcmipp_create_links(struct dcmipp_device * dcmipp)182 static int dcmipp_create_links(struct dcmipp_device *dcmipp)
183 {
184 	unsigned int i;
185 	int ret;
186 
187 	/* Initialize the links between entities */
188 	for (i = 0; i < dcmipp->pipe_cfg->num_links; i++) {
189 		const struct dcmipp_ent_link *link =
190 			&dcmipp->pipe_cfg->links[i];
191 		struct dcmipp_ent_device *ved_src =
192 			dcmipp->entity[link->src_ent];
193 		struct dcmipp_ent_device *ved_sink =
194 			dcmipp->entity[link->sink_ent];
195 
196 		dev_dbg(dcmipp->dev, "Create link \"%s\":%d -> %d:\"%s\" [%s]\n",
197 			dcmipp->pipe_cfg->ents[link->src_ent].name,
198 			link->src_pad, link->sink_pad,
199 			dcmipp->pipe_cfg->ents[link->sink_ent].name,
200 			LINK_FLAG_TO_STR(link->flags));
201 
202 		ret = media_create_pad_link(ved_src->ent, link->src_pad,
203 					    ved_sink->ent, link->sink_pad,
204 					    link->flags);
205 		if (ret)
206 			return ret;
207 	}
208 
209 	return 0;
210 }
211 
212 static int dcmipp_graph_init(struct dcmipp_device *dcmipp);
213 
dcmipp_create_subdevs(struct dcmipp_device * dcmipp)214 static int dcmipp_create_subdevs(struct dcmipp_device *dcmipp)
215 {
216 	int ret, i;
217 
218 	/* Call all subdev inits */
219 	for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
220 		const char *name = dcmipp->pipe_cfg->ents[i].name;
221 
222 		dev_dbg(dcmipp->dev, "add subdev %s\n", name);
223 		dcmipp->entity[i] =
224 			dcmipp->pipe_cfg->ents[i].init(dcmipp->dev, name,
225 						       &dcmipp->v4l2_dev,
226 						       dcmipp->regs);
227 		if (IS_ERR(dcmipp->entity[i])) {
228 			dev_err(dcmipp->dev, "failed to init subdev %s\n",
229 				name);
230 			ret = PTR_ERR(dcmipp->entity[i]);
231 			goto err_init_entity;
232 		}
233 	}
234 
235 	/* Initialize links */
236 	ret = dcmipp_create_links(dcmipp);
237 	if (ret)
238 		goto err_init_entity;
239 
240 	ret = dcmipp_graph_init(dcmipp);
241 	if (ret < 0)
242 		goto err_init_entity;
243 
244 	return 0;
245 
246 err_init_entity:
247 	while (i-- > 0)
248 		dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]);
249 	return ret;
250 }
251 
252 static const struct of_device_id dcmipp_of_match[] = {
253 	{ .compatible = "st,stm32mp13-dcmipp", .data = &stm32mp13_pipe_cfg },
254 	{ .compatible = "st,stm32mp25-dcmipp", .data = &stm32mp25_pipe_cfg },
255 	{ /* end node */ },
256 };
257 MODULE_DEVICE_TABLE(of, dcmipp_of_match);
258 
dcmipp_irq_thread(int irq,void * arg)259 static irqreturn_t dcmipp_irq_thread(int irq, void *arg)
260 {
261 	struct dcmipp_device *dcmipp = arg;
262 	struct dcmipp_ent_device *ved;
263 	unsigned int i;
264 
265 	/* Call irq thread of each entities of pipeline */
266 	for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
267 		ved = dcmipp->entity[i];
268 		if (ved->thread_fn && ved->handler_ret == IRQ_WAKE_THREAD)
269 			ved->thread_fn(irq, ved);
270 	}
271 
272 	return IRQ_HANDLED;
273 }
274 
dcmipp_irq_callback(int irq,void * arg)275 static irqreturn_t dcmipp_irq_callback(int irq, void *arg)
276 {
277 	struct dcmipp_device *dcmipp = arg;
278 	struct dcmipp_ent_device *ved;
279 	irqreturn_t ret = IRQ_HANDLED;
280 	unsigned int i;
281 
282 	/* Call irq handler of each entities of pipeline */
283 	for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
284 		ved = dcmipp->entity[i];
285 		if (ved->handler)
286 			ved->handler_ret = ved->handler(irq, ved);
287 		else if (ved->thread_fn)
288 			ved->handler_ret = IRQ_WAKE_THREAD;
289 		else
290 			ved->handler_ret = IRQ_HANDLED;
291 		if (ved->handler_ret != IRQ_HANDLED)
292 			ret = ved->handler_ret;
293 	}
294 
295 	return ret;
296 }
297 
dcmipp_graph_notify_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)298 static int dcmipp_graph_notify_bound(struct v4l2_async_notifier *notifier,
299 				     struct v4l2_subdev *subdev,
300 				     struct v4l2_async_connection *asd)
301 {
302 	struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
303 	int ret = -EINVAL;
304 	int src_pad, i;
305 	struct dcmipp_ent_device *sink;
306 	struct v4l2_fwnode_endpoint vep = { 0 };
307 	struct fwnode_handle *ep;
308 	enum v4l2_mbus_type supported_types[] = {
309 		V4L2_MBUS_PARALLEL, V4L2_MBUS_BT656, V4L2_MBUS_CSI2_DPHY
310 	};
311 
312 	dev_dbg(dcmipp->dev, "Subdev \"%s\" bound\n", subdev->name);
313 
314 	/*
315 	 * Link this sub-device to DCMIPP, it could be
316 	 * a parallel camera sensor or a CSI-2 to parallel bridge
317 	 */
318 	src_pad = media_entity_get_fwnode_pad(&subdev->entity,
319 					      subdev->fwnode,
320 					      MEDIA_PAD_FL_SOURCE);
321 
322 	/* Get bus characteristics from devicetree */
323 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0,
324 					     FWNODE_GRAPH_ENDPOINT_NEXT);
325 	if (!ep) {
326 		dev_err(dcmipp->dev, "Could not find the endpoint\n");
327 		return -ENODEV;
328 	}
329 
330 	/* Check for supported MBUS type */
331 	for (i = 0; i < ARRAY_SIZE(supported_types); i++) {
332 		/* Only MP25 supports CSI input */
333 		if (supported_types[i] == V4L2_MBUS_CSI2_DPHY &&
334 		    !dcmipp->pipe_cfg->has_csi2)
335 			continue;
336 
337 		vep.bus_type = supported_types[i];
338 		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
339 		if (!ret)
340 			break;
341 	}
342 
343 	fwnode_handle_put(ep);
344 
345 	if (ret) {
346 		dev_err(dcmipp->dev, "Could not parse the endpoint\n");
347 		return ret;
348 	}
349 
350 	if (vep.bus_type != V4L2_MBUS_CSI2_DPHY &&
351 	    vep.bus.parallel.bus_width == 0) {
352 		dev_err(dcmipp->dev, "Invalid parallel interface bus-width\n");
353 		return -ENODEV;
354 	}
355 
356 	/* Only 8 bits bus width supported with BT656 bus */
357 	if (vep.bus_type == V4L2_MBUS_BT656 &&
358 	    vep.bus.parallel.bus_width != 8) {
359 		dev_err(dcmipp->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n",
360 			vep.bus.parallel.bus_width);
361 		return -ENODEV;
362 	}
363 
364 	/* Connect input device to the dcmipp_input subdev */
365 	sink = dcmipp->entity[ID_INPUT];
366 	if (vep.bus_type != V4L2_MBUS_CSI2_DPHY) {
367 		sink->bus.flags = vep.bus.parallel.flags;
368 		sink->bus.bus_width = vep.bus.parallel.bus_width;
369 		sink->bus.data_shift = vep.bus.parallel.data_shift;
370 	}
371 	sink->bus_type = vep.bus_type;
372 	ret = media_create_pad_link(&subdev->entity, src_pad, sink->ent, 0,
373 				    MEDIA_LNK_FL_IMMUTABLE |
374 				    MEDIA_LNK_FL_ENABLED);
375 	if (ret) {
376 		dev_err(dcmipp->dev, "Failed to create media pad link with subdev \"%s\"\n",
377 			subdev->name);
378 		return ret;
379 	}
380 
381 	dev_dbg(dcmipp->dev, "DCMIPP is now linked to \"%s\"\n", subdev->name);
382 
383 	return 0;
384 }
385 
dcmipp_graph_notify_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * sd,struct v4l2_async_connection * asd)386 static void dcmipp_graph_notify_unbind(struct v4l2_async_notifier *notifier,
387 				       struct v4l2_subdev *sd,
388 				       struct v4l2_async_connection *asd)
389 {
390 	struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
391 
392 	dev_dbg(dcmipp->dev, "Removing %s\n", sd->name);
393 }
394 
dcmipp_graph_notify_complete(struct v4l2_async_notifier * notifier)395 static int dcmipp_graph_notify_complete(struct v4l2_async_notifier *notifier)
396 {
397 	struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
398 	int ret;
399 
400 	/* Register the media device */
401 	ret = media_device_register(&dcmipp->mdev);
402 	if (ret) {
403 		dev_err(dcmipp->mdev.dev,
404 			"media device register failed (err=%d)\n", ret);
405 		return ret;
406 	}
407 
408 	/* Expose all subdev's nodes*/
409 	ret = v4l2_device_register_subdev_nodes(&dcmipp->v4l2_dev);
410 	if (ret) {
411 		dev_err(dcmipp->mdev.dev,
412 			"dcmipp subdev nodes registration failed (err=%d)\n",
413 			ret);
414 		media_device_unregister(&dcmipp->mdev);
415 		return ret;
416 	}
417 
418 	dev_dbg(dcmipp->dev, "Notify complete !\n");
419 
420 	return 0;
421 }
422 
423 static const struct v4l2_async_notifier_operations dcmipp_graph_notify_ops = {
424 	.bound = dcmipp_graph_notify_bound,
425 	.unbind = dcmipp_graph_notify_unbind,
426 	.complete = dcmipp_graph_notify_complete,
427 };
428 
dcmipp_graph_init(struct dcmipp_device * dcmipp)429 static int dcmipp_graph_init(struct dcmipp_device *dcmipp)
430 {
431 	struct v4l2_async_connection *asd;
432 	struct fwnode_handle *ep;
433 	int ret;
434 
435 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0,
436 					     FWNODE_GRAPH_ENDPOINT_NEXT);
437 	if (!ep) {
438 		dev_err(dcmipp->dev, "Failed to get next endpoint\n");
439 		return -EINVAL;
440 	}
441 
442 	v4l2_async_nf_init(&dcmipp->notifier, &dcmipp->v4l2_dev);
443 
444 	asd = v4l2_async_nf_add_fwnode_remote(&dcmipp->notifier, ep,
445 					      struct v4l2_async_connection);
446 
447 	fwnode_handle_put(ep);
448 
449 	if (IS_ERR(asd)) {
450 		dev_err(dcmipp->dev, "Failed to add fwnode remote subdev\n");
451 		return PTR_ERR(asd);
452 	}
453 
454 	dcmipp->notifier.ops = &dcmipp_graph_notify_ops;
455 
456 	ret = v4l2_async_nf_register(&dcmipp->notifier);
457 	if (ret < 0) {
458 		dev_err(dcmipp->dev, "Failed to register notifier\n");
459 		v4l2_async_nf_cleanup(&dcmipp->notifier);
460 		return ret;
461 	}
462 
463 	return 0;
464 }
465 
dcmipp_probe(struct platform_device * pdev)466 static int dcmipp_probe(struct platform_device *pdev)
467 {
468 	struct dcmipp_device *dcmipp;
469 	struct clk *kclk, *mclk;
470 	const struct dcmipp_pipeline_config *pipe_cfg;
471 	struct reset_control *rstc;
472 	int irq;
473 	int ret;
474 
475 	dcmipp = devm_kzalloc(&pdev->dev, sizeof(*dcmipp), GFP_KERNEL);
476 	if (!dcmipp)
477 		return -ENOMEM;
478 
479 	dcmipp->dev = &pdev->dev;
480 
481 	pipe_cfg = device_get_match_data(dcmipp->dev);
482 	if (!pipe_cfg) {
483 		dev_err(&pdev->dev, "Can't get device data\n");
484 		return -ENODEV;
485 	}
486 	dcmipp->pipe_cfg = pipe_cfg;
487 
488 	platform_set_drvdata(pdev, dcmipp);
489 
490 	/* Get hardware resources from devicetree */
491 	rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
492 	if (IS_ERR(rstc))
493 		return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
494 				     "Could not get reset control\n");
495 
496 	irq = platform_get_irq(pdev, 0);
497 	if (irq < 0)
498 		return irq;
499 
500 	dcmipp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
501 	if (IS_ERR(dcmipp->regs)) {
502 		dev_err(&pdev->dev, "Could not map registers\n");
503 		return PTR_ERR(dcmipp->regs);
504 	}
505 
506 	ret = devm_request_threaded_irq(&pdev->dev, irq, dcmipp_irq_callback,
507 					dcmipp_irq_thread, IRQF_ONESHOT,
508 					dev_name(&pdev->dev), dcmipp);
509 	if (ret) {
510 		dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
511 		return ret;
512 	}
513 
514 	/* Reset device */
515 	ret = reset_control_assert(rstc);
516 	if (ret) {
517 		dev_err(&pdev->dev, "Failed to assert the reset line\n");
518 		return ret;
519 	}
520 
521 	usleep_range(3000, 5000);
522 
523 	ret = reset_control_deassert(rstc);
524 	if (ret) {
525 		dev_err(&pdev->dev, "Failed to deassert the reset line\n");
526 		return ret;
527 	}
528 
529 	kclk = devm_clk_get(&pdev->dev, "kclk");
530 	if (IS_ERR(kclk))
531 		return dev_err_probe(&pdev->dev, PTR_ERR(kclk),
532 				     "Unable to get kclk\n");
533 	dcmipp->kclk = kclk;
534 
535 	if (dcmipp->pipe_cfg->needs_mclk) {
536 		mclk = devm_clk_get(&pdev->dev, "mclk");
537 		if (IS_ERR(mclk))
538 			return dev_err_probe(&pdev->dev, PTR_ERR(mclk),
539 					     "Unable to get mclk\n");
540 		dcmipp->mclk = mclk;
541 	}
542 
543 	dcmipp->entity = devm_kcalloc(&pdev->dev, dcmipp->pipe_cfg->num_ents,
544 				      sizeof(*dcmipp->entity), GFP_KERNEL);
545 	if (!dcmipp->entity)
546 		return -ENOMEM;
547 
548 	/* Register the v4l2 struct */
549 	ret = v4l2_device_register(&pdev->dev, &dcmipp->v4l2_dev);
550 	if (ret) {
551 		dev_err(&pdev->dev,
552 			"v4l2 device register failed (err=%d)\n", ret);
553 		return ret;
554 	}
555 
556 	/* Link the media device within the v4l2_device */
557 	dcmipp->v4l2_dev.mdev = &dcmipp->mdev;
558 
559 	/* Initialize media device */
560 	strscpy(dcmipp->mdev.model, DCMIPP_MDEV_MODEL_NAME,
561 		sizeof(dcmipp->mdev.model));
562 	dcmipp->mdev.hw_revision = pipe_cfg->hw_revision;
563 	dcmipp->mdev.dev = &pdev->dev;
564 	media_device_init(&dcmipp->mdev);
565 
566 	/* Initialize subdevs */
567 	ret = dcmipp_create_subdevs(dcmipp);
568 	if (ret) {
569 		media_device_cleanup(&dcmipp->mdev);
570 		v4l2_device_unregister(&dcmipp->v4l2_dev);
571 		return ret;
572 	}
573 
574 	pm_runtime_enable(dcmipp->dev);
575 
576 	dev_info(&pdev->dev, "Probe done");
577 
578 	return 0;
579 }
580 
dcmipp_remove(struct platform_device * pdev)581 static void dcmipp_remove(struct platform_device *pdev)
582 {
583 	struct dcmipp_device *dcmipp = platform_get_drvdata(pdev);
584 	unsigned int i;
585 
586 	pm_runtime_disable(&pdev->dev);
587 
588 	v4l2_async_nf_unregister(&dcmipp->notifier);
589 	v4l2_async_nf_cleanup(&dcmipp->notifier);
590 
591 	for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++)
592 		dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]);
593 
594 	media_device_unregister(&dcmipp->mdev);
595 	media_device_cleanup(&dcmipp->mdev);
596 
597 	v4l2_device_unregister(&dcmipp->v4l2_dev);
598 }
599 
dcmipp_runtime_suspend(struct device * dev)600 static int dcmipp_runtime_suspend(struct device *dev)
601 {
602 	struct dcmipp_device *dcmipp = dev_get_drvdata(dev);
603 
604 	clk_disable_unprepare(dcmipp->kclk);
605 	clk_disable_unprepare(dcmipp->mclk);
606 
607 	return 0;
608 }
609 
dcmipp_runtime_resume(struct device * dev)610 static int dcmipp_runtime_resume(struct device *dev)
611 {
612 	struct dcmipp_device *dcmipp = dev_get_drvdata(dev);
613 	int ret;
614 
615 	ret = clk_prepare_enable(dcmipp->mclk);
616 	if (ret) {
617 		dev_err(dev, "%s: Failed to prepare_enable mclk\n", __func__);
618 		return ret;
619 	}
620 
621 	ret = clk_prepare_enable(dcmipp->kclk);
622 	if (ret) {
623 		clk_disable_unprepare(dcmipp->mclk);
624 		dev_err(dev, "%s: Failed to prepare_enable kclk\n", __func__);
625 	}
626 
627 	return ret;
628 }
629 
dcmipp_suspend(struct device * dev)630 static int dcmipp_suspend(struct device *dev)
631 {
632 	/* disable clock */
633 	pm_runtime_force_suspend(dev);
634 
635 	/* change pinctrl state */
636 	pinctrl_pm_select_sleep_state(dev);
637 
638 	return 0;
639 }
640 
dcmipp_resume(struct device * dev)641 static int dcmipp_resume(struct device *dev)
642 {
643 	/* restore pinctl default state */
644 	pinctrl_pm_select_default_state(dev);
645 
646 	/* clock enable */
647 	pm_runtime_force_resume(dev);
648 
649 	return 0;
650 }
651 
652 static const struct dev_pm_ops dcmipp_pm_ops = {
653 	SYSTEM_SLEEP_PM_OPS(dcmipp_suspend, dcmipp_resume)
654 	RUNTIME_PM_OPS(dcmipp_runtime_suspend, dcmipp_runtime_resume, NULL)
655 };
656 
657 static struct platform_driver dcmipp_pdrv = {
658 	.probe		= dcmipp_probe,
659 	.remove		= dcmipp_remove,
660 	.driver		= {
661 		.name	= DCMIPP_PDEV_NAME,
662 		.of_match_table = dcmipp_of_match,
663 		.pm = pm_ptr(&dcmipp_pm_ops),
664 	},
665 };
666 
667 module_platform_driver(dcmipp_pdrv);
668 
669 MODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@foss.st.com>");
670 MODULE_AUTHOR("Alain Volmat <alain.volmat@foss.st.com>");
671 MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface with Pixel Processor driver");
672 MODULE_LICENSE("GPL");
673