diff options
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r-- | sound/soc/sh/fsi.c | 188 |
1 files changed, 155 insertions, 33 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 23c0e83d4c19..4a9da6b5f4e1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -86,8 +86,8 @@ | |||
86 | #define SE (1 << 0) /* Fix the master clock */ | 86 | #define SE (1 << 0) /* Fix the master clock */ |
87 | 87 | ||
88 | /* CLK_RST */ | 88 | /* CLK_RST */ |
89 | #define B_CLK 0x00000010 | 89 | #define CRB (1 << 4) |
90 | #define A_CLK 0x00000001 | 90 | #define CRA (1 << 0) |
91 | 91 | ||
92 | /* IO SHIFT / MACRO */ | 92 | /* IO SHIFT / MACRO */ |
93 | #define BI_SHIFT 12 | 93 | #define BI_SHIFT 12 |
@@ -146,11 +146,20 @@ struct fsi_priv { | |||
146 | void __iomem *base; | 146 | void __iomem *base; |
147 | struct fsi_master *master; | 147 | struct fsi_master *master; |
148 | 148 | ||
149 | int chan_num; | ||
150 | struct fsi_stream playback; | 149 | struct fsi_stream playback; |
151 | struct fsi_stream capture; | 150 | struct fsi_stream capture; |
152 | 151 | ||
152 | int chan_num:16; | ||
153 | int clk_master:1; | ||
154 | |||
153 | long rate; | 155 | long rate; |
156 | |||
157 | /* for suspend/resume */ | ||
158 | u32 saved_do_fmt; | ||
159 | u32 saved_di_fmt; | ||
160 | u32 saved_ckg1; | ||
161 | u32 saved_ckg2; | ||
162 | u32 saved_out_sel; | ||
154 | }; | 163 | }; |
155 | 164 | ||
156 | struct fsi_core { | 165 | struct fsi_core { |
@@ -171,6 +180,14 @@ struct fsi_master { | |||
171 | struct fsi_core *core; | 180 | struct fsi_core *core; |
172 | struct sh_fsi_platform_info *info; | 181 | struct sh_fsi_platform_info *info; |
173 | spinlock_t lock; | 182 | spinlock_t lock; |
183 | |||
184 | /* for suspend/resume */ | ||
185 | u32 saved_a_mclk; | ||
186 | u32 saved_b_mclk; | ||
187 | u32 saved_iemsk; | ||
188 | u32 saved_imsk; | ||
189 | u32 saved_clk_rst; | ||
190 | u32 saved_soft_rst; | ||
174 | }; | 191 | }; |
175 | 192 | ||
176 | /* | 193 | /* |
@@ -244,6 +261,11 @@ static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) | |||
244 | return fsi->master; | 261 | return fsi->master; |
245 | } | 262 | } |
246 | 263 | ||
264 | static int fsi_is_clk_master(struct fsi_priv *fsi) | ||
265 | { | ||
266 | return fsi->clk_master; | ||
267 | } | ||
268 | |||
247 | static int fsi_is_port_a(struct fsi_priv *fsi) | 269 | static int fsi_is_port_a(struct fsi_priv *fsi) |
248 | { | 270 | { |
249 | return fsi->master->base == fsi->base; | 271 | return fsi->master->base == fsi->base; |
@@ -535,20 +557,45 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
535 | } | 557 | } |
536 | 558 | ||
537 | /* | 559 | /* |
538 | * ctrl function | 560 | * clock function |
539 | */ | 561 | */ |
562 | #define fsi_module_init(m, d) __fsi_module_clk_ctrl(m, d, 1) | ||
563 | #define fsi_module_kill(m, d) __fsi_module_clk_ctrl(m, d, 0) | ||
564 | static void __fsi_module_clk_ctrl(struct fsi_master *master, | ||
565 | struct device *dev, | ||
566 | int enable) | ||
567 | { | ||
568 | pm_runtime_get_sync(dev); | ||
569 | |||
570 | if (enable) { | ||
571 | /* enable only SR */ | ||
572 | fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); | ||
573 | fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); | ||
574 | } else { | ||
575 | /* clear all registers */ | ||
576 | fsi_master_mask_set(master, SOFT_RST, FSISR, 0); | ||
577 | } | ||
540 | 578 | ||
541 | static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) | 579 | pm_runtime_put_sync(dev); |
580 | } | ||
581 | |||
582 | #define fsi_port_start(f) __fsi_port_clk_ctrl(f, 1) | ||
583 | #define fsi_port_stop(f) __fsi_port_clk_ctrl(f, 0) | ||
584 | static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable) | ||
542 | { | 585 | { |
543 | u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); | ||
544 | struct fsi_master *master = fsi_get_master(fsi); | 586 | struct fsi_master *master = fsi_get_master(fsi); |
587 | u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR; | ||
588 | u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; | ||
589 | int is_master = fsi_is_clk_master(fsi); | ||
545 | 590 | ||
546 | if (enable) | 591 | fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0); |
547 | fsi_master_mask_set(master, CLK_RST, val, val); | 592 | if (is_master) |
548 | else | 593 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); |
549 | fsi_master_mask_set(master, CLK_RST, val, 0); | ||
550 | } | 594 | } |
551 | 595 | ||
596 | /* | ||
597 | * ctrl function | ||
598 | */ | ||
552 | static void fsi_fifo_init(struct fsi_priv *fsi, | 599 | static void fsi_fifo_init(struct fsi_priv *fsi, |
553 | int is_play, | 600 | int is_play, |
554 | struct snd_soc_dai *dai) | 601 | struct snd_soc_dai *dai) |
@@ -601,18 +648,6 @@ static void fsi_fifo_init(struct fsi_priv *fsi, | |||
601 | } | 648 | } |
602 | } | 649 | } |
603 | 650 | ||
604 | static void fsi_soft_all_reset(struct fsi_master *master) | ||
605 | { | ||
606 | /* port AB reset */ | ||
607 | fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); | ||
608 | mdelay(10); | ||
609 | |||
610 | /* soft reset */ | ||
611 | fsi_master_mask_set(master, SOFT_RST, FSISR, 0); | ||
612 | fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); | ||
613 | mdelay(10); | ||
614 | } | ||
615 | |||
616 | static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | 651 | static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) |
617 | { | 652 | { |
618 | struct snd_pcm_runtime *runtime; | 653 | struct snd_pcm_runtime *runtime; |
@@ -793,14 +828,13 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
793 | struct fsi_priv *fsi = fsi_get_priv(substream); | 828 | struct fsi_priv *fsi = fsi_get_priv(substream); |
794 | int is_play = fsi_is_play(substream); | 829 | int is_play = fsi_is_play(substream); |
795 | struct fsi_master *master = fsi_get_master(fsi); | 830 | struct fsi_master *master = fsi_get_master(fsi); |
796 | set_rate_func set_rate; | 831 | set_rate_func set_rate = fsi_get_info_set_rate(master); |
797 | 832 | ||
798 | fsi_irq_disable(fsi, is_play); | 833 | fsi_irq_disable(fsi, is_play); |
799 | fsi_clk_ctrl(fsi, 0); | ||
800 | 834 | ||
801 | set_rate = fsi_get_info_set_rate(master); | 835 | if (fsi_is_clk_master(fsi)) |
802 | if (set_rate && fsi->rate) | ||
803 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); | 836 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); |
837 | |||
804 | fsi->rate = 0; | 838 | fsi->rate = 0; |
805 | 839 | ||
806 | pm_runtime_put_sync(dai->dev); | 840 | pm_runtime_put_sync(dai->dev); |
@@ -821,8 +855,10 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
821 | frames_to_bytes(runtime, runtime->period_size)); | 855 | frames_to_bytes(runtime, runtime->period_size)); |
822 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); | 856 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); |
823 | fsi_irq_enable(fsi, is_play); | 857 | fsi_irq_enable(fsi, is_play); |
858 | fsi_port_start(fsi); | ||
824 | break; | 859 | break; |
825 | case SNDRV_PCM_TRIGGER_STOP: | 860 | case SNDRV_PCM_TRIGGER_STOP: |
861 | fsi_port_stop(fsi); | ||
826 | fsi_irq_disable(fsi, is_play); | 862 | fsi_irq_disable(fsi, is_play); |
827 | fsi_stream_pop(fsi, is_play); | 863 | fsi_stream_pop(fsi, is_play); |
828 | break; | 864 | break; |
@@ -876,6 +912,8 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) | |||
876 | static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 912 | static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
877 | { | 913 | { |
878 | struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); | 914 | struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); |
915 | struct fsi_master *master = fsi_get_master(fsi); | ||
916 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
879 | u32 flags = fsi_get_info_flags(fsi); | 917 | u32 flags = fsi_get_info_flags(fsi); |
880 | u32 data = 0; | 918 | u32 data = 0; |
881 | int ret; | 919 | int ret; |
@@ -886,6 +924,7 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
886 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 924 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
887 | case SND_SOC_DAIFMT_CBM_CFM: | 925 | case SND_SOC_DAIFMT_CBM_CFM: |
888 | data = DIMD | DOMD; | 926 | data = DIMD | DOMD; |
927 | fsi->clk_master = 1; | ||
889 | break; | 928 | break; |
890 | case SND_SOC_DAIFMT_CBS_CFS: | 929 | case SND_SOC_DAIFMT_CBS_CFS: |
891 | break; | 930 | break; |
@@ -893,6 +932,13 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
893 | ret = -EINVAL; | 932 | ret = -EINVAL; |
894 | goto set_fmt_exit; | 933 | goto set_fmt_exit; |
895 | } | 934 | } |
935 | |||
936 | if (fsi_is_clk_master(fsi) && !set_rate) { | ||
937 | dev_err(dai->dev, "platform doesn't have set_rate\n"); | ||
938 | ret = -EINVAL; | ||
939 | goto set_fmt_exit; | ||
940 | } | ||
941 | |||
896 | fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); | 942 | fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); |
897 | 943 | ||
898 | /* set format */ | 944 | /* set format */ |
@@ -919,13 +965,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | |||
919 | { | 965 | { |
920 | struct fsi_priv *fsi = fsi_get_priv(substream); | 966 | struct fsi_priv *fsi = fsi_get_priv(substream); |
921 | struct fsi_master *master = fsi_get_master(fsi); | 967 | struct fsi_master *master = fsi_get_master(fsi); |
922 | set_rate_func set_rate; | 968 | set_rate_func set_rate = fsi_get_info_set_rate(master); |
923 | int fsi_ver = master->core->ver; | 969 | int fsi_ver = master->core->ver; |
924 | long rate = params_rate(params); | 970 | long rate = params_rate(params); |
925 | int ret; | 971 | int ret; |
926 | 972 | ||
927 | set_rate = fsi_get_info_set_rate(master); | 973 | if (!fsi_is_clk_master(fsi)) |
928 | if (!set_rate) | ||
929 | return 0; | 974 | return 0; |
930 | 975 | ||
931 | ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); | 976 | ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); |
@@ -987,7 +1032,6 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | |||
987 | 1032 | ||
988 | fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); | 1033 | fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); |
989 | udelay(10); | 1034 | udelay(10); |
990 | fsi_clk_ctrl(fsi, 1); | ||
991 | ret = 0; | 1035 | ret = 0; |
992 | } | 1036 | } |
993 | 1037 | ||
@@ -1202,9 +1246,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
1202 | pm_runtime_enable(&pdev->dev); | 1246 | pm_runtime_enable(&pdev->dev); |
1203 | dev_set_drvdata(&pdev->dev, master); | 1247 | dev_set_drvdata(&pdev->dev, master); |
1204 | 1248 | ||
1205 | pm_runtime_get_sync(&pdev->dev); | 1249 | fsi_module_init(master, &pdev->dev); |
1206 | fsi_soft_all_reset(master); | ||
1207 | pm_runtime_put_sync(&pdev->dev); | ||
1208 | 1250 | ||
1209 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, | 1251 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, |
1210 | id_entry->name, master); | 1252 | id_entry->name, master); |
@@ -1248,6 +1290,8 @@ static int fsi_remove(struct platform_device *pdev) | |||
1248 | 1290 | ||
1249 | master = dev_get_drvdata(&pdev->dev); | 1291 | master = dev_get_drvdata(&pdev->dev); |
1250 | 1292 | ||
1293 | fsi_module_kill(master, &pdev->dev); | ||
1294 | |||
1251 | free_irq(master->irq, master); | 1295 | free_irq(master->irq, master); |
1252 | pm_runtime_disable(&pdev->dev); | 1296 | pm_runtime_disable(&pdev->dev); |
1253 | 1297 | ||
@@ -1260,6 +1304,82 @@ static int fsi_remove(struct platform_device *pdev) | |||
1260 | return 0; | 1304 | return 0; |
1261 | } | 1305 | } |
1262 | 1306 | ||
1307 | static void __fsi_suspend(struct fsi_priv *fsi, | ||
1308 | struct device *dev, | ||
1309 | set_rate_func set_rate) | ||
1310 | { | ||
1311 | fsi->saved_do_fmt = fsi_reg_read(fsi, DO_FMT); | ||
1312 | fsi->saved_di_fmt = fsi_reg_read(fsi, DI_FMT); | ||
1313 | fsi->saved_ckg1 = fsi_reg_read(fsi, CKG1); | ||
1314 | fsi->saved_ckg2 = fsi_reg_read(fsi, CKG2); | ||
1315 | fsi->saved_out_sel = fsi_reg_read(fsi, OUT_SEL); | ||
1316 | |||
1317 | if (fsi_is_clk_master(fsi)) | ||
1318 | set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0); | ||
1319 | } | ||
1320 | |||
1321 | static void __fsi_resume(struct fsi_priv *fsi, | ||
1322 | struct device *dev, | ||
1323 | set_rate_func set_rate) | ||
1324 | { | ||
1325 | fsi_reg_write(fsi, DO_FMT, fsi->saved_do_fmt); | ||
1326 | fsi_reg_write(fsi, DI_FMT, fsi->saved_di_fmt); | ||
1327 | fsi_reg_write(fsi, CKG1, fsi->saved_ckg1); | ||
1328 | fsi_reg_write(fsi, CKG2, fsi->saved_ckg2); | ||
1329 | fsi_reg_write(fsi, OUT_SEL, fsi->saved_out_sel); | ||
1330 | |||
1331 | if (fsi_is_clk_master(fsi)) | ||
1332 | set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1); | ||
1333 | } | ||
1334 | |||
1335 | static int fsi_suspend(struct device *dev) | ||
1336 | { | ||
1337 | struct fsi_master *master = dev_get_drvdata(dev); | ||
1338 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
1339 | |||
1340 | pm_runtime_get_sync(dev); | ||
1341 | |||
1342 | __fsi_suspend(&master->fsia, dev, set_rate); | ||
1343 | __fsi_suspend(&master->fsib, dev, set_rate); | ||
1344 | |||
1345 | master->saved_a_mclk = fsi_core_read(master, a_mclk); | ||
1346 | master->saved_b_mclk = fsi_core_read(master, b_mclk); | ||
1347 | master->saved_iemsk = fsi_core_read(master, iemsk); | ||
1348 | master->saved_imsk = fsi_core_read(master, imsk); | ||
1349 | master->saved_clk_rst = fsi_master_read(master, CLK_RST); | ||
1350 | master->saved_soft_rst = fsi_master_read(master, SOFT_RST); | ||
1351 | |||
1352 | fsi_module_kill(master, dev); | ||
1353 | |||
1354 | pm_runtime_put_sync(dev); | ||
1355 | |||
1356 | return 0; | ||
1357 | } | ||
1358 | |||
1359 | static int fsi_resume(struct device *dev) | ||
1360 | { | ||
1361 | struct fsi_master *master = dev_get_drvdata(dev); | ||
1362 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
1363 | |||
1364 | pm_runtime_get_sync(dev); | ||
1365 | |||
1366 | fsi_module_init(master, dev); | ||
1367 | |||
1368 | fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst); | ||
1369 | fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst); | ||
1370 | fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk); | ||
1371 | fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk); | ||
1372 | fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk); | ||
1373 | fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk); | ||
1374 | |||
1375 | __fsi_resume(&master->fsia, dev, set_rate); | ||
1376 | __fsi_resume(&master->fsib, dev, set_rate); | ||
1377 | |||
1378 | pm_runtime_put_sync(dev); | ||
1379 | |||
1380 | return 0; | ||
1381 | } | ||
1382 | |||
1263 | static int fsi_runtime_nop(struct device *dev) | 1383 | static int fsi_runtime_nop(struct device *dev) |
1264 | { | 1384 | { |
1265 | /* Runtime PM callback shared between ->runtime_suspend() | 1385 | /* Runtime PM callback shared between ->runtime_suspend() |
@@ -1273,6 +1393,8 @@ static int fsi_runtime_nop(struct device *dev) | |||
1273 | } | 1393 | } |
1274 | 1394 | ||
1275 | static struct dev_pm_ops fsi_pm_ops = { | 1395 | static struct dev_pm_ops fsi_pm_ops = { |
1396 | .suspend = fsi_suspend, | ||
1397 | .resume = fsi_resume, | ||
1276 | .runtime_suspend = fsi_runtime_nop, | 1398 | .runtime_suspend = fsi_runtime_nop, |
1277 | .runtime_resume = fsi_runtime_nop, | 1399 | .runtime_resume = fsi_runtime_nop, |
1278 | }; | 1400 | }; |