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