Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] atmel-isi: add runtime pm support

The runtime pm resume/suspend will enable/disable pclk (ISI peripheral
clock).

We have to call runtime_pm_get_sync()/runtime_pm_put() when we need to
access ISI registers. In atmel_isi_probe(), remove the isi disable code
as at that moment ISI peripheral clock is not enable yet.

Besides, clock_start()/clock_stop() is used to control the mclk, not
the ISI peripheral clock. So move this to start[stop]_streaming()
function.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Josh Wu and committed by
Mauro Carvalho Chehab
f3745a3a 8c037835

+47 -8
+47 -8
drivers/media/platform/soc_camera/atmel-isi.c
··· 20 20 #include <linux/kernel.h> 21 21 #include <linux/module.h> 22 22 #include <linux/platform_device.h> 23 + #include <linux/pm_runtime.h> 23 24 #include <linux/slab.h> 24 25 25 26 #include <media/atmel-isi.h> ··· 387 386 struct atmel_isi *isi = ici->priv; 388 387 int ret; 389 388 389 + pm_runtime_get_sync(ici->v4l2_dev.dev); 390 + 390 391 /* Reset ISI */ 391 392 ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); 392 393 if (ret < 0) { 393 394 dev_err(icd->parent, "Reset ISI timed out\n"); 395 + pm_runtime_put(ici->v4l2_dev.dev); 394 396 return ret; 395 397 } 396 398 /* Disable all interrupts */ ··· 447 443 ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); 448 444 if (ret < 0) 449 445 dev_err(icd->parent, "Disable ISI timed out\n"); 446 + 447 + pm_runtime_put(ici->v4l2_dev.dev); 450 448 } 451 449 452 450 static struct vb2_ops isi_video_qops = { ··· 520 514 if (mf->code != xlate->code) 521 515 return -EINVAL; 522 516 517 + /* Enable PM and peripheral clock before operate isi registers */ 518 + pm_runtime_get_sync(ici->v4l2_dev.dev); 519 + 523 520 ret = configure_geometry(isi, pix->width, pix->height, xlate->code); 521 + 522 + pm_runtime_put(ici->v4l2_dev.dev); 523 + 524 524 if (ret < 0) 525 525 return ret; 526 526 ··· 746 734 struct atmel_isi *isi = ici->priv; 747 735 int ret; 748 736 749 - ret = clk_prepare_enable(isi->pclk); 750 - if (ret) 751 - return ret; 752 - 753 737 if (!IS_ERR(isi->mck)) { 754 738 ret = clk_prepare_enable(isi->mck); 755 739 if (ret) { 756 - clk_disable_unprepare(isi->pclk); 757 740 return ret; 758 741 } 759 742 } ··· 763 756 764 757 if (!IS_ERR(isi->mck)) 765 758 clk_disable_unprepare(isi->mck); 766 - clk_disable_unprepare(isi->pclk); 767 759 } 768 760 769 761 static unsigned int isi_camera_poll(struct file *file, poll_table *pt) ··· 859 853 860 854 cfg1 |= ISI_CFG1_THMASK_BEATS_16; 861 855 856 + /* Enable PM and peripheral clock before operate isi registers */ 857 + pm_runtime_get_sync(ici->v4l2_dev.dev); 858 + 862 859 isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); 863 860 isi_writel(isi, ISI_CFG1, cfg1); 861 + 862 + pm_runtime_put(ici->v4l2_dev.dev); 864 863 865 864 return 0; 866 865 } ··· 898 887 sizeof(struct fbd) * MAX_BUFFER_NUM, 899 888 isi->p_fb_descriptors, 900 889 isi->fb_descriptors_phys); 890 + pm_runtime_disable(&pdev->dev); 901 891 902 892 return 0; 903 893 } ··· 1037 1025 if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) 1038 1026 isi->width_flags |= 1 << 9; 1039 1027 1040 - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); 1041 - 1042 1028 irq = platform_get_irq(pdev, 0); 1043 1029 if (IS_ERR_VALUE(irq)) { 1044 1030 ret = irq; ··· 1057 1047 soc_host->v4l2_dev.dev = &pdev->dev; 1058 1048 soc_host->nr = pdev->id; 1059 1049 1050 + pm_suspend_ignore_children(&pdev->dev, true); 1051 + pm_runtime_enable(&pdev->dev); 1052 + 1060 1053 if (isi->pdata.asd_sizes) { 1061 1054 soc_host->asd = isi->pdata.asd; 1062 1055 soc_host->asd_sizes = isi->pdata.asd_sizes; ··· 1073 1060 return 0; 1074 1061 1075 1062 err_register_soc_camera_host: 1063 + pm_runtime_disable(&pdev->dev); 1076 1064 err_req_irq: 1077 1065 err_ioremap: 1078 1066 vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); ··· 1086 1072 return ret; 1087 1073 } 1088 1074 1075 + static int atmel_isi_runtime_suspend(struct device *dev) 1076 + { 1077 + struct soc_camera_host *soc_host = to_soc_camera_host(dev); 1078 + struct atmel_isi *isi = container_of(soc_host, 1079 + struct atmel_isi, soc_host); 1080 + 1081 + clk_disable_unprepare(isi->pclk); 1082 + 1083 + return 0; 1084 + } 1085 + static int atmel_isi_runtime_resume(struct device *dev) 1086 + { 1087 + struct soc_camera_host *soc_host = to_soc_camera_host(dev); 1088 + struct atmel_isi *isi = container_of(soc_host, 1089 + struct atmel_isi, soc_host); 1090 + 1091 + return clk_prepare_enable(isi->pclk); 1092 + } 1093 + 1094 + static const struct dev_pm_ops atmel_isi_dev_pm_ops = { 1095 + SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, 1096 + atmel_isi_runtime_resume, NULL) 1097 + }; 1098 + 1089 1099 static const struct of_device_id atmel_isi_of_match[] = { 1090 1100 { .compatible = "atmel,at91sam9g45-isi" }, 1091 1101 { } ··· 1121 1083 .driver = { 1122 1084 .name = "atmel_isi", 1123 1085 .of_match_table = of_match_ptr(atmel_isi_of_match), 1086 + .pm = &atmel_isi_dev_pm_ops, 1124 1087 }, 1125 1088 }; 1126 1089