diff options
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/fsi.c | 182 |
1 files changed, 100 insertions, 82 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 643d256e13c8..fec1a7dcf90b 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -118,10 +118,38 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena | |||
118 | /* | 118 | /* |
119 | * FSI driver use below type name for variable | 119 | * FSI driver use below type name for variable |
120 | * | 120 | * |
121 | * xxx_len : data length | ||
122 | * xxx_width : data width | ||
123 | * xxx_offset : data offset | ||
124 | * xxx_num : number of data | 121 | * xxx_num : number of data |
122 | * xxx_pos : position of data | ||
123 | * xxx_capa : capacity of data | ||
124 | */ | ||
125 | |||
126 | /* | ||
127 | * period/frame/sample image | ||
128 | * | ||
129 | * ex) PCM (2ch) | ||
130 | * | ||
131 | * period pos period pos | ||
132 | * [n] [n + 1] | ||
133 | * |<-------------------- period--------------------->| | ||
134 | * ==|============================================ ... =|== | ||
135 | * | | | ||
136 | * ||<----- frame ----->|<------ frame ----->| ... | | ||
137 | * |+--------------------+--------------------+- ... | | ||
138 | * ||[ sample ][ sample ]|[ sample ][ sample ]| ... | | ||
139 | * |+--------------------+--------------------+- ... | | ||
140 | * ==|============================================ ... =|== | ||
141 | */ | ||
142 | |||
143 | /* | ||
144 | * FSI FIFO image | ||
145 | * | ||
146 | * | | | ||
147 | * | | | ||
148 | * | [ sample ] | | ||
149 | * | [ sample ] | | ||
150 | * | [ sample ] | | ||
151 | * | [ sample ] | | ||
152 | * --> go to codecs | ||
125 | */ | 153 | */ |
126 | 154 | ||
127 | /* | 155 | /* |
@@ -131,12 +159,11 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena | |||
131 | struct fsi_stream { | 159 | struct fsi_stream { |
132 | struct snd_pcm_substream *substream; | 160 | struct snd_pcm_substream *substream; |
133 | 161 | ||
134 | int fifo_max_num; | 162 | int fifo_sample_capa; /* sample capacity of FSI FIFO */ |
135 | 163 | int buff_sample_capa; /* sample capacity of ALSA buffer */ | |
136 | int buff_offset; | 164 | int buff_sample_pos; /* sample position of ALSA buffer */ |
137 | int buff_len; | 165 | int period_samples; /* sample number / 1 period */ |
138 | int period_len; | 166 | int period_pos; /* current period position */ |
139 | int period_num; | ||
140 | 167 | ||
141 | int uerr_num; | 168 | int uerr_num; |
142 | int oerr_num; | 169 | int oerr_num; |
@@ -342,6 +369,16 @@ static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) | |||
342 | return shift; | 369 | return shift; |
343 | } | 370 | } |
344 | 371 | ||
372 | static int fsi_frame2sample(struct fsi_priv *fsi, int frames) | ||
373 | { | ||
374 | return frames * fsi->chan_num; | ||
375 | } | ||
376 | |||
377 | static int fsi_sample2frame(struct fsi_priv *fsi, int samples) | ||
378 | { | ||
379 | return samples / fsi->chan_num; | ||
380 | } | ||
381 | |||
345 | static void fsi_stream_push(struct fsi_priv *fsi, | 382 | static void fsi_stream_push(struct fsi_priv *fsi, |
346 | int is_play, | 383 | int is_play, |
347 | struct snd_pcm_substream *substream) | 384 | struct snd_pcm_substream *substream) |
@@ -350,10 +387,10 @@ static void fsi_stream_push(struct fsi_priv *fsi, | |||
350 | struct snd_pcm_runtime *runtime = substream->runtime; | 387 | struct snd_pcm_runtime *runtime = substream->runtime; |
351 | 388 | ||
352 | io->substream = substream; | 389 | io->substream = substream; |
353 | io->buff_len = frames_to_bytes(runtime, runtime->buffer_size); | 390 | io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size); |
354 | io->buff_offset = 0; | 391 | io->buff_sample_pos = 0; |
355 | io->period_len = frames_to_bytes(runtime, runtime->period_size); | 392 | io->period_samples = fsi_frame2sample(fsi, runtime->period_size); |
356 | io->period_num = 0; | 393 | io->period_pos = 0; |
357 | io->oerr_num = -1; /* ignore 1st err */ | 394 | io->oerr_num = -1; /* ignore 1st err */ |
358 | io->uerr_num = -1; /* ignore 1st err */ | 395 | io->uerr_num = -1; /* ignore 1st err */ |
359 | } | 396 | } |
@@ -371,47 +408,26 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | |||
371 | dev_err(dai->dev, "under_run = %d\n", io->uerr_num); | 408 | dev_err(dai->dev, "under_run = %d\n", io->uerr_num); |
372 | 409 | ||
373 | io->substream = NULL; | 410 | io->substream = NULL; |
374 | io->buff_len = 0; | 411 | io->buff_sample_capa = 0; |
375 | io->buff_offset = 0; | 412 | io->buff_sample_pos = 0; |
376 | io->period_len = 0; | 413 | io->period_samples = 0; |
377 | io->period_num = 0; | 414 | io->period_pos = 0; |
378 | io->oerr_num = 0; | 415 | io->oerr_num = 0; |
379 | io->uerr_num = 0; | 416 | io->uerr_num = 0; |
380 | } | 417 | } |
381 | 418 | ||
382 | static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) | 419 | static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play) |
383 | { | 420 | { |
384 | u32 status; | 421 | u32 status; |
385 | int data_num; | 422 | int frames; |
386 | 423 | ||
387 | status = is_play ? | 424 | status = is_play ? |
388 | fsi_reg_read(fsi, DOFF_ST) : | 425 | fsi_reg_read(fsi, DOFF_ST) : |
389 | fsi_reg_read(fsi, DIFF_ST); | 426 | fsi_reg_read(fsi, DIFF_ST); |
390 | 427 | ||
391 | data_num = 0x1ff & (status >> 8); | 428 | frames = 0x1ff & (status >> 8); |
392 | data_num *= fsi->chan_num; | ||
393 | |||
394 | return data_num; | ||
395 | } | ||
396 | |||
397 | static int fsi_len2num(int len, int width) | ||
398 | { | ||
399 | return len / width; | ||
400 | } | ||
401 | 429 | ||
402 | #define fsi_num2offset(a, b) fsi_num2len(a, b) | 430 | return fsi_frame2sample(fsi, frames); |
403 | static int fsi_num2len(int num, int width) | ||
404 | { | ||
405 | return num * width; | ||
406 | } | ||
407 | |||
408 | static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play) | ||
409 | { | ||
410 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
411 | struct snd_pcm_substream *substream = io->substream; | ||
412 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
413 | |||
414 | return frames_to_bytes(runtime, 1) / fsi->chan_num; | ||
415 | } | 431 | } |
416 | 432 | ||
417 | static void fsi_count_fifo_err(struct fsi_priv *fsi) | 433 | static void fsi_count_fifo_err(struct fsi_priv *fsi) |
@@ -443,8 +459,10 @@ static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream) | |||
443 | { | 459 | { |
444 | int is_play = fsi_stream_is_play(stream); | 460 | int is_play = fsi_stream_is_play(stream); |
445 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 461 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
462 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
446 | 463 | ||
447 | return io->substream->runtime->dma_area + io->buff_offset; | 464 | return runtime->dma_area + |
465 | samples_to_bytes(runtime, io->buff_sample_pos); | ||
448 | } | 466 | } |
449 | 467 | ||
450 | static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) | 468 | static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) |
@@ -683,13 +701,14 @@ static void fsi_fifo_init(struct fsi_priv *fsi, | |||
683 | struct fsi_master *master = fsi_get_master(fsi); | 701 | struct fsi_master *master = fsi_get_master(fsi); |
684 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 702 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
685 | u32 shift, i; | 703 | u32 shift, i; |
704 | int frame_capa; | ||
686 | 705 | ||
687 | /* get on-chip RAM capacity */ | 706 | /* get on-chip RAM capacity */ |
688 | shift = fsi_master_read(master, FIFO_SZ); | 707 | shift = fsi_master_read(master, FIFO_SZ); |
689 | shift >>= fsi_get_port_shift(fsi, is_play); | 708 | shift >>= fsi_get_port_shift(fsi, is_play); |
690 | shift &= FIFO_SZ_MASK; | 709 | shift &= FIFO_SZ_MASK; |
691 | io->fifo_max_num = 256 << shift; | 710 | frame_capa = 256 << shift; |
692 | dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num); | 711 | dev_dbg(dai->dev, "fifo = %d words\n", frame_capa); |
693 | 712 | ||
694 | /* | 713 | /* |
695 | * The maximum number of sample data varies depending | 714 | * The maximum number of sample data varies depending |
@@ -711,9 +730,11 @@ static void fsi_fifo_init(struct fsi_priv *fsi, | |||
711 | * 8 channels: 32 ( 32 x 8 = 256) | 730 | * 8 channels: 32 ( 32 x 8 = 256) |
712 | */ | 731 | */ |
713 | for (i = 1; i < fsi->chan_num; i <<= 1) | 732 | for (i = 1; i < fsi->chan_num; i <<= 1) |
714 | io->fifo_max_num >>= 1; | 733 | frame_capa >>= 1; |
715 | dev_dbg(dai->dev, "%d channel %d store\n", | 734 | dev_dbg(dai->dev, "%d channel %d store\n", |
716 | fsi->chan_num, io->fifo_max_num); | 735 | fsi->chan_num, frame_capa); |
736 | |||
737 | io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); | ||
717 | 738 | ||
718 | /* | 739 | /* |
719 | * set interrupt generation factor | 740 | * set interrupt generation factor |
@@ -734,10 +755,10 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
734 | struct snd_pcm_substream *substream = NULL; | 755 | struct snd_pcm_substream *substream = NULL; |
735 | int is_play = fsi_stream_is_play(stream); | 756 | int is_play = fsi_stream_is_play(stream); |
736 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 757 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
737 | int data_residue_num; | 758 | int sample_residues; |
738 | int data_num; | 759 | int sample_width; |
739 | int data_num_max; | 760 | int samples; |
740 | int ch_width; | 761 | int samples_max; |
741 | int over_period; | 762 | int over_period; |
742 | void (*fn)(struct fsi_priv *fsi, int size); | 763 | void (*fn)(struct fsi_priv *fsi, int size); |
743 | 764 | ||
@@ -753,36 +774,35 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
753 | /* FSI FIFO has limit. | 774 | /* FSI FIFO has limit. |
754 | * So, this driver can not send periods data at a time | 775 | * So, this driver can not send periods data at a time |
755 | */ | 776 | */ |
756 | if (io->buff_offset >= | 777 | if (io->buff_sample_pos >= |
757 | fsi_num2offset(io->period_num + 1, io->period_len)) { | 778 | io->period_samples * (io->period_pos + 1)) { |
758 | 779 | ||
759 | over_period = 1; | 780 | over_period = 1; |
760 | io->period_num = (io->period_num + 1) % runtime->periods; | 781 | io->period_pos = (io->period_pos + 1) % runtime->periods; |
761 | 782 | ||
762 | if (0 == io->period_num) | 783 | if (0 == io->period_pos) |
763 | io->buff_offset = 0; | 784 | io->buff_sample_pos = 0; |
764 | } | 785 | } |
765 | 786 | ||
766 | /* get 1 channel data width */ | 787 | /* get 1 sample data width */ |
767 | ch_width = fsi_get_frame_width(fsi, is_play); | 788 | sample_width = samples_to_bytes(runtime, 1); |
768 | 789 | ||
769 | /* get residue data number of alsa */ | 790 | /* get number of residue samples */ |
770 | data_residue_num = fsi_len2num(io->buff_len - io->buff_offset, | 791 | sample_residues = io->buff_sample_capa - io->buff_sample_pos; |
771 | ch_width); | ||
772 | 792 | ||
773 | if (is_play) { | 793 | if (is_play) { |
774 | /* | 794 | /* |
775 | * for play-back | 795 | * for play-back |
776 | * | 796 | * |
777 | * data_num_max : number of FSI fifo free space | 797 | * samples_max : number of FSI fifo free samples space |
778 | * data_num : number of ALSA residue data | 798 | * samples : number of ALSA residue samples |
779 | */ | 799 | */ |
780 | data_num_max = io->fifo_max_num * fsi->chan_num; | 800 | samples_max = io->fifo_sample_capa; |
781 | data_num_max -= fsi_get_fifo_data_num(fsi, is_play); | 801 | samples_max -= fsi_get_current_fifo_samples(fsi, is_play); |
782 | 802 | ||
783 | data_num = data_residue_num; | 803 | samples = sample_residues; |
784 | 804 | ||
785 | switch (ch_width) { | 805 | switch (sample_width) { |
786 | case 2: | 806 | case 2: |
787 | fn = fsi_dma_soft_push16; | 807 | fn = fsi_dma_soft_push16; |
788 | break; | 808 | break; |
@@ -796,13 +816,13 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
796 | /* | 816 | /* |
797 | * for capture | 817 | * for capture |
798 | * | 818 | * |
799 | * data_num_max : number of ALSA free space | 819 | * samples_max : number of ALSA free samples space |
800 | * data_num : number of data in FSI fifo | 820 | * samples : number of samples in FSI fifo |
801 | */ | 821 | */ |
802 | data_num_max = data_residue_num; | 822 | samples_max = sample_residues; |
803 | data_num = fsi_get_fifo_data_num(fsi, is_play); | 823 | samples = fsi_get_current_fifo_samples(fsi, is_play); |
804 | 824 | ||
805 | switch (ch_width) { | 825 | switch (sample_width) { |
806 | case 2: | 826 | case 2: |
807 | fn = fsi_dma_soft_pop16; | 827 | fn = fsi_dma_soft_pop16; |
808 | break; | 828 | break; |
@@ -814,12 +834,12 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
814 | } | 834 | } |
815 | } | 835 | } |
816 | 836 | ||
817 | data_num = min(data_num, data_num_max); | 837 | samples = min(samples, samples_max); |
818 | 838 | ||
819 | fn(fsi, data_num); | 839 | fn(fsi, samples); |
820 | 840 | ||
821 | /* update buff_offset */ | 841 | /* update buff_sample_pos */ |
822 | io->buff_offset += fsi_num2offset(data_num, ch_width); | 842 | io->buff_sample_pos += samples; |
823 | 843 | ||
824 | if (over_period) | 844 | if (over_period) |
825 | snd_pcm_period_elapsed(substream); | 845 | snd_pcm_period_elapsed(substream); |
@@ -1107,16 +1127,14 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) | |||
1107 | 1127 | ||
1108 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | 1128 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) |
1109 | { | 1129 | { |
1110 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1111 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1130 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1112 | struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); | 1131 | struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); |
1113 | long location; | 1132 | int samples_pos = io->buff_sample_pos - 1; |
1114 | 1133 | ||
1115 | location = (io->buff_offset - 1); | 1134 | if (samples_pos < 0) |
1116 | if (location < 0) | 1135 | samples_pos = 0; |
1117 | location = 0; | ||
1118 | 1136 | ||
1119 | return bytes_to_frames(runtime, location); | 1137 | return fsi_sample2frame(fsi, samples_pos); |
1120 | } | 1138 | } |
1121 | 1139 | ||
1122 | static struct snd_pcm_ops fsi_pcm_ops = { | 1140 | static struct snd_pcm_ops fsi_pcm_ops = { |