Merge remote-tracking branches 'asoc/topic/mediatek', 'asoc/topic/mtk', 'asoc/topic...
[pandora-kernel.git] / sound / soc / mediatek / mtk-afe-pcm.c
index cc228db..d190fe0 100644 (file)
 /* Memory interface */
 #define AFE_DL1_BASE           0x0040
 #define AFE_DL1_CUR            0x0044
+#define AFE_DL1_END            0x0048
 #define AFE_DL2_BASE           0x0050
 #define AFE_DL2_CUR            0x0054
 #define AFE_AWB_BASE           0x0070
 #define AFE_AWB_CUR            0x007c
 #define AFE_VUL_BASE           0x0080
 #define AFE_VUL_CUR            0x008c
+#define AFE_VUL_END            0x0088
 #define AFE_DAI_BASE           0x0090
 #define AFE_DAI_CUR            0x009c
 #define AFE_MOD_PCM_BASE       0x0330
 #define AFE_MOD_PCM_CUR                0x033c
 #define AFE_HDMI_OUT_BASE      0x0374
 #define AFE_HDMI_OUT_CUR       0x0378
+#define AFE_HDMI_OUT_END       0x037c
 
 #define AFE_ADDA2_TOP_CON0     0x0600
 
@@ -127,6 +130,34 @@ enum afe_tdm_ch_start {
        AFE_TDM_CH_ZERO,
 };
 
+static const unsigned int mtk_afe_backup_list[] = {
+       AUDIO_TOP_CON0,
+       AFE_CONN1,
+       AFE_CONN2,
+       AFE_CONN7,
+       AFE_CONN8,
+       AFE_DAC_CON1,
+       AFE_DL1_BASE,
+       AFE_DL1_END,
+       AFE_VUL_BASE,
+       AFE_VUL_END,
+       AFE_HDMI_OUT_BASE,
+       AFE_HDMI_OUT_END,
+       AFE_HDMI_CONN0,
+       AFE_DAC_CON0,
+};
+
+struct mtk_afe {
+       /* address for ioremap audio hardware register */
+       void __iomem *base_addr;
+       struct device *dev;
+       struct regmap *regmap;
+       struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM];
+       struct clk *clocks[MTK_CLK_NUM];
+       unsigned int backup_regs[ARRAY_SIZE(mtk_afe_backup_list)];
+       bool suspended;
+};
+
 static const struct snd_pcm_hardware mtk_afe_hardware = {
        .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                 SNDRV_PCM_INFO_MMAP_VALID),
@@ -722,11 +753,53 @@ static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = {
 
 };
 
+static int mtk_afe_runtime_suspend(struct device *dev);
+static int mtk_afe_runtime_resume(struct device *dev);
+
+static int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
+{
+       struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
+       int i;
+
+       dev_dbg(afe->dev, "%s\n", __func__);
+       if (pm_runtime_status_suspended(afe->dev) || afe->suspended)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++)
+               regmap_read(afe->regmap, mtk_afe_backup_list[i],
+                           &afe->backup_regs[i]);
+
+       afe->suspended = true;
+       mtk_afe_runtime_suspend(afe->dev);
+       return 0;
+}
+
+static int mtk_afe_dai_resume(struct snd_soc_dai *dai)
+{
+       struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
+       int i = 0;
+
+       dev_dbg(afe->dev, "%s\n", __func__);
+       if (pm_runtime_status_suspended(afe->dev) || !afe->suspended)
+               return 0;
+
+       mtk_afe_runtime_resume(afe->dev);
+
+       for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++)
+               regmap_write(afe->regmap, mtk_afe_backup_list[i],
+                            afe->backup_regs[i]);
+
+       afe->suspended = false;
+       return 0;
+}
+
 static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = {
        /* FE DAIs: memory intefaces to CPU */
        {
                .name = "DL1", /* downlink 1 */
                .id = MTK_AFE_MEMIF_DL1,
+               .suspend = mtk_afe_dai_suspend,
+               .resume = mtk_afe_dai_resume,
                .playback = {
                        .stream_name = "DL1",
                        .channels_min = 1,
@@ -738,6 +811,8 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = {
        }, {
                .name = "VUL", /* voice uplink */
                .id = MTK_AFE_MEMIF_VUL,
+               .suspend = mtk_afe_dai_suspend,
+               .resume = mtk_afe_dai_resume,
                .capture = {
                        .stream_name = "VUL",
                        .channels_min = 1,
@@ -774,6 +849,8 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = {
        {
                .name = "HDMI",
                .id = MTK_AFE_MEMIF_HDMI,
+               .suspend = mtk_afe_dai_suspend,
+               .resume = mtk_afe_dai_resume,
                .playback = {
                        .stream_name = "HDMI",
                        .channels_min = 2,
@@ -820,10 +897,6 @@ static const struct snd_kcontrol_new mtk_afe_o10_mix[] = {
 };
 
 static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = {
-       /* Backend DAIs  */
-       SND_SOC_DAPM_AIF_IN("I2S Capture", NULL, 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("I2S Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
-
        /* inter-connections */
        SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -855,11 +928,6 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = {
        { "O10", "I18 Switch", "I18" },
 };
 
-static const struct snd_soc_dapm_widget mtk_afe_hdmi_widgets[] = {
-       /* Backend DAIs  */
-       SND_SOC_DAPM_AIF_OUT("HDMIO Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
-};
-
 static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = {
        {"HDMIO Playback", NULL, "HDMI"},
 };
@@ -874,8 +942,6 @@ static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = {
 
 static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = {
        .name = "mtk-afe-hdmi-dai",
-       .dapm_widgets = mtk_afe_hdmi_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(mtk_afe_hdmi_widgets),
        .dapm_routes = mtk_afe_hdmi_routes,
        .num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes),
 };
@@ -1199,6 +1265,8 @@ err_pm_disable:
 static int mtk_afe_pcm_dev_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               mtk_afe_runtime_suspend(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
        return 0;
@@ -1218,7 +1286,6 @@ static const struct dev_pm_ops mtk_afe_pm_ops = {
 static struct platform_driver mtk_afe_pcm_driver = {
        .driver = {
                   .name = "mtk-afe-pcm",
-                  .owner = THIS_MODULE,
                   .of_match_table = mtk_afe_pcm_dt_match,
                   .pm = &mtk_afe_pm_ops,
        },