diff options
author | Mark Brown <broonie@kernel.org> | 2016-05-27 08:45:55 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-05-27 08:45:55 -0400 |
commit | 77c92d2b4c6a65ef7e9ca0e7d574d4d48fd5efae (patch) | |
tree | a679783f49521f00b026b9475ef222b78519fb8e /sound | |
parent | 38e3c63da388f25c0b472a6624eb005076ea0dfb (diff) | |
parent | ee4c879b53eb5d757661b9bc8fcdf1a3d2e5fdfb (diff) |
Merge remote-tracking branch 'asoc/topic/sti' into asoc-next
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/sti/sti_uniperif.c | 144 | ||||
-rw-r--r-- | sound/soc/sti/uniperif.h | 220 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_player.c | 182 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_reader.c | 229 |
4 files changed, 646 insertions, 129 deletions
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 39bcefe5eea0..488ef4ed8fba 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c | |||
@@ -11,6 +11,142 @@ | |||
11 | #include "uniperif.h" | 11 | #include "uniperif.h" |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * User frame size shall be 2, 4, 6 or 8 32-bits words length | ||
15 | * (i.e. 8, 16, 24 or 32 bytes) | ||
16 | * This constraint comes from allowed values for | ||
17 | * UNIPERIF_I2S_FMT_NUM_CH register | ||
18 | */ | ||
19 | #define UNIPERIF_MAX_FRAME_SZ 0x20 | ||
20 | #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ) | ||
21 | |||
22 | int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
23 | unsigned int rx_mask, int slots, | ||
24 | int slot_width) | ||
25 | { | ||
26 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
27 | struct uniperif *uni = priv->dai_data.uni; | ||
28 | int i, frame_size, avail_slots; | ||
29 | |||
30 | if (!UNIPERIF_TYPE_IS_TDM(uni)) { | ||
31 | dev_err(uni->dev, "cpu dai not in tdm mode\n"); | ||
32 | return -EINVAL; | ||
33 | } | ||
34 | |||
35 | /* store info in unip context */ | ||
36 | uni->tdm_slot.slots = slots; | ||
37 | uni->tdm_slot.slot_width = slot_width; | ||
38 | /* unip is unidirectionnal */ | ||
39 | uni->tdm_slot.mask = (tx_mask != 0) ? tx_mask : rx_mask; | ||
40 | |||
41 | /* number of available timeslots */ | ||
42 | for (i = 0, avail_slots = 0; i < uni->tdm_slot.slots; i++) { | ||
43 | if ((uni->tdm_slot.mask >> i) & 0x01) | ||
44 | avail_slots++; | ||
45 | } | ||
46 | uni->tdm_slot.avail_slots = avail_slots; | ||
47 | |||
48 | /* frame size in bytes */ | ||
49 | frame_size = uni->tdm_slot.avail_slots * uni->tdm_slot.slot_width / 8; | ||
50 | |||
51 | /* check frame size is allowed */ | ||
52 | if ((frame_size > UNIPERIF_MAX_FRAME_SZ) || | ||
53 | (frame_size & ~(int)UNIPERIF_ALLOWED_FRAME_SZ)) { | ||
54 | dev_err(uni->dev, "frame size not allowed: %d bytes\n", | ||
55 | frame_size); | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, | ||
63 | struct snd_pcm_hw_rule *rule) | ||
64 | { | ||
65 | struct uniperif *uni = rule->private; | ||
66 | struct snd_interval t; | ||
67 | |||
68 | t.min = uni->tdm_slot.avail_slots; | ||
69 | t.max = uni->tdm_slot.avail_slots; | ||
70 | t.openmin = 0; | ||
71 | t.openmax = 0; | ||
72 | t.integer = 0; | ||
73 | |||
74 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
75 | } | ||
76 | |||
77 | int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, | ||
78 | struct snd_pcm_hw_rule *rule) | ||
79 | { | ||
80 | struct uniperif *uni = rule->private; | ||
81 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | ||
82 | u64 format; | ||
83 | |||
84 | switch (uni->tdm_slot.slot_width) { | ||
85 | case 16: | ||
86 | format = SNDRV_PCM_FMTBIT_S16_LE; | ||
87 | break; | ||
88 | case 32: | ||
89 | format = SNDRV_PCM_FMTBIT_S32_LE; | ||
90 | break; | ||
91 | default: | ||
92 | dev_err(uni->dev, "format not supported: %d bits\n", | ||
93 | uni->tdm_slot.slot_width); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | maskp->bits[0] &= (u_int32_t)format; | ||
98 | maskp->bits[1] &= (u_int32_t)(format >> 32); | ||
99 | /* clear remaining indexes */ | ||
100 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX - 64) / 8); | ||
101 | |||
102 | if (!maskp->bits[0] && !maskp->bits[1]) | ||
103 | return -EINVAL; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, | ||
109 | unsigned int *word_pos) | ||
110 | { | ||
111 | int slot_width = uni->tdm_slot.slot_width / 8; | ||
112 | int slots_num = uni->tdm_slot.slots; | ||
113 | unsigned int slots_mask = uni->tdm_slot.mask; | ||
114 | int i, j, k; | ||
115 | unsigned int word16_pos[4]; | ||
116 | |||
117 | /* word16_pos: | ||
118 | * word16_pos[0] = WORDX_LSB | ||
119 | * word16_pos[1] = WORDX_MSB, | ||
120 | * word16_pos[2] = WORDX+1_LSB | ||
121 | * word16_pos[3] = WORDX+1_MSB | ||
122 | */ | ||
123 | |||
124 | /* set unip word position */ | ||
125 | for (i = 0, j = 0, k = 0; (i < slots_num) && (k < WORD_MAX); i++) { | ||
126 | if ((slots_mask >> i) & 0x01) { | ||
127 | word16_pos[j] = i * slot_width; | ||
128 | |||
129 | if (slot_width == 4) { | ||
130 | word16_pos[j + 1] = word16_pos[j] + 2; | ||
131 | j++; | ||
132 | } | ||
133 | j++; | ||
134 | |||
135 | if (j > 3) { | ||
136 | word_pos[k] = word16_pos[1] | | ||
137 | (word16_pos[0] << 8) | | ||
138 | (word16_pos[3] << 16) | | ||
139 | (word16_pos[2] << 24); | ||
140 | j = 0; | ||
141 | k++; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* | ||
14 | * sti_uniperiph_dai_create_ctrl | 150 | * sti_uniperiph_dai_create_ctrl |
15 | * This function is used to create Ctrl associated to DAI but also pcm device. | 151 | * This function is used to create Ctrl associated to DAI but also pcm device. |
16 | * Request is done by front end to associate ctrl with pcm device id | 152 | * Request is done by front end to associate ctrl with pcm device id |
@@ -45,10 +181,16 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | |||
45 | struct snd_pcm_hw_params *params, | 181 | struct snd_pcm_hw_params *params, |
46 | struct snd_soc_dai *dai) | 182 | struct snd_soc_dai *dai) |
47 | { | 183 | { |
184 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
185 | struct uniperif *uni = priv->dai_data.uni; | ||
48 | struct snd_dmaengine_dai_dma_data *dma_data; | 186 | struct snd_dmaengine_dai_dma_data *dma_data; |
49 | int transfer_size; | 187 | int transfer_size; |
50 | 188 | ||
51 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | 189 | if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM) |
190 | /* transfer size = user frame size (in 32-bits FIFO cell) */ | ||
191 | transfer_size = snd_soc_params_to_frame_size(params) / 32; | ||
192 | else | ||
193 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | ||
52 | 194 | ||
53 | dma_data = snd_soc_dai_get_dma_data(dai, substream); | 195 | dma_data = snd_soc_dai_get_dma_data(dai, substream); |
54 | dma_data->maxburst = transfer_size; | 196 | dma_data->maxburst = transfer_size; |
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f0fd5a9944e9..eb9933c62ad6 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h | |||
@@ -25,7 +25,7 @@ | |||
25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) | 25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * AUD_UNIPERIF_SOFT_RST reg | 28 | * UNIPERIF_SOFT_RST reg |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 | 31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 |
@@ -50,7 +50,7 @@ | |||
50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) | 50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * AUD_UNIPERIF_FIFO_DATA reg | 53 | * UNIPERIF_FIFO_DATA reg |
54 | */ | 54 | */ |
55 | 55 | ||
56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 | 56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 |
@@ -58,7 +58,7 @@ | |||
58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) | 58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | 61 | * UNIPERIF_CHANNEL_STA_REGN reg |
62 | */ | 62 | */ |
63 | 63 | ||
64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | 64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) |
@@ -105,7 +105,7 @@ | |||
105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) | 105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) |
106 | 106 | ||
107 | /* | 107 | /* |
108 | * AUD_UNIPERIF_ITS reg | 108 | * UNIPERIF_ITS reg |
109 | */ | 109 | */ |
110 | 110 | ||
111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C | 111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C |
@@ -143,7 +143,7 @@ | |||
143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | 143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * AUD_UNIPERIF_ITS_BCLR reg | 146 | * UNIPERIF_ITS_BCLR reg |
147 | */ | 147 | */ |
148 | 148 | ||
149 | /* FIFO_ERROR */ | 149 | /* FIFO_ERROR */ |
@@ -160,7 +160,7 @@ | |||
160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) | 160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * AUD_UNIPERIF_ITM reg | 163 | * UNIPERIF_ITM reg |
164 | */ | 164 | */ |
165 | 165 | ||
166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 | 166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 |
@@ -188,7 +188,7 @@ | |||
188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | 188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) |
189 | 189 | ||
190 | /* | 190 | /* |
191 | * AUD_UNIPERIF_ITM_BCLR reg | 191 | * UNIPERIF_ITM_BCLR reg |
192 | */ | 192 | */ |
193 | 193 | ||
194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c | 194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c |
@@ -213,7 +213,7 @@ | |||
213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) | 213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) |
214 | 214 | ||
215 | /* | 215 | /* |
216 | * AUD_UNIPERIF_ITM_BSET reg | 216 | * UNIPERIF_ITM_BSET reg |
217 | */ | 217 | */ |
218 | 218 | ||
219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 | 219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 |
@@ -767,7 +767,7 @@ | |||
767 | SET_UNIPERIF_REG(ip, \ | 767 | SET_UNIPERIF_REG(ip, \ |
768 | UNIPERIF_CTRL_OFFSET(ip), \ | 768 | UNIPERIF_CTRL_OFFSET(ip), \ |
769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ | 769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ |
770 | CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) | 770 | UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) |
771 | 771 | ||
772 | /* UNDERFLOW_REC_WINDOW */ | 772 | /* UNDERFLOW_REC_WINDOW */ |
773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 | 773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 |
@@ -1046,7 +1046,7 @@ | |||
1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) | 1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) |
1047 | 1047 | ||
1048 | /* | 1048 | /* |
1049 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | 1049 | * UNIPERIF_CHANNEL_STA_REGN reg |
1050 | */ | 1050 | */ |
1051 | 1051 | ||
1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | 1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) |
@@ -1057,7 +1057,7 @@ | |||
1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) | 1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) |
1058 | 1058 | ||
1059 | /* | 1059 | /* |
1060 | * AUD_UNIPERIF_USER_VALIDITY reg | 1060 | * UNIPERIF_USER_VALIDITY reg |
1061 | */ | 1061 | */ |
1062 | 1062 | ||
1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 | 1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 |
@@ -1101,12 +1101,136 @@ | |||
1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) | 1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) |
1102 | 1102 | ||
1103 | /* | 1103 | /* |
1104 | * UNIPERIF_TDM_ENABLE | ||
1105 | */ | ||
1106 | #define UNIPERIF_TDM_ENABLE_OFFSET(ip) 0x0118 | ||
1107 | #define GET_UNIPERIF_TDM_ENABLE(ip) \ | ||
1108 | readl_relaxed(ip->base + UNIPERIF_TDM_ENABLE_OFFSET(ip)) | ||
1109 | #define SET_UNIPERIF_TDM_ENABLE(ip, value) \ | ||
1110 | writel_relaxed(value, ip->base + UNIPERIF_TDM_ENABLE_OFFSET(ip)) | ||
1111 | |||
1112 | /* TDM_ENABLE */ | ||
1113 | #define UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip) 0x0 | ||
1114 | #define UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip) 0x1 | ||
1115 | #define GET_UNIPERIF_TDM_ENABLE_EN_TDM(ip) \ | ||
1116 | GET_UNIPERIF_REG(ip, \ | ||
1117 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1118 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1119 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip)) | ||
1120 | #define SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(ip) \ | ||
1121 | SET_UNIPERIF_REG(ip, \ | ||
1122 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1123 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1124 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip), 1) | ||
1125 | #define SET_UNIPERIF_TDM_ENABLE_TDM_DISABLE(ip) \ | ||
1126 | SET_UNIPERIF_REG(ip, \ | ||
1127 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1128 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1129 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip), 0) | ||
1130 | |||
1131 | /* | ||
1132 | * UNIPERIF_TDM_FS_REF_FREQ | ||
1133 | */ | ||
1134 | #define UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip) 0x011c | ||
1135 | #define GET_UNIPERIF_TDM_FS_REF_FREQ(ip) \ | ||
1136 | readl_relaxed(ip->base + UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip)) | ||
1137 | #define SET_UNIPERIF_TDM_FS_REF_FREQ(ip, value) \ | ||
1138 | writel_relaxed(value, ip->base + \ | ||
1139 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip)) | ||
1140 | |||
1141 | /* REF_FREQ */ | ||
1142 | #define UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip) 0x0 | ||
1143 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip) 0 | ||
1144 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip) 1 | ||
1145 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip) 2 | ||
1146 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip) 3 | ||
1147 | #define UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip) 0x3 | ||
1148 | #define GET_UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ(ip) \ | ||
1149 | GET_UNIPERIF_REG(ip, \ | ||
1150 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1151 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1152 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip)) | ||
1153 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip) \ | ||
1154 | SET_UNIPERIF_REG(ip, \ | ||
1155 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1156 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1157 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1158 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip)) | ||
1159 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip) \ | ||
1160 | SET_UNIPERIF_REG(ip, \ | ||
1161 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1162 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1163 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1164 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip)) | ||
1165 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip) \ | ||
1166 | SET_UNIPERIF_REG(ip, \ | ||
1167 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1168 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1169 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1170 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip)) | ||
1171 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip) \ | ||
1172 | SET_UNIPERIF_REG(ip, \ | ||
1173 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1174 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1175 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1176 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip)) | ||
1177 | |||
1178 | /* | ||
1179 | * UNIPERIF_TDM_FS_REF_DIV | ||
1180 | */ | ||
1181 | #define UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip) 0x0120 | ||
1182 | #define GET_UNIPERIF_TDM_FS_REF_DIV(ip) \ | ||
1183 | readl_relaxed(ip->base + UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip)) | ||
1184 | #define SET_UNIPERIF_TDM_FS_REF_DIV(ip, value) \ | ||
1185 | writel_relaxed(value, ip->base + \ | ||
1186 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip)) | ||
1187 | |||
1188 | /* NUM_TIMESLOT */ | ||
1189 | #define UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip) 0x0 | ||
1190 | #define UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip) 0xff | ||
1191 | #define GET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(ip) \ | ||
1192 | GET_UNIPERIF_REG(ip, \ | ||
1193 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip), \ | ||
1194 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip), \ | ||
1195 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip)) | ||
1196 | #define SET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(ip, value) \ | ||
1197 | SET_UNIPERIF_REG(ip, \ | ||
1198 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip), \ | ||
1199 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip), \ | ||
1200 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip), value) | ||
1201 | |||
1202 | /* | ||
1203 | * UNIPERIF_TDM_WORD_POS_X_Y | ||
1204 | * 32 bits of UNIPERIF_TDM_WORD_POS_X_Y register shall be set in 1 shot | ||
1205 | */ | ||
1206 | #define UNIPERIF_TDM_WORD_POS_1_2_OFFSET(ip) 0x013c | ||
1207 | #define UNIPERIF_TDM_WORD_POS_3_4_OFFSET(ip) 0x0140 | ||
1208 | #define UNIPERIF_TDM_WORD_POS_5_6_OFFSET(ip) 0x0144 | ||
1209 | #define UNIPERIF_TDM_WORD_POS_7_8_OFFSET(ip) 0x0148 | ||
1210 | #define GET_UNIPERIF_TDM_WORD_POS(ip, words) \ | ||
1211 | readl_relaxed(ip->base + UNIPERIF_TDM_WORD_POS_##words##_OFFSET(ip)) | ||
1212 | #define SET_UNIPERIF_TDM_WORD_POS(ip, words, value) \ | ||
1213 | writel_relaxed(value, ip->base + \ | ||
1214 | UNIPERIF_TDM_WORD_POS_##words##_OFFSET(ip)) | ||
1215 | /* | ||
1104 | * uniperipheral IP capabilities | 1216 | * uniperipheral IP capabilities |
1105 | */ | 1217 | */ |
1106 | 1218 | ||
1107 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ | 1219 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ |
1108 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ | 1220 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ |
1109 | 1221 | ||
1222 | #define UNIPERIF_TYPE_IS_HDMI(p) \ | ||
1223 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_HDMI) | ||
1224 | #define UNIPERIF_TYPE_IS_PCM(p) \ | ||
1225 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_PCM) | ||
1226 | #define UNIPERIF_TYPE_IS_SPDIF(p) \ | ||
1227 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_SPDIF) | ||
1228 | #define UNIPERIF_TYPE_IS_IEC958(p) \ | ||
1229 | (UNIPERIF_TYPE_IS_HDMI(p) || \ | ||
1230 | UNIPERIF_TYPE_IS_SPDIF(p)) | ||
1231 | #define UNIPERIF_TYPE_IS_TDM(p) \ | ||
1232 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_TDM) | ||
1233 | |||
1110 | /* | 1234 | /* |
1111 | * Uniperipheral IP revisions | 1235 | * Uniperipheral IP revisions |
1112 | */ | 1236 | */ |
@@ -1125,10 +1249,11 @@ enum uniperif_version { | |||
1125 | }; | 1249 | }; |
1126 | 1250 | ||
1127 | enum uniperif_type { | 1251 | enum uniperif_type { |
1128 | SND_ST_UNIPERIF_PLAYER_TYPE_NONE, | 1252 | SND_ST_UNIPERIF_TYPE_NONE, |
1129 | SND_ST_UNIPERIF_PLAYER_TYPE_HDMI, | 1253 | SND_ST_UNIPERIF_TYPE_HDMI, |
1130 | SND_ST_UNIPERIF_PLAYER_TYPE_PCM, | 1254 | SND_ST_UNIPERIF_TYPE_PCM, |
1131 | SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF | 1255 | SND_ST_UNIPERIF_TYPE_SPDIF, |
1256 | SND_ST_UNIPERIF_TYPE_TDM | ||
1132 | }; | 1257 | }; |
1133 | 1258 | ||
1134 | enum uniperif_state { | 1259 | enum uniperif_state { |
@@ -1145,9 +1270,17 @@ enum uniperif_iec958_encoding_mode { | |||
1145 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED | 1270 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED |
1146 | }; | 1271 | }; |
1147 | 1272 | ||
1273 | enum uniperif_word_pos { | ||
1274 | WORD_1_2, | ||
1275 | WORD_3_4, | ||
1276 | WORD_5_6, | ||
1277 | WORD_7_8, | ||
1278 | WORD_MAX | ||
1279 | }; | ||
1280 | |||
1148 | struct uniperif_info { | 1281 | struct uniperif_info { |
1149 | int id; /* instance value of the uniperipheral IP */ | 1282 | int id; /* instance value of the uniperipheral IP */ |
1150 | enum uniperif_type player_type; | 1283 | enum uniperif_type type; |
1151 | int underflow_enabled; /* Underflow recovery mode */ | 1284 | int underflow_enabled; /* Underflow recovery mode */ |
1152 | }; | 1285 | }; |
1153 | 1286 | ||
@@ -1156,12 +1289,20 @@ struct uniperif_iec958_settings { | |||
1156 | struct snd_aes_iec958 iec958; | 1289 | struct snd_aes_iec958 iec958; |
1157 | }; | 1290 | }; |
1158 | 1291 | ||
1292 | struct dai_tdm_slot { | ||
1293 | unsigned int mask; | ||
1294 | int slots; | ||
1295 | int slot_width; | ||
1296 | unsigned int avail_slots; | ||
1297 | }; | ||
1298 | |||
1159 | struct uniperif { | 1299 | struct uniperif { |
1160 | /* System information */ | 1300 | /* System information */ |
1161 | struct uniperif_info *info; | 1301 | struct uniperif_info *info; |
1162 | struct device *dev; | 1302 | struct device *dev; |
1163 | int ver; /* IP version, used by register access macros */ | 1303 | int ver; /* IP version, used by register access macros */ |
1164 | struct regmap_field *clk_sel; | 1304 | struct regmap_field *clk_sel; |
1305 | struct regmap_field *valid_sel; | ||
1165 | 1306 | ||
1166 | /* capabilities */ | 1307 | /* capabilities */ |
1167 | const struct snd_pcm_hardware *hw; | 1308 | const struct snd_pcm_hardware *hw; |
@@ -1192,6 +1333,7 @@ struct uniperif { | |||
1192 | 1333 | ||
1193 | /* dai properties */ | 1334 | /* dai properties */ |
1194 | unsigned int daifmt; | 1335 | unsigned int daifmt; |
1336 | struct dai_tdm_slot tdm_slot; | ||
1195 | 1337 | ||
1196 | /* DAI callbacks */ | 1338 | /* DAI callbacks */ |
1197 | const struct snd_soc_dai_ops *dai_ops; | 1339 | const struct snd_soc_dai_ops *dai_ops; |
@@ -1209,6 +1351,28 @@ struct sti_uniperiph_data { | |||
1209 | struct sti_uniperiph_dai dai_data; | 1351 | struct sti_uniperiph_dai dai_data; |
1210 | }; | 1352 | }; |
1211 | 1353 | ||
1354 | static const struct snd_pcm_hardware uni_tdm_hw = { | ||
1355 | .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
1356 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | | ||
1357 | SNDRV_PCM_INFO_MMAP_VALID, | ||
1358 | |||
1359 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
1360 | |||
1361 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
1362 | .rate_min = 8000, | ||
1363 | .rate_max = 48000, | ||
1364 | |||
1365 | .channels_min = 1, | ||
1366 | .channels_max = 32, | ||
1367 | |||
1368 | .periods_min = 2, | ||
1369 | .periods_max = 10, | ||
1370 | |||
1371 | .period_bytes_min = 128, | ||
1372 | .period_bytes_max = 64 * PAGE_SIZE, | ||
1373 | .buffer_bytes_max = 256 * PAGE_SIZE | ||
1374 | }; | ||
1375 | |||
1212 | /* uniperiph player*/ | 1376 | /* uniperiph player*/ |
1213 | int uni_player_init(struct platform_device *pdev, | 1377 | int uni_player_init(struct platform_device *pdev, |
1214 | struct uniperif *uni_player); | 1378 | struct uniperif *uni_player); |
@@ -1226,4 +1390,28 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | |||
1226 | struct snd_pcm_hw_params *params, | 1390 | struct snd_pcm_hw_params *params, |
1227 | struct snd_soc_dai *dai); | 1391 | struct snd_soc_dai *dai); |
1228 | 1392 | ||
1393 | static inline int sti_uniperiph_get_user_frame_size( | ||
1394 | struct snd_pcm_runtime *runtime) | ||
1395 | { | ||
1396 | return (runtime->channels * snd_pcm_format_width(runtime->format) / 8); | ||
1397 | } | ||
1398 | |||
1399 | static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni) | ||
1400 | { | ||
1401 | return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8); | ||
1402 | } | ||
1403 | |||
1404 | int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
1405 | unsigned int rx_mask, int slots, | ||
1406 | int slot_width); | ||
1407 | |||
1408 | int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, | ||
1409 | unsigned int *word_pos); | ||
1410 | |||
1411 | int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, | ||
1412 | struct snd_pcm_hw_rule *rule); | ||
1413 | |||
1414 | int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, | ||
1415 | struct snd_pcm_hw_rule *rule); | ||
1416 | |||
1229 | #endif | 1417 | #endif |
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 7aca6b92f718..ee1c7c245bc7 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c | |||
@@ -21,23 +21,14 @@ | |||
21 | 21 | ||
22 | /* sys config registers definitions */ | 22 | /* sys config registers definitions */ |
23 | #define SYS_CFG_AUDIO_GLUE 0xA4 | 23 | #define SYS_CFG_AUDIO_GLUE 0xA4 |
24 | #define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 | ||
25 | 24 | ||
26 | /* | 25 | /* |
27 | * Driver specific types. | 26 | * Driver specific types. |
28 | */ | 27 | */ |
29 | #define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ | ||
30 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) | ||
31 | #define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ | ||
32 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) | ||
33 | #define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ | ||
34 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) | ||
35 | #define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ | ||
36 | (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ | ||
37 | UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) | ||
38 | 28 | ||
39 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 | 29 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 |
40 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 | 30 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 |
31 | #define UNIPERIF_PLAYER_I2S_OUT 1 /* player id connected to I2S/TDM TX bus */ | ||
41 | 32 | ||
42 | /* | 33 | /* |
43 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to | 34 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to |
@@ -444,18 +435,11 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
444 | 435 | ||
445 | /* Force slot width to 32 in I2S mode (HW constraint) */ | 436 | /* Force slot width to 32 in I2S mode (HW constraint) */ |
446 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == | 437 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == |
447 | SND_SOC_DAIFMT_I2S) { | 438 | SND_SOC_DAIFMT_I2S) |
448 | slot_width = 32; | 439 | slot_width = 32; |
449 | } else { | 440 | else |
450 | switch (runtime->format) { | 441 | slot_width = snd_pcm_format_width(runtime->format); |
451 | case SNDRV_PCM_FORMAT_S16_LE: | 442 | |
452 | slot_width = 16; | ||
453 | break; | ||
454 | default: | ||
455 | slot_width = 32; | ||
456 | break; | ||
457 | } | ||
458 | } | ||
459 | output_frame_size = slot_width * runtime->channels; | 443 | output_frame_size = slot_width * runtime->channels; |
460 | 444 | ||
461 | clk_div = player->mclk / runtime->rate; | 445 | clk_div = player->mclk / runtime->rate; |
@@ -530,7 +514,6 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
530 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); | 514 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); |
531 | 515 | ||
532 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | 516 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); |
533 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); | ||
534 | 517 | ||
535 | /* No iec958 formatting as outputting to DAC */ | 518 | /* No iec958 formatting as outputting to DAC */ |
536 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); | 519 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); |
@@ -538,6 +521,55 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
538 | return 0; | 521 | return 0; |
539 | } | 522 | } |
540 | 523 | ||
524 | static int uni_player_prepare_tdm(struct uniperif *player, | ||
525 | struct snd_pcm_runtime *runtime) | ||
526 | { | ||
527 | int tdm_frame_size; /* unip tdm frame size in bytes */ | ||
528 | int user_frame_size; /* user tdm frame size in bytes */ | ||
529 | /* default unip TDM_WORD_POS_X_Y */ | ||
530 | unsigned int word_pos[4] = { | ||
531 | 0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A}; | ||
532 | int freq, ret; | ||
533 | |||
534 | tdm_frame_size = | ||
535 | sti_uniperiph_get_unip_tdm_frame_size(player); | ||
536 | user_frame_size = | ||
537 | sti_uniperiph_get_user_frame_size(runtime); | ||
538 | |||
539 | /* fix 16/0 format */ | ||
540 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); | ||
541 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); | ||
542 | |||
543 | /* number of words inserted on the TDM line */ | ||
544 | SET_UNIPERIF_I2S_FMT_NUM_CH(player, user_frame_size / 4 / 2); | ||
545 | |||
546 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | ||
547 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); | ||
548 | |||
549 | /* Enable the tdm functionality */ | ||
550 | SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(player); | ||
551 | |||
552 | /* number of 8 bits timeslots avail in unip tdm frame */ | ||
553 | SET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(player, tdm_frame_size); | ||
554 | |||
555 | /* set the timeslot allocation for words in FIFO */ | ||
556 | sti_uniperiph_get_tdm_word_pos(player, word_pos); | ||
557 | SET_UNIPERIF_TDM_WORD_POS(player, 1_2, word_pos[WORD_1_2]); | ||
558 | SET_UNIPERIF_TDM_WORD_POS(player, 3_4, word_pos[WORD_3_4]); | ||
559 | SET_UNIPERIF_TDM_WORD_POS(player, 5_6, word_pos[WORD_5_6]); | ||
560 | SET_UNIPERIF_TDM_WORD_POS(player, 7_8, word_pos[WORD_7_8]); | ||
561 | |||
562 | /* set unip clk rate (not done vai set_sysclk ops) */ | ||
563 | freq = runtime->rate * tdm_frame_size * 8; | ||
564 | mutex_lock(&player->ctrl_lock); | ||
565 | ret = uni_player_clk_set_rate(player, freq); | ||
566 | if (!ret) | ||
567 | player->mclk = freq; | ||
568 | mutex_unlock(&player->ctrl_lock); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
541 | /* | 573 | /* |
542 | * ALSA uniperipheral iec958 controls | 574 | * ALSA uniperipheral iec958 controls |
543 | */ | 575 | */ |
@@ -668,11 +700,29 @@ static int uni_player_startup(struct snd_pcm_substream *substream, | |||
668 | { | 700 | { |
669 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 701 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
670 | struct uniperif *player = priv->dai_data.uni; | 702 | struct uniperif *player = priv->dai_data.uni; |
703 | int ret; | ||
704 | |||
671 | player->substream = substream; | 705 | player->substream = substream; |
672 | 706 | ||
673 | player->clk_adj = 0; | 707 | player->clk_adj = 0; |
674 | 708 | ||
675 | return 0; | 709 | if (!UNIPERIF_TYPE_IS_TDM(player)) |
710 | return 0; | ||
711 | |||
712 | /* refine hw constraint in tdm mode */ | ||
713 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
714 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
715 | sti_uniperiph_fix_tdm_chan, | ||
716 | player, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
717 | -1); | ||
718 | if (ret < 0) | ||
719 | return ret; | ||
720 | |||
721 | return snd_pcm_hw_rule_add(substream->runtime, 0, | ||
722 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
723 | sti_uniperiph_fix_tdm_format, | ||
724 | player, SNDRV_PCM_HW_PARAM_FORMAT, | ||
725 | -1); | ||
676 | } | 726 | } |
677 | 727 | ||
678 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 728 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
@@ -682,7 +732,7 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
682 | struct uniperif *player = priv->dai_data.uni; | 732 | struct uniperif *player = priv->dai_data.uni; |
683 | int ret; | 733 | int ret; |
684 | 734 | ||
685 | if (dir == SND_SOC_CLOCK_IN) | 735 | if (UNIPERIF_TYPE_IS_TDM(player) || (dir == SND_SOC_CLOCK_IN)) |
686 | return 0; | 736 | return 0; |
687 | 737 | ||
688 | if (clk_id != 0) | 738 | if (clk_id != 0) |
@@ -714,7 +764,13 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, | |||
714 | } | 764 | } |
715 | 765 | ||
716 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | 766 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ |
717 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | 767 | if (player->info->type == SND_ST_UNIPERIF_TYPE_TDM) { |
768 | /* transfer size = user frame size (in 32 bits FIFO cell) */ | ||
769 | transfer_size = | ||
770 | sti_uniperiph_get_user_frame_size(runtime) / 4; | ||
771 | } else { | ||
772 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
773 | } | ||
718 | 774 | ||
719 | /* Calculate number of empty cells available before asserting DREQ */ | 775 | /* Calculate number of empty cells available before asserting DREQ */ |
720 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { | 776 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { |
@@ -738,16 +794,19 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, | |||
738 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); | 794 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); |
739 | 795 | ||
740 | /* Uniperipheral setup depends on player type */ | 796 | /* Uniperipheral setup depends on player type */ |
741 | switch (player->info->player_type) { | 797 | switch (player->info->type) { |
742 | case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: | 798 | case SND_ST_UNIPERIF_TYPE_HDMI: |
743 | ret = uni_player_prepare_iec958(player, runtime); | 799 | ret = uni_player_prepare_iec958(player, runtime); |
744 | break; | 800 | break; |
745 | case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: | 801 | case SND_ST_UNIPERIF_TYPE_PCM: |
746 | ret = uni_player_prepare_pcm(player, runtime); | 802 | ret = uni_player_prepare_pcm(player, runtime); |
747 | break; | 803 | break; |
748 | case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: | 804 | case SND_ST_UNIPERIF_TYPE_SPDIF: |
749 | ret = uni_player_prepare_iec958(player, runtime); | 805 | ret = uni_player_prepare_iec958(player, runtime); |
750 | break; | 806 | break; |
807 | case SND_ST_UNIPERIF_TYPE_TDM: | ||
808 | ret = uni_player_prepare_tdm(player, runtime); | ||
809 | break; | ||
751 | default: | 810 | default: |
752 | dev_err(player->dev, "invalid player type"); | 811 | dev_err(player->dev, "invalid player type"); |
753 | return -EINVAL; | 812 | return -EINVAL; |
@@ -852,8 +911,8 @@ static int uni_player_start(struct uniperif *player) | |||
852 | * will not take affect and hang the player. | 911 | * will not take affect and hang the player. |
853 | */ | 912 | */ |
854 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | 913 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) |
855 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) | 914 | if (UNIPERIF_TYPE_IS_IEC958(player)) |
856 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); | 915 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); |
857 | 916 | ||
858 | /* Force channel status update (no update if clk disable) */ | 917 | /* Force channel status update (no update if clk disable) */ |
859 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | 918 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) |
@@ -954,27 +1013,30 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, | |||
954 | player->substream = NULL; | 1013 | player->substream = NULL; |
955 | } | 1014 | } |
956 | 1015 | ||
957 | static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, | 1016 | static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, |
958 | struct uniperif *player) | 1017 | struct uniperif *player) |
959 | { | 1018 | { |
960 | int bit_offset; | ||
961 | struct device_node *node = pdev->dev.of_node; | 1019 | struct device_node *node = pdev->dev.of_node; |
962 | struct regmap *regmap; | 1020 | struct regmap *regmap; |
963 | 1021 | struct reg_field regfield[2] = { | |
964 | bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; | 1022 | /* PCM_CLK_SEL */ |
1023 | REG_FIELD(SYS_CFG_AUDIO_GLUE, | ||
1024 | 8 + player->info->id, | ||
1025 | 8 + player->info->id), | ||
1026 | /* PCMP_VALID_SEL */ | ||
1027 | REG_FIELD(SYS_CFG_AUDIO_GLUE, 0, 1) | ||
1028 | }; | ||
965 | 1029 | ||
966 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); | 1030 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); |
967 | 1031 | ||
968 | if (regmap) { | 1032 | if (!regmap) { |
969 | struct reg_field regfield = | ||
970 | REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); | ||
971 | |||
972 | player->clk_sel = regmap_field_alloc(regmap, regfield); | ||
973 | } else { | ||
974 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); | 1033 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); |
975 | return -EINVAL; | 1034 | return -EINVAL; |
976 | } | 1035 | } |
977 | 1036 | ||
1037 | player->clk_sel = regmap_field_alloc(regmap, regfield[0]); | ||
1038 | player->valid_sel = regmap_field_alloc(regmap, regfield[1]); | ||
1039 | |||
978 | return 0; | 1040 | return 0; |
979 | } | 1041 | } |
980 | 1042 | ||
@@ -1012,19 +1074,21 @@ static int uni_player_parse_dt(struct platform_device *pdev, | |||
1012 | } | 1074 | } |
1013 | 1075 | ||
1014 | if (strcasecmp(mode, "hdmi") == 0) | 1076 | if (strcasecmp(mode, "hdmi") == 0) |
1015 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; | 1077 | info->type = SND_ST_UNIPERIF_TYPE_HDMI; |
1016 | else if (strcasecmp(mode, "pcm") == 0) | 1078 | else if (strcasecmp(mode, "pcm") == 0) |
1017 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; | 1079 | info->type = SND_ST_UNIPERIF_TYPE_PCM; |
1018 | else if (strcasecmp(mode, "spdif") == 0) | 1080 | else if (strcasecmp(mode, "spdif") == 0) |
1019 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; | 1081 | info->type = SND_ST_UNIPERIF_TYPE_SPDIF; |
1082 | else if (strcasecmp(mode, "tdm") == 0) | ||
1083 | info->type = SND_ST_UNIPERIF_TYPE_TDM; | ||
1020 | else | 1084 | else |
1021 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; | 1085 | info->type = SND_ST_UNIPERIF_TYPE_NONE; |
1022 | 1086 | ||
1023 | /* Save the info structure */ | 1087 | /* Save the info structure */ |
1024 | player->info = info; | 1088 | player->info = info; |
1025 | 1089 | ||
1026 | /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ | 1090 | /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ |
1027 | if (uni_player_parse_dt_clk_glue(pdev, player)) | 1091 | if (uni_player_parse_dt_audio_glue(pdev, player)) |
1028 | return -EINVAL; | 1092 | return -EINVAL; |
1029 | 1093 | ||
1030 | return 0; | 1094 | return 0; |
@@ -1037,7 +1101,8 @@ static const struct snd_soc_dai_ops uni_player_dai_ops = { | |||
1037 | .trigger = uni_player_trigger, | 1101 | .trigger = uni_player_trigger, |
1038 | .hw_params = sti_uniperiph_dai_hw_params, | 1102 | .hw_params = sti_uniperiph_dai_hw_params, |
1039 | .set_fmt = sti_uniperiph_dai_set_fmt, | 1103 | .set_fmt = sti_uniperiph_dai_set_fmt, |
1040 | .set_sysclk = uni_player_set_sysclk | 1104 | .set_sysclk = uni_player_set_sysclk, |
1105 | .set_tdm_slot = sti_uniperiph_set_tdm_slot | ||
1041 | }; | 1106 | }; |
1042 | 1107 | ||
1043 | int uni_player_init(struct platform_device *pdev, | 1108 | int uni_player_init(struct platform_device *pdev, |
@@ -1047,7 +1112,6 @@ int uni_player_init(struct platform_device *pdev, | |||
1047 | 1112 | ||
1048 | player->dev = &pdev->dev; | 1113 | player->dev = &pdev->dev; |
1049 | player->state = UNIPERIF_STATE_STOPPED; | 1114 | player->state = UNIPERIF_STATE_STOPPED; |
1050 | player->hw = &uni_player_pcm_hw; | ||
1051 | player->dai_ops = &uni_player_dai_ops; | 1115 | player->dai_ops = &uni_player_dai_ops; |
1052 | 1116 | ||
1053 | ret = uni_player_parse_dt(pdev, player); | 1117 | ret = uni_player_parse_dt(pdev, player); |
@@ -1057,6 +1121,11 @@ int uni_player_init(struct platform_device *pdev, | |||
1057 | return ret; | 1121 | return ret; |
1058 | } | 1122 | } |
1059 | 1123 | ||
1124 | if (UNIPERIF_TYPE_IS_TDM(player)) | ||
1125 | player->hw = &uni_tdm_hw; | ||
1126 | else | ||
1127 | player->hw = &uni_player_pcm_hw; | ||
1128 | |||
1060 | /* Get uniperif resource */ | 1129 | /* Get uniperif resource */ |
1061 | player->clk = of_clk_get(pdev->dev.of_node, 0); | 1130 | player->clk = of_clk_get(pdev->dev.of_node, 0); |
1062 | if (IS_ERR(player->clk)) | 1131 | if (IS_ERR(player->clk)) |
@@ -1073,6 +1142,17 @@ int uni_player_init(struct platform_device *pdev, | |||
1073 | } | 1142 | } |
1074 | } | 1143 | } |
1075 | 1144 | ||
1145 | /* connect to I2S/TDM TX bus */ | ||
1146 | if (player->valid_sel && | ||
1147 | (player->info->id == UNIPERIF_PLAYER_I2S_OUT)) { | ||
1148 | ret = regmap_field_write(player->valid_sel, player->info->id); | ||
1149 | if (ret) { | ||
1150 | dev_err(player->dev, | ||
1151 | "%s: unable to connect to tdm bus", __func__); | ||
1152 | return ret; | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1076 | ret = devm_request_irq(&pdev->dev, player->irq, | 1156 | ret = devm_request_irq(&pdev->dev, player->irq, |
1077 | uni_player_irq_handler, IRQF_SHARED, | 1157 | uni_player_irq_handler, IRQF_SHARED, |
1078 | dev_name(&pdev->dev), player); | 1158 | dev_name(&pdev->dev), player); |
@@ -1087,7 +1167,7 @@ int uni_player_init(struct platform_device *pdev, | |||
1087 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); | 1167 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); |
1088 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); | 1168 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); |
1089 | 1169 | ||
1090 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { | 1170 | if (UNIPERIF_TYPE_IS_IEC958(player)) { |
1091 | /* Set default iec958 status bits */ | 1171 | /* Set default iec958 status bits */ |
1092 | 1172 | ||
1093 | /* Consumer, PCM, copyright, 2ch, mode 0 */ | 1173 | /* Consumer, PCM, copyright, 2ch, mode 0 */ |
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 8a0eb2050169..eb74a328c928 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c | |||
@@ -73,55 +73,10 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) | |||
73 | return ret; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | 76 | static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, |
77 | struct snd_soc_dai *dai) | 77 | struct uniperif *reader) |
78 | { | 78 | { |
79 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
80 | struct uniperif *reader = priv->dai_data.uni; | ||
81 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
82 | int transfer_size, trigger_limit; | ||
83 | int slot_width; | 79 | int slot_width; |
84 | int count = 10; | ||
85 | |||
86 | /* The reader should be stopped */ | ||
87 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
88 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
89 | reader->state); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
94 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
95 | |||
96 | /* Calculate number of empty cells available before asserting DREQ */ | ||
97 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
98 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
99 | else | ||
100 | /* | ||
101 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
102 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
103 | * from OFF or STANDBY to AUDIO DATA. | ||
104 | */ | ||
105 | trigger_limit = transfer_size; | ||
106 | |||
107 | /* Trigger limit must be an even number */ | ||
108 | if ((!trigger_limit % 2) || | ||
109 | (trigger_limit != 1 && transfer_size % 2) || | ||
110 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
111 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
116 | |||
117 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | ||
118 | case SND_SOC_DAIFMT_IB_IF: | ||
119 | case SND_SOC_DAIFMT_NB_IF: | ||
120 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
121 | break; | ||
122 | default: | ||
123 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
124 | } | ||
125 | 80 | ||
126 | /* Force slot width to 32 in I2S mode */ | 81 | /* Force slot width to 32 in I2S mode */ |
127 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) | 82 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) |
@@ -173,6 +128,109 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, | |||
173 | return -EINVAL; | 128 | return -EINVAL; |
174 | } | 129 | } |
175 | 130 | ||
131 | /* Number of channels must be even */ | ||
132 | if ((runtime->channels % 2) || (runtime->channels < 2) || | ||
133 | (runtime->channels > 10)) { | ||
134 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
139 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int uni_reader_prepare_tdm(struct snd_pcm_runtime *runtime, | ||
145 | struct uniperif *reader) | ||
146 | { | ||
147 | int frame_size; /* user tdm frame size in bytes */ | ||
148 | /* default unip TDM_WORD_POS_X_Y */ | ||
149 | unsigned int word_pos[4] = { | ||
150 | 0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A}; | ||
151 | |||
152 | frame_size = sti_uniperiph_get_user_frame_size(runtime); | ||
153 | |||
154 | /* fix 16/0 format */ | ||
155 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader); | ||
156 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader); | ||
157 | |||
158 | /* number of words inserted on the TDM line */ | ||
159 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, frame_size / 4 / 2); | ||
160 | |||
161 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
162 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | ||
163 | SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(reader); | ||
164 | |||
165 | /* | ||
166 | * set the timeslots allocation for words in FIFO | ||
167 | * | ||
168 | * HW bug: (LSB word < MSB word) => this config is not possible | ||
169 | * So if we want (LSB word < MSB) word, then it shall be | ||
170 | * handled by user | ||
171 | */ | ||
172 | sti_uniperiph_get_tdm_word_pos(reader, word_pos); | ||
173 | SET_UNIPERIF_TDM_WORD_POS(reader, 1_2, word_pos[WORD_1_2]); | ||
174 | SET_UNIPERIF_TDM_WORD_POS(reader, 3_4, word_pos[WORD_3_4]); | ||
175 | SET_UNIPERIF_TDM_WORD_POS(reader, 5_6, word_pos[WORD_5_6]); | ||
176 | SET_UNIPERIF_TDM_WORD_POS(reader, 7_8, word_pos[WORD_7_8]); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | ||
182 | struct snd_soc_dai *dai) | ||
183 | { | ||
184 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
185 | struct uniperif *reader = priv->dai_data.uni; | ||
186 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
187 | int transfer_size, trigger_limit, ret; | ||
188 | int count = 10; | ||
189 | |||
190 | /* The reader should be stopped */ | ||
191 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
192 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
193 | reader->state); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
198 | if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) { | ||
199 | /* transfer size = unip frame size (in 32 bits FIFO cell) */ | ||
200 | transfer_size = | ||
201 | sti_uniperiph_get_user_frame_size(runtime) / 4; | ||
202 | } else { | ||
203 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
204 | } | ||
205 | |||
206 | /* Calculate number of empty cells available before asserting DREQ */ | ||
207 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
208 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
209 | else | ||
210 | /* | ||
211 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
212 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
213 | * from OFF or STANDBY to AUDIO DATA. | ||
214 | */ | ||
215 | trigger_limit = transfer_size; | ||
216 | |||
217 | /* Trigger limit must be an even number */ | ||
218 | if ((!trigger_limit % 2) || | ||
219 | (trigger_limit != 1 && transfer_size % 2) || | ||
220 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
221 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
226 | |||
227 | if (UNIPERIF_TYPE_IS_TDM(reader)) | ||
228 | ret = uni_reader_prepare_tdm(runtime, reader); | ||
229 | else | ||
230 | ret = uni_reader_prepare_pcm(runtime, reader); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | |||
176 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 234 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
177 | case SND_SOC_DAIFMT_I2S: | 235 | case SND_SOC_DAIFMT_I2S: |
178 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | 236 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); |
@@ -191,21 +249,26 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, | |||
191 | return -EINVAL; | 249 | return -EINVAL; |
192 | } | 250 | } |
193 | 251 | ||
194 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | 252 | /* Data clocking (changing) on the rising/falling edge */ |
195 | 253 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | |
196 | /* Data clocking (changing) on the rising edge */ | 254 | case SND_SOC_DAIFMT_NB_NF: |
197 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | 255 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); |
198 | 256 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | |
199 | /* Number of channels must be even */ | 257 | break; |
200 | 258 | case SND_SOC_DAIFMT_NB_IF: | |
201 | if ((runtime->channels % 2) || (runtime->channels < 2) || | 259 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); |
202 | (runtime->channels > 10)) { | 260 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); |
203 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | 261 | break; |
204 | return -EINVAL; | 262 | case SND_SOC_DAIFMT_IB_NF: |
263 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
264 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader); | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_IB_IF: | ||
267 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
268 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader); | ||
269 | break; | ||
205 | } | 270 | } |
206 | 271 | ||
207 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
208 | |||
209 | /* Clear any pending interrupts */ | 272 | /* Clear any pending interrupts */ |
210 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); | 273 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); |
211 | 274 | ||
@@ -293,6 +356,32 @@ static int uni_reader_trigger(struct snd_pcm_substream *substream, | |||
293 | } | 356 | } |
294 | } | 357 | } |
295 | 358 | ||
359 | static int uni_reader_startup(struct snd_pcm_substream *substream, | ||
360 | struct snd_soc_dai *dai) | ||
361 | { | ||
362 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
363 | struct uniperif *reader = priv->dai_data.uni; | ||
364 | int ret; | ||
365 | |||
366 | if (!UNIPERIF_TYPE_IS_TDM(reader)) | ||
367 | return 0; | ||
368 | |||
369 | /* refine hw constraint in tdm mode */ | ||
370 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
371 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
372 | sti_uniperiph_fix_tdm_chan, | ||
373 | reader, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
374 | -1); | ||
375 | if (ret < 0) | ||
376 | return ret; | ||
377 | |||
378 | return snd_pcm_hw_rule_add(substream->runtime, 0, | ||
379 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
380 | sti_uniperiph_fix_tdm_format, | ||
381 | reader, SNDRV_PCM_HW_PARAM_FORMAT, | ||
382 | -1); | ||
383 | } | ||
384 | |||
296 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, | 385 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, |
297 | struct snd_soc_dai *dai) | 386 | struct snd_soc_dai *dai) |
298 | { | 387 | { |
@@ -310,6 +399,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
310 | { | 399 | { |
311 | struct uniperif_info *info; | 400 | struct uniperif_info *info; |
312 | struct device_node *node = pdev->dev.of_node; | 401 | struct device_node *node = pdev->dev.of_node; |
402 | const char *mode; | ||
313 | 403 | ||
314 | /* Allocate memory for the info structure */ | 404 | /* Allocate memory for the info structure */ |
315 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 405 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
@@ -322,6 +412,17 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
322 | return -EINVAL; | 412 | return -EINVAL; |
323 | } | 413 | } |
324 | 414 | ||
415 | /* Read the device mode property */ | ||
416 | if (of_property_read_string(node, "st,mode", &mode)) { | ||
417 | dev_err(&pdev->dev, "uniperipheral mode not defined"); | ||
418 | return -EINVAL; | ||
419 | } | ||
420 | |||
421 | if (strcasecmp(mode, "tdm") == 0) | ||
422 | info->type = SND_ST_UNIPERIF_TYPE_TDM; | ||
423 | else | ||
424 | info->type = SND_ST_UNIPERIF_TYPE_PCM; | ||
425 | |||
325 | /* Save the info structure */ | 426 | /* Save the info structure */ |
326 | reader->info = info; | 427 | reader->info = info; |
327 | 428 | ||
@@ -329,11 +430,13 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
329 | } | 430 | } |
330 | 431 | ||
331 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { | 432 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { |
433 | .startup = uni_reader_startup, | ||
332 | .shutdown = uni_reader_shutdown, | 434 | .shutdown = uni_reader_shutdown, |
333 | .prepare = uni_reader_prepare, | 435 | .prepare = uni_reader_prepare, |
334 | .trigger = uni_reader_trigger, | 436 | .trigger = uni_reader_trigger, |
335 | .hw_params = sti_uniperiph_dai_hw_params, | 437 | .hw_params = sti_uniperiph_dai_hw_params, |
336 | .set_fmt = sti_uniperiph_dai_set_fmt, | 438 | .set_fmt = sti_uniperiph_dai_set_fmt, |
439 | .set_tdm_slot = sti_uniperiph_set_tdm_slot | ||
337 | }; | 440 | }; |
338 | 441 | ||
339 | int uni_reader_init(struct platform_device *pdev, | 442 | int uni_reader_init(struct platform_device *pdev, |
@@ -343,7 +446,6 @@ int uni_reader_init(struct platform_device *pdev, | |||
343 | 446 | ||
344 | reader->dev = &pdev->dev; | 447 | reader->dev = &pdev->dev; |
345 | reader->state = UNIPERIF_STATE_STOPPED; | 448 | reader->state = UNIPERIF_STATE_STOPPED; |
346 | reader->hw = &uni_reader_pcm_hw; | ||
347 | reader->dai_ops = &uni_reader_dai_ops; | 449 | reader->dai_ops = &uni_reader_dai_ops; |
348 | 450 | ||
349 | ret = uni_reader_parse_dt(pdev, reader); | 451 | ret = uni_reader_parse_dt(pdev, reader); |
@@ -352,6 +454,11 @@ int uni_reader_init(struct platform_device *pdev, | |||
352 | return ret; | 454 | return ret; |
353 | } | 455 | } |
354 | 456 | ||
457 | if (UNIPERIF_TYPE_IS_TDM(reader)) | ||
458 | reader->hw = &uni_tdm_hw; | ||
459 | else | ||
460 | reader->hw = &uni_reader_pcm_hw; | ||
461 | |||
355 | ret = devm_request_irq(&pdev->dev, reader->irq, | 462 | ret = devm_request_irq(&pdev->dev, reader->irq, |
356 | uni_reader_irq_handler, IRQF_SHARED, | 463 | uni_reader_irq_handler, IRQF_SHARED, |
357 | dev_name(&pdev->dev), reader); | 464 | dev_name(&pdev->dev), reader); |