diff options
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r-- | sound/soc/sh/fsi.c | 203 |
1 files changed, 114 insertions, 89 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 2b06402801ef..0c9997e2d8c0 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -78,6 +78,8 @@ | |||
78 | /* CKG1 */ | 78 | /* CKG1 */ |
79 | #define ACKMD_MASK 0x00007000 | 79 | #define ACKMD_MASK 0x00007000 |
80 | #define BPFMD_MASK 0x00000700 | 80 | #define BPFMD_MASK 0x00000700 |
81 | #define DIMD (1 << 4) | ||
82 | #define DOMD (1 << 0) | ||
81 | 83 | ||
82 | /* A/B MST_CTLR */ | 84 | /* A/B MST_CTLR */ |
83 | #define BP (1 << 4) /* Fix the signal of Biphase output */ | 85 | #define BP (1 << 4) /* Fix the signal of Biphase output */ |
@@ -111,6 +113,8 @@ | |||
111 | 113 | ||
112 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | 114 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
113 | 115 | ||
116 | typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable); | ||
117 | |||
114 | /* | 118 | /* |
115 | * FSI driver use below type name for variable | 119 | * FSI driver use below type name for variable |
116 | * | 120 | * |
@@ -128,7 +132,6 @@ struct fsi_stream { | |||
128 | struct snd_pcm_substream *substream; | 132 | struct snd_pcm_substream *substream; |
129 | 133 | ||
130 | int fifo_max_num; | 134 | int fifo_max_num; |
131 | int chan_num; | ||
132 | 135 | ||
133 | int buff_offset; | 136 | int buff_offset; |
134 | int buff_len; | 137 | int buff_len; |
@@ -143,6 +146,7 @@ struct fsi_priv { | |||
143 | void __iomem *base; | 146 | void __iomem *base; |
144 | struct fsi_master *master; | 147 | struct fsi_master *master; |
145 | 148 | ||
149 | int chan_num; | ||
146 | struct fsi_stream playback; | 150 | struct fsi_stream playback; |
147 | struct fsi_stream capture; | 151 | struct fsi_stream capture; |
148 | 152 | ||
@@ -252,9 +256,8 @@ static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) | |||
252 | return rtd->cpu_dai; | 256 | return rtd->cpu_dai; |
253 | } | 257 | } |
254 | 258 | ||
255 | static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | 259 | static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai) |
256 | { | 260 | { |
257 | struct snd_soc_dai *dai = fsi_get_dai(substream); | ||
258 | struct fsi_master *master = snd_soc_dai_get_drvdata(dai); | 261 | struct fsi_master *master = snd_soc_dai_get_drvdata(dai); |
259 | 262 | ||
260 | if (dai->id == 0) | 263 | if (dai->id == 0) |
@@ -263,11 +266,27 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | |||
263 | return &master->fsib; | 266 | return &master->fsib; |
264 | } | 267 | } |
265 | 268 | ||
269 | static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | ||
270 | { | ||
271 | return fsi_get_priv_frm_dai(fsi_get_dai(substream)); | ||
272 | } | ||
273 | |||
274 | static set_rate_func fsi_get_info_set_rate(struct fsi_master *master) | ||
275 | { | ||
276 | if (!master->info) | ||
277 | return NULL; | ||
278 | |||
279 | return master->info->set_rate; | ||
280 | } | ||
281 | |||
266 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) | 282 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) |
267 | { | 283 | { |
268 | int is_porta = fsi_is_port_a(fsi); | 284 | int is_porta = fsi_is_port_a(fsi); |
269 | struct fsi_master *master = fsi_get_master(fsi); | 285 | struct fsi_master *master = fsi_get_master(fsi); |
270 | 286 | ||
287 | if (!master->info) | ||
288 | return 0; | ||
289 | |||
271 | return is_porta ? master->info->porta_flags : | 290 | return is_porta ? master->info->porta_flags : |
272 | master->info->portb_flags; | 291 | master->info->portb_flags; |
273 | } | 292 | } |
@@ -288,21 +307,6 @@ static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi, | |||
288 | return is_play ? &fsi->playback : &fsi->capture; | 307 | return is_play ? &fsi->playback : &fsi->capture; |
289 | } | 308 | } |
290 | 309 | ||
291 | static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play) | ||
292 | { | ||
293 | u32 mode; | ||
294 | u32 flags = fsi_get_info_flags(fsi); | ||
295 | |||
296 | mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE; | ||
297 | |||
298 | /* return | ||
299 | * 1 : master mode | ||
300 | * 0 : slave mode | ||
301 | */ | ||
302 | |||
303 | return (mode & flags) != mode; | ||
304 | } | ||
305 | |||
306 | static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) | 310 | static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) |
307 | { | 311 | { |
308 | int is_porta = fsi_is_port_a(fsi); | 312 | int is_porta = fsi_is_port_a(fsi); |
@@ -357,7 +361,6 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | |||
357 | static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) | 361 | static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) |
358 | { | 362 | { |
359 | u32 status; | 363 | u32 status; |
360 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
361 | int data_num; | 364 | int data_num; |
362 | 365 | ||
363 | status = is_play ? | 366 | status = is_play ? |
@@ -365,7 +368,7 @@ static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) | |||
365 | fsi_reg_read(fsi, DIFF_ST); | 368 | fsi_reg_read(fsi, DIFF_ST); |
366 | 369 | ||
367 | data_num = 0x1ff & (status >> 8); | 370 | data_num = 0x1ff & (status >> 8); |
368 | data_num *= io->chan_num; | 371 | data_num *= fsi->chan_num; |
369 | 372 | ||
370 | return data_num; | 373 | return data_num; |
371 | } | 374 | } |
@@ -387,7 +390,7 @@ static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play) | |||
387 | struct snd_pcm_substream *substream = io->substream; | 390 | struct snd_pcm_substream *substream = io->substream; |
388 | struct snd_pcm_runtime *runtime = substream->runtime; | 391 | struct snd_pcm_runtime *runtime = substream->runtime; |
389 | 392 | ||
390 | return frames_to_bytes(runtime, 1) / io->chan_num; | 393 | return frames_to_bytes(runtime, 1) / fsi->chan_num; |
391 | } | 394 | } |
392 | 395 | ||
393 | static void fsi_count_fifo_err(struct fsi_priv *fsi) | 396 | static void fsi_count_fifo_err(struct fsi_priv *fsi) |
@@ -580,10 +583,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi, | |||
580 | * 7 channels: 32 ( 32 x 7 = 224) | 583 | * 7 channels: 32 ( 32 x 7 = 224) |
581 | * 8 channels: 32 ( 32 x 8 = 256) | 584 | * 8 channels: 32 ( 32 x 8 = 256) |
582 | */ | 585 | */ |
583 | for (i = 1; i < io->chan_num; i <<= 1) | 586 | for (i = 1; i < fsi->chan_num; i <<= 1) |
584 | io->fifo_max_num >>= 1; | 587 | io->fifo_max_num >>= 1; |
585 | dev_dbg(dai->dev, "%d channel %d store\n", | 588 | dev_dbg(dai->dev, "%d channel %d store\n", |
586 | io->chan_num, io->fifo_max_num); | 589 | fsi->chan_num, io->fifo_max_num); |
587 | 590 | ||
588 | /* | 591 | /* |
589 | * set interrupt generation factor | 592 | * set interrupt generation factor |
@@ -659,7 +662,7 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
659 | * data_num_max : number of FSI fifo free space | 662 | * data_num_max : number of FSI fifo free space |
660 | * data_num : number of ALSA residue data | 663 | * data_num : number of ALSA residue data |
661 | */ | 664 | */ |
662 | data_num_max = io->fifo_max_num * io->chan_num; | 665 | data_num_max = io->fifo_max_num * fsi->chan_num; |
663 | data_num_max -= fsi_get_fifo_data_num(fsi, is_play); | 666 | data_num_max -= fsi_get_fifo_data_num(fsi, is_play); |
664 | 667 | ||
665 | data_num = data_residue_num; | 668 | data_num = data_residue_num; |
@@ -754,25 +757,12 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
754 | struct snd_soc_dai *dai) | 757 | struct snd_soc_dai *dai) |
755 | { | 758 | { |
756 | struct fsi_priv *fsi = fsi_get_priv(substream); | 759 | struct fsi_priv *fsi = fsi_get_priv(substream); |
757 | struct fsi_master *master = fsi_get_master(fsi); | ||
758 | struct fsi_stream *io; | ||
759 | u32 flags = fsi_get_info_flags(fsi); | 760 | u32 flags = fsi_get_info_flags(fsi); |
760 | u32 fmt; | ||
761 | u32 data; | 761 | u32 data; |
762 | int is_play = fsi_is_play(substream); | 762 | int is_play = fsi_is_play(substream); |
763 | int is_master; | ||
764 | |||
765 | io = fsi_get_stream(fsi, is_play); | ||
766 | 763 | ||
767 | pm_runtime_get_sync(dai->dev); | 764 | pm_runtime_get_sync(dai->dev); |
768 | 765 | ||
769 | /* CKG1 */ | ||
770 | data = is_play ? (1 << 0) : (1 << 4); | ||
771 | is_master = fsi_is_master_mode(fsi, is_play); | ||
772 | if (is_master) | ||
773 | fsi_reg_mask_set(fsi, CKG1, data, data); | ||
774 | else | ||
775 | fsi_reg_mask_set(fsi, CKG1, data, 0); | ||
776 | 766 | ||
777 | /* clock inversion (CKG2) */ | 767 | /* clock inversion (CKG2) */ |
778 | data = 0; | 768 | data = 0; |
@@ -787,54 +777,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
787 | 777 | ||
788 | fsi_reg_write(fsi, CKG2, data); | 778 | fsi_reg_write(fsi, CKG2, data); |
789 | 779 | ||
790 | /* do fmt, di fmt */ | ||
791 | data = 0; | ||
792 | fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); | ||
793 | switch (fmt) { | ||
794 | case SH_FSI_FMT_MONO: | ||
795 | data = CR_MONO; | ||
796 | io->chan_num = 1; | ||
797 | break; | ||
798 | case SH_FSI_FMT_MONO_DELAY: | ||
799 | data = CR_MONO_D; | ||
800 | io->chan_num = 1; | ||
801 | break; | ||
802 | case SH_FSI_FMT_PCM: | ||
803 | data = CR_PCM; | ||
804 | io->chan_num = 2; | ||
805 | break; | ||
806 | case SH_FSI_FMT_I2S: | ||
807 | data = CR_I2S; | ||
808 | io->chan_num = 2; | ||
809 | break; | ||
810 | case SH_FSI_FMT_TDM: | ||
811 | io->chan_num = is_play ? | ||
812 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | ||
813 | data = CR_TDM | (io->chan_num - 1); | ||
814 | break; | ||
815 | case SH_FSI_FMT_TDM_DELAY: | ||
816 | io->chan_num = is_play ? | ||
817 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | ||
818 | data = CR_TDM_D | (io->chan_num - 1); | ||
819 | break; | ||
820 | case SH_FSI_FMT_SPDIF: | ||
821 | if (master->core->ver < 2) { | ||
822 | dev_err(dai->dev, "This FSI can not use SPDIF\n"); | ||
823 | return -EINVAL; | ||
824 | } | ||
825 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; | ||
826 | io->chan_num = 2; | ||
827 | fsi_spdif_clk_ctrl(fsi, 1); | ||
828 | fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); | ||
829 | break; | ||
830 | default: | ||
831 | dev_err(dai->dev, "unknown format.\n"); | ||
832 | return -EINVAL; | ||
833 | } | ||
834 | is_play ? | ||
835 | fsi_reg_write(fsi, DO_FMT, data) : | ||
836 | fsi_reg_write(fsi, DI_FMT, data); | ||
837 | |||
838 | /* irq clear */ | 780 | /* irq clear */ |
839 | fsi_irq_disable(fsi, is_play); | 781 | fsi_irq_disable(fsi, is_play); |
840 | fsi_irq_clear_status(fsi); | 782 | fsi_irq_clear_status(fsi); |
@@ -851,12 +793,12 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
851 | struct fsi_priv *fsi = fsi_get_priv(substream); | 793 | struct fsi_priv *fsi = fsi_get_priv(substream); |
852 | int is_play = fsi_is_play(substream); | 794 | int is_play = fsi_is_play(substream); |
853 | struct fsi_master *master = fsi_get_master(fsi); | 795 | struct fsi_master *master = fsi_get_master(fsi); |
854 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); | 796 | set_rate_func set_rate; |
855 | 797 | ||
856 | fsi_irq_disable(fsi, is_play); | 798 | fsi_irq_disable(fsi, is_play); |
857 | fsi_clk_ctrl(fsi, 0); | 799 | fsi_clk_ctrl(fsi, 0); |
858 | 800 | ||
859 | set_rate = master->info->set_rate; | 801 | set_rate = fsi_get_info_set_rate(master); |
860 | if (set_rate && fsi->rate) | 802 | if (set_rate && fsi->rate) |
861 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); | 803 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); |
862 | fsi->rate = 0; | 804 | fsi->rate = 0; |
@@ -889,18 +831,100 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
889 | return ret; | 831 | return ret; |
890 | } | 832 | } |
891 | 833 | ||
834 | static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) | ||
835 | { | ||
836 | u32 data = 0; | ||
837 | |||
838 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
839 | case SND_SOC_DAIFMT_I2S: | ||
840 | data = CR_I2S; | ||
841 | fsi->chan_num = 2; | ||
842 | break; | ||
843 | case SND_SOC_DAIFMT_LEFT_J: | ||
844 | data = CR_PCM; | ||
845 | fsi->chan_num = 2; | ||
846 | break; | ||
847 | default: | ||
848 | return -EINVAL; | ||
849 | } | ||
850 | |||
851 | fsi_reg_write(fsi, DO_FMT, data); | ||
852 | fsi_reg_write(fsi, DI_FMT, data); | ||
853 | |||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static int fsi_set_fmt_spdif(struct fsi_priv *fsi) | ||
858 | { | ||
859 | struct fsi_master *master = fsi_get_master(fsi); | ||
860 | u32 data = 0; | ||
861 | |||
862 | if (master->core->ver < 2) | ||
863 | return -EINVAL; | ||
864 | |||
865 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; | ||
866 | fsi->chan_num = 2; | ||
867 | fsi_spdif_clk_ctrl(fsi, 1); | ||
868 | fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); | ||
869 | |||
870 | fsi_reg_write(fsi, DO_FMT, data); | ||
871 | fsi_reg_write(fsi, DI_FMT, data); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
877 | { | ||
878 | struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); | ||
879 | u32 flags = fsi_get_info_flags(fsi); | ||
880 | u32 data = 0; | ||
881 | int ret; | ||
882 | |||
883 | pm_runtime_get_sync(dai->dev); | ||
884 | |||
885 | /* set master/slave audio interface */ | ||
886 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
887 | case SND_SOC_DAIFMT_CBM_CFM: | ||
888 | data = DIMD | DOMD; | ||
889 | break; | ||
890 | case SND_SOC_DAIFMT_CBS_CFS: | ||
891 | break; | ||
892 | default: | ||
893 | ret = -EINVAL; | ||
894 | goto set_fmt_exit; | ||
895 | } | ||
896 | fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); | ||
897 | |||
898 | /* set format */ | ||
899 | switch (flags & SH_FSI_FMT_MASK) { | ||
900 | case SH_FSI_FMT_DAI: | ||
901 | ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); | ||
902 | break; | ||
903 | case SH_FSI_FMT_SPDIF: | ||
904 | ret = fsi_set_fmt_spdif(fsi); | ||
905 | break; | ||
906 | default: | ||
907 | ret = -EINVAL; | ||
908 | } | ||
909 | |||
910 | set_fmt_exit: | ||
911 | pm_runtime_put_sync(dai->dev); | ||
912 | |||
913 | return ret; | ||
914 | } | ||
915 | |||
892 | static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | 916 | static int fsi_dai_hw_params(struct snd_pcm_substream *substream, |
893 | struct snd_pcm_hw_params *params, | 917 | struct snd_pcm_hw_params *params, |
894 | struct snd_soc_dai *dai) | 918 | struct snd_soc_dai *dai) |
895 | { | 919 | { |
896 | struct fsi_priv *fsi = fsi_get_priv(substream); | 920 | struct fsi_priv *fsi = fsi_get_priv(substream); |
897 | struct fsi_master *master = fsi_get_master(fsi); | 921 | struct fsi_master *master = fsi_get_master(fsi); |
898 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); | 922 | set_rate_func set_rate; |
899 | int fsi_ver = master->core->ver; | 923 | int fsi_ver = master->core->ver; |
900 | long rate = params_rate(params); | 924 | long rate = params_rate(params); |
901 | int ret; | 925 | int ret; |
902 | 926 | ||
903 | set_rate = master->info->set_rate; | 927 | set_rate = fsi_get_info_set_rate(master); |
904 | if (!set_rate) | 928 | if (!set_rate) |
905 | return 0; | 929 | return 0; |
906 | 930 | ||
@@ -975,6 +999,7 @@ static struct snd_soc_dai_ops fsi_dai_ops = { | |||
975 | .startup = fsi_dai_startup, | 999 | .startup = fsi_dai_startup, |
976 | .shutdown = fsi_dai_shutdown, | 1000 | .shutdown = fsi_dai_shutdown, |
977 | .trigger = fsi_dai_trigger, | 1001 | .trigger = fsi_dai_trigger, |
1002 | .set_fmt = fsi_dai_set_fmt, | ||
978 | .hw_params = fsi_dai_hw_params, | 1003 | .hw_params = fsi_dai_hw_params, |
979 | }; | 1004 | }; |
980 | 1005 | ||