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