aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/qcom
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2016-02-11 07:18:33 -0500
committerMark Brown <broonie@kernel.org>2016-02-19 11:20:18 -0500
commitfb5d11524eda5561f6dd8cc03f9dc778027ce907 (patch)
tree9ba4d2867ddbd2539496c35676c82e5888dd7fbc /sound/soc/qcom
parentdad8061494d2a2ce6edc2ae5ab530b0d330b2685 (diff)
ASoC: qcom: add mic support
This patch adds mic support to the lpass driver, most of the driver is reused as it is, only the register level access is changed depending on te direction of the stream. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Acked-by: Kenneth Westfield <kwestfie@codeaurora.org> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/qcom')
-rw-r--r--sound/soc/qcom/lpass-cpu.c113
-rw-r--r--sound/soc/qcom/lpass-platform.c167
2 files changed, 204 insertions, 76 deletions
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 91774fc87fcc..3cde9fb977fa 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -120,31 +120,60 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
120 return -EINVAL; 120 return -EINVAL;
121 } 121 }
122 122
123 switch (channels) { 123 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
124 case 1: 124 switch (channels) {
125 regval |= LPAIF_I2SCTL_SPKMODE_SD0; 125 case 1:
126 regval |= LPAIF_I2SCTL_SPKMONO_MONO; 126 regval |= LPAIF_I2SCTL_SPKMODE_SD0;
127 break; 127 regval |= LPAIF_I2SCTL_SPKMONO_MONO;
128 case 2: 128 break;
129 regval |= LPAIF_I2SCTL_SPKMODE_SD0; 129 case 2:
130 regval |= LPAIF_I2SCTL_SPKMONO_STEREO; 130 regval |= LPAIF_I2SCTL_SPKMODE_SD0;
131 break; 131 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
132 case 4: 132 break;
133 regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; 133 case 4:
134 regval |= LPAIF_I2SCTL_SPKMONO_STEREO; 134 regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
135 break; 135 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
136 case 6: 136 break;
137 regval |= LPAIF_I2SCTL_SPKMODE_6CH; 137 case 6:
138 regval |= LPAIF_I2SCTL_SPKMONO_STEREO; 138 regval |= LPAIF_I2SCTL_SPKMODE_6CH;
139 break; 139 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
140 case 8: 140 break;
141 regval |= LPAIF_I2SCTL_SPKMODE_8CH; 141 case 8:
142 regval |= LPAIF_I2SCTL_SPKMONO_STEREO; 142 regval |= LPAIF_I2SCTL_SPKMODE_8CH;
143 break; 143 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
144 default: 144 break;
145 dev_err(dai->dev, "%s() invalid channels given: %u\n", 145 default:
146 __func__, channels); 146 dev_err(dai->dev, "%s() invalid channels given: %u\n",
147 return -EINVAL; 147 __func__, channels);
148 return -EINVAL;
149 }
150 } else {
151 switch (channels) {
152 case 1:
153 regval |= LPAIF_I2SCTL_MICMODE_SD0;
154 regval |= LPAIF_I2SCTL_MICMONO_MONO;
155 break;
156 case 2:
157 regval |= LPAIF_I2SCTL_MICMODE_SD0;
158 regval |= LPAIF_I2SCTL_MICMONO_STEREO;
159 break;
160 case 4:
161 regval |= LPAIF_I2SCTL_MICMODE_QUAD01;
162 regval |= LPAIF_I2SCTL_MICMONO_STEREO;
163 break;
164 case 6:
165 regval |= LPAIF_I2SCTL_MICMODE_6CH;
166 regval |= LPAIF_I2SCTL_MICMONO_STEREO;
167 break;
168 case 8:
169 regval |= LPAIF_I2SCTL_MICMODE_8CH;
170 regval |= LPAIF_I2SCTL_MICMONO_STEREO;
171 break;
172 default:
173 dev_err(dai->dev, "%s() invalid channels given: %u\n",
174 __func__, channels);
175 return -EINVAL;
176 }
148 } 177 }
149 178
150 ret = regmap_write(drvdata->lpaif_map, 179 ret = regmap_write(drvdata->lpaif_map,
@@ -188,10 +217,19 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
188{ 217{
189 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 218 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
190 int ret; 219 int ret;
220 unsigned int val, mask;
221
222 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
223 val = LPAIF_I2SCTL_SPKEN_ENABLE;
224 mask = LPAIF_I2SCTL_SPKEN_MASK;
225 } else {
226 val = LPAIF_I2SCTL_MICEN_ENABLE;
227 mask = LPAIF_I2SCTL_MICEN_MASK;
228 }
191 229
192 ret = regmap_update_bits(drvdata->lpaif_map, 230 ret = regmap_update_bits(drvdata->lpaif_map,
193 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 231 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
194 LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); 232 mask, val);
195 if (ret) 233 if (ret)
196 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 234 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
197 __func__, ret); 235 __func__, ret);
@@ -204,16 +242,24 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
204{ 242{
205 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 243 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
206 int ret = -EINVAL; 244 int ret = -EINVAL;
245 unsigned int val, mask;
207 246
208 switch (cmd) { 247 switch (cmd) {
209 case SNDRV_PCM_TRIGGER_START: 248 case SNDRV_PCM_TRIGGER_START:
210 case SNDRV_PCM_TRIGGER_RESUME: 249 case SNDRV_PCM_TRIGGER_RESUME:
211 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 250 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
251 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
252 val = LPAIF_I2SCTL_SPKEN_ENABLE;
253 mask = LPAIF_I2SCTL_SPKEN_MASK;
254 } else {
255 val = LPAIF_I2SCTL_MICEN_ENABLE;
256 mask = LPAIF_I2SCTL_MICEN_MASK;
257 }
258
212 ret = regmap_update_bits(drvdata->lpaif_map, 259 ret = regmap_update_bits(drvdata->lpaif_map,
213 LPAIF_I2SCTL_REG(drvdata->variant, 260 LPAIF_I2SCTL_REG(drvdata->variant,
214 dai->driver->id), 261 dai->driver->id),
215 LPAIF_I2SCTL_SPKEN_MASK, 262 mask, val);
216 LPAIF_I2SCTL_SPKEN_ENABLE);
217 if (ret) 263 if (ret)
218 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 264 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
219 __func__, ret); 265 __func__, ret);
@@ -221,11 +267,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
221 case SNDRV_PCM_TRIGGER_STOP: 267 case SNDRV_PCM_TRIGGER_STOP:
222 case SNDRV_PCM_TRIGGER_SUSPEND: 268 case SNDRV_PCM_TRIGGER_SUSPEND:
223 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 269 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
270 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
271 val = LPAIF_I2SCTL_SPKEN_DISABLE;
272 mask = LPAIF_I2SCTL_SPKEN_MASK;
273 } else {
274 val = LPAIF_I2SCTL_MICEN_DISABLE;
275 mask = LPAIF_I2SCTL_MICEN_MASK;
276 }
277
224 ret = regmap_update_bits(drvdata->lpaif_map, 278 ret = regmap_update_bits(drvdata->lpaif_map,
225 LPAIF_I2SCTL_REG(drvdata->variant, 279 LPAIF_I2SCTL_REG(drvdata->variant,
226 dai->driver->id), 280 dai->driver->id),
227 LPAIF_I2SCTL_SPKEN_MASK, 281 mask, val);
228 LPAIF_I2SCTL_SPKEN_DISABLE);
229 if (ret) 282 if (ret)
230 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 283 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
231 __func__, ret); 284 __func__, ret);
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 348e50bc8891..6e8665430bd5 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -26,6 +26,7 @@
26 26
27struct lpass_pcm_data { 27struct lpass_pcm_data {
28 int rdma_ch; 28 int rdma_ch;
29 int wrdma_ch;
29 int i2s_port; 30 int i2s_port;
30}; 31};
31 32
@@ -90,10 +91,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
90 snd_pcm_format_t format = params_format(params); 91 snd_pcm_format_t format = params_format(params);
91 unsigned int channels = params_channels(params); 92 unsigned int channels = params_channels(params);
92 unsigned int regval; 93 unsigned int regval;
93 int dir = substream->stream; 94 int ch, dir = substream->stream;
94 int bitwidth; 95 int bitwidth;
95 int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; 96 int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
96 97
98 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
99 ch = pcm_data->rdma_ch;
100 else
101 ch = pcm_data->wrdma_ch;
102
97 bitwidth = snd_pcm_format_width(format); 103 bitwidth = snd_pcm_format_width(format);
98 if (bitwidth < 0) { 104 if (bitwidth < 0) {
99 dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n", 105 dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n",
@@ -158,7 +164,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
158 } 164 }
159 165
160 ret = regmap_write(drvdata->lpaif_map, 166 ret = regmap_write(drvdata->lpaif_map,
161 LPAIF_DMACTL_REG(v, pcm_data->rdma_ch, dir), regval); 167 LPAIF_DMACTL_REG(v, ch, dir), regval);
162 if (ret) { 168 if (ret) {
163 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 169 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
164 __func__, ret); 170 __func__, ret);
@@ -175,10 +181,15 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
175 struct lpass_data *drvdata = 181 struct lpass_data *drvdata =
176 snd_soc_platform_get_drvdata(soc_runtime->platform); 182 snd_soc_platform_get_drvdata(soc_runtime->platform);
177 struct lpass_variant *v = drvdata->variant; 183 struct lpass_variant *v = drvdata->variant;
184 unsigned int reg;
178 int ret; 185 int ret;
179 186
180 ret = regmap_write(drvdata->lpaif_map, 187 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
181 LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0); 188 reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch);
189 else
190 reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch);
191
192 ret = regmap_write(drvdata->lpaif_map, reg, 0);
182 if (ret) 193 if (ret)
183 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 194 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
184 __func__, ret); 195 __func__, ret);
@@ -194,11 +205,15 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
194 struct lpass_data *drvdata = 205 struct lpass_data *drvdata =
195 snd_soc_platform_get_drvdata(soc_runtime->platform); 206 snd_soc_platform_get_drvdata(soc_runtime->platform);
196 struct lpass_variant *v = drvdata->variant; 207 struct lpass_variant *v = drvdata->variant;
197 int ret, ch = pcm_data->rdma_ch; 208 int ret, ch, dir = substream->stream;
198 int dir = substream->stream; 209
210 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
211 ch = pcm_data->rdma_ch;
212 else
213 ch = pcm_data->wrdma_ch;
199 214
200 ret = regmap_write(drvdata->lpaif_map, 215 ret = regmap_write(drvdata->lpaif_map,
201 LPAIF_RDMABASE_REG(v, ch), 216 LPAIF_DMABASE_REG(v, ch, dir),
202 runtime->dma_addr); 217 runtime->dma_addr);
203 if (ret) { 218 if (ret) {
204 dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", 219 dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -244,8 +259,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
244 struct lpass_data *drvdata = 259 struct lpass_data *drvdata =
245 snd_soc_platform_get_drvdata(soc_runtime->platform); 260 snd_soc_platform_get_drvdata(soc_runtime->platform);
246 struct lpass_variant *v = drvdata->variant; 261 struct lpass_variant *v = drvdata->variant;
247 int ret, ch = pcm_data->rdma_ch; 262 int ret, ch, dir = substream->stream;
248 int dir = substream->stream; 263
264 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
265 ch = pcm_data->rdma_ch;
266 else
267 ch = pcm_data->wrdma_ch;
249 268
250 switch (cmd) { 269 switch (cmd) {
251 case SNDRV_PCM_TRIGGER_START: 270 case SNDRV_PCM_TRIGGER_START:
@@ -317,8 +336,12 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
317 snd_soc_platform_get_drvdata(soc_runtime->platform); 336 snd_soc_platform_get_drvdata(soc_runtime->platform);
318 struct lpass_variant *v = drvdata->variant; 337 struct lpass_variant *v = drvdata->variant;
319 unsigned int base_addr, curr_addr; 338 unsigned int base_addr, curr_addr;
320 int ret, ch = pcm_data->rdma_ch; 339 int ret, ch, dir = substream->stream;
321 int dir = substream->stream; 340
341 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
342 ch = pcm_data->rdma_ch;
343 else
344 ch = pcm_data->wrdma_ch;
322 345
323 ret = regmap_read(drvdata->lpaif_map, 346 ret = regmap_read(drvdata->lpaif_map,
324 LPAIF_DMABASE_REG(v, ch, dir), &base_addr); 347 LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
@@ -446,8 +469,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
446static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) 469static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
447{ 470{
448 struct snd_pcm *pcm = soc_runtime->pcm; 471 struct snd_pcm *pcm = soc_runtime->pcm;
449 struct snd_pcm_substream *substream = 472 struct snd_pcm_substream *psubstream, *csubstream;
450 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
451 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; 473 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
452 struct lpass_data *drvdata = 474 struct lpass_data *drvdata =
453 snd_soc_platform_get_drvdata(soc_runtime->platform); 475 snd_soc_platform_get_drvdata(soc_runtime->platform);
@@ -460,55 +482,108 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
460 if (!data) 482 if (!data)
461 return -ENOMEM; 483 return -ENOMEM;
462 484
463 if (v->alloc_dma_channel) 485 data->i2s_port = cpu_dai->driver->id;
464 data->rdma_ch = v->alloc_dma_channel(drvdata, 486 snd_soc_pcm_set_drvdata(soc_runtime, data);
465 SNDRV_PCM_STREAM_PLAYBACK);
466 487
467 if (IS_ERR_VALUE(data->rdma_ch)) 488 psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
468 return data->rdma_ch; 489 if (psubstream) {
490 if (v->alloc_dma_channel)
491 data->rdma_ch = v->alloc_dma_channel(drvdata,
492 SNDRV_PCM_STREAM_PLAYBACK);
469 493
470 drvdata->substream[data->rdma_ch] = substream; 494 if (IS_ERR_VALUE(data->rdma_ch))
471 data->i2s_port = cpu_dai->driver->id; 495 return data->rdma_ch;
472 496
473 snd_soc_pcm_set_drvdata(soc_runtime, data); 497 drvdata->substream[data->rdma_ch] = psubstream;
474 498
475 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, 499 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
476 soc_runtime->platform->dev, 500 soc_runtime->platform->dev,
477 size, &substream->dma_buffer); 501 size, &psubstream->dma_buffer);
478 if (ret) 502 if (ret)
479 return ret; 503 goto playback_alloc_err;
480 504
481 ret = regmap_write(drvdata->lpaif_map, 505 ret = regmap_write(drvdata->lpaif_map,
482 LPAIF_RDMACTL_REG(v, data->rdma_ch), 0); 506 LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
483 if (ret) { 507 if (ret) {
484 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 508 dev_err(soc_runtime->dev,
509 "%s() error writing to rdmactl reg: %d\n",
485 __func__, ret); 510 __func__, ret);
486 goto err_buf; 511 goto capture_alloc_err;
512 }
513 }
514
515 csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
516 if (csubstream) {
517 if (v->alloc_dma_channel)
518 data->wrdma_ch = v->alloc_dma_channel(drvdata,
519 SNDRV_PCM_STREAM_CAPTURE);
520
521 if (IS_ERR_VALUE(data->wrdma_ch))
522 goto capture_alloc_err;
523
524 drvdata->substream[data->wrdma_ch] = csubstream;
525
526 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
527 soc_runtime->platform->dev,
528 size, &csubstream->dma_buffer);
529 if (ret)
530 goto capture_alloc_err;
531
532 ret = regmap_write(drvdata->lpaif_map,
533 LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0);
534 if (ret) {
535 dev_err(soc_runtime->dev,
536 "%s() error writing to wrdmactl reg: %d\n",
537 __func__, ret);
538 goto capture_reg_err;
539 }
487 } 540 }
488 541
489 return 0; 542 return 0;
490 543
491err_buf: 544capture_reg_err:
492 snd_dma_free_pages(&substream->dma_buffer); 545 if (csubstream)
546 snd_dma_free_pages(&csubstream->dma_buffer);
547
548capture_alloc_err:
549 if (psubstream)
550 snd_dma_free_pages(&psubstream->dma_buffer);
551
552 playback_alloc_err:
553 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
554
493 return ret; 555 return ret;
494} 556}
495 557
496static void lpass_platform_pcm_free(struct snd_pcm *pcm) 558static void lpass_platform_pcm_free(struct snd_pcm *pcm)
497{ 559{
498 struct snd_pcm_substream *substream = 560 struct snd_soc_pcm_runtime *rt;
499 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 561 struct lpass_data *drvdata;
500 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 562 struct lpass_pcm_data *data;
501 struct lpass_data *drvdata = 563 struct lpass_variant *v;
502 snd_soc_platform_get_drvdata(soc_runtime->platform); 564 struct snd_pcm_substream *substream;
503 struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime); 565 int ch, i;
504 struct lpass_variant *v = drvdata->variant; 566
505 567 for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
506 drvdata->substream[data->rdma_ch] = NULL; 568 substream = pcm->streams[i].substream;
507 569 if (substream) {
508 if (v->free_dma_channel) 570 rt = substream->private_data;
509 v->free_dma_channel(drvdata, data->rdma_ch); 571 data = snd_soc_pcm_get_drvdata(rt);
510 572 drvdata = snd_soc_platform_get_drvdata(rt->platform);
511 snd_dma_free_pages(&substream->dma_buffer); 573
574 ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
575 ? data->rdma_ch
576 : data->wrdma_ch;
577 v = drvdata->variant;
578 drvdata->substream[ch] = NULL;
579 if (v->free_dma_channel)
580 v->free_dma_channel(drvdata, ch);
581
582 snd_dma_free_pages(&substream->dma_buffer);
583 substream->dma_buffer.area = NULL;
584 substream->dma_buffer.addr = 0;
585 }
586 }
512} 587}
513 588
514static struct snd_soc_platform_driver lpass_platform_driver = { 589static struct snd_soc_platform_driver lpass_platform_driver = {