1 /*
2 * omap-abe.c -- OMAP ALSA SoC DAI driver using Audio Backend
3 *
4 * Copyright (C) 2010 Texas Instruments
5 *
6 * Contact: Liam Girdwood <lrg@ti.com>
7 * Misael Lopez Cruz <misael.lopez@ti.com>
8 * Sebastien Guiriec <s-guiriec@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/platform_device.h>
29 #include <linux/slab.h>
30 #include <linux/pm_runtime.h>
31 #include <linux/firmware.h>
32 #include <linux/debugfs.h>
33 #include <linux/opp.h>
34 #include <linux/dma-mapping.h>
35 #include <linux/of_device.h>
37 #include <sound/soc.h>
38 #include <sound/soc-fw.h>
39 #include "../../../arch/arm/mach-omap2/omap-pm.h"
41 #include "omap-abe-priv.h"
43 int abe_opp_stream_event(struct snd_soc_dapm_context *dapm, int event);
44 int abe_pm_suspend(struct snd_soc_dai *dai);
45 int abe_pm_resume(struct snd_soc_dai *dai);
47 irqreturn_t abe_irq_handler(int irq, void *dev_id);
48 void abe_init_debugfs(struct omap_abe *abe);
49 void abe_cleanup_debugfs(struct omap_abe *abe);
50 int abe_opp_init_initial_opp(struct omap_abe *abe);
51 extern struct snd_pcm_ops omap_aess_pcm_ops;
52 extern struct snd_soc_dai_driver omap_abe_dai[6];
54 static u64 omap_abe_dmamask = DMA_BIT_MASK(32);
56 static const char *abe_memory_bank[5] = {
57 "dmem",
58 "cmem",
59 "smem",
60 "pmem",
61 "mpu"
62 };
64 /* TODO: map IO directly into ABE memories */
65 static unsigned int omap_abe_oppwidget_read(struct snd_soc_platform *platform,
66 unsigned int reg)
67 {
68 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
70 if (reg > OMAP_ABE_NUM_DAPM_REG)
71 return 0;
73 dev_dbg(platform->dev, "read R%d (Ox%x) = 0x%x\n",
74 reg, reg, abe->opp.widget[reg]);
75 return abe->opp.widget[reg];
76 }
78 static int omap_abe_oppwidget_write(struct snd_soc_platform *platform, unsigned int reg,
79 unsigned int val)
80 {
81 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
83 if (reg > OMAP_ABE_NUM_DAPM_REG)
84 return 0;
86 abe->opp.widget[reg] = val;
87 dev_dbg(platform->dev, "write R%d (Ox%x) = 0x%x\n", reg, reg, val);
88 return 0;
89 }
92 static void abe_init_gains(struct omap_aess *abe)
93 {
94 /* Uplink gains */
95 omap_aess_mute_gain(abe, OMAP_AESS_MIXAUDUL_MM_DL);
96 omap_aess_mute_gain(abe, OMAP_AESS_MIXAUDUL_TONES);
97 omap_aess_mute_gain(abe, OMAP_AESS_MIXAUDUL_UPLINK);
98 omap_aess_mute_gain(abe, OMAP_AESS_MIXAUDUL_VX_DL);
99 omap_aess_mute_gain(abe, OMAP_AESS_MIXVXREC_TONES);
100 omap_aess_mute_gain(abe, OMAP_AESS_MIXVXREC_VX_DL);
101 omap_aess_mute_gain(abe, OMAP_AESS_MIXVXREC_MM_DL);
102 omap_aess_mute_gain(abe, OMAP_AESS_MIXVXREC_VX_UL);
103 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DMIC1_LEFT);
104 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DMIC1_RIGHT);
105 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DMIC2_LEFT);
106 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DMIC2_RIGHT);
107 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DMIC3_LEFT);
108 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DMIC3_RIGHT);
110 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_AMIC_LEFT);
111 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_AMIC_RIGHT);
113 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_BTUL_LEFT);
114 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_BTUL_RIGHT);
116 /* Downlink gains */
117 omap_aess_write_gain(abe, OMAP_AESS_GAIN_DL1_LEFT, GAIN_0dB);
118 omap_aess_write_gain(abe, OMAP_AESS_GAIN_DL1_RIGHT, GAIN_0dB);
119 /*SEBG: Ramp RAMP_2MS */
121 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DL1_LEFT);
122 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DL1_RIGHT);
124 omap_aess_write_gain(abe, OMAP_AESS_GAIN_DL2_LEFT, GAIN_M7dB);
125 omap_aess_write_gain(abe, OMAP_AESS_GAIN_DL2_RIGHT, GAIN_M7dB);
126 /*SEBG: Ramp RAMP_2MS */
128 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DL2_LEFT);
129 omap_aess_mute_gain(abe, OMAP_AESS_GAIN_DL2_RIGHT);
130 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL1_MM_DL);
131 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL1_MM_UL2);
132 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL1_VX_DL);
133 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL1_TONES);
134 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL2_TONES);
135 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL2_VX_DL);
136 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL2_MM_DL);
137 omap_aess_mute_gain(abe, OMAP_AESS_MIXDL2_MM_UL2);
138 omap_aess_mute_gain(abe, OMAP_AESS_MIXECHO_DL1);
139 omap_aess_mute_gain(abe, OMAP_AESS_MIXECHO_DL2);
141 /* Sidetone gains */
142 omap_aess_mute_gain(abe, OMAP_AESS_MIXSDT_UL);
143 omap_aess_mute_gain(abe, OMAP_AESS_MIXSDT_DL);
144 }
146 static int abe_load_coeffs(struct snd_soc_platform *platform,
147 struct snd_soc_fw_hdr *hdr)
148 {
149 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
150 const struct snd_soc_file_coeff_data *cd = snd_soc_fw_get_data(hdr);
151 const void *coeff_data = cd + 1;
153 dev_dbg(platform->dev,"coeff %d size 0x%x with %d elems\n",
154 cd->id, cd->size, cd->count);
156 switch (cd->id) {
157 case OMAP_AESS_CMEM_DL1_COEFS_ID:
158 abe->equ.dl1.profile_size = cd->size / cd->count;
159 abe->equ.dl1.num_profiles = cd->count;
160 abe->equ.dl1.coeff_data = kmalloc(cd->size, GFP_KERNEL);
161 if (abe->equ.dl1.coeff_data == NULL)
162 return -ENOMEM;
163 memcpy(abe->equ.dl1.coeff_data, coeff_data, cd->size);
164 break;
165 case OMAP_AESS_CMEM_DL2_L_COEFS_ID:
166 abe->equ.dl2l.profile_size = cd->size / cd->count;
167 abe->equ.dl2l.num_profiles = cd->count;
168 abe->equ.dl2l.coeff_data = kmalloc(cd->size, GFP_KERNEL);
169 if (abe->equ.dl2l.coeff_data == NULL)
170 return -ENOMEM;
171 memcpy(abe->equ.dl2l.coeff_data, coeff_data, cd->size);
172 break;
173 case OMAP_AESS_CMEM_DL2_R_COEFS_ID:
174 abe->equ.dl2r.profile_size = cd->size / cd->count;
175 abe->equ.dl2r.num_profiles = cd->count;
176 abe->equ.dl2r.coeff_data = kmalloc(cd->size, GFP_KERNEL);
177 if (abe->equ.dl2r.coeff_data == NULL)
178 return -ENOMEM;
179 memcpy(abe->equ.dl2r.coeff_data, coeff_data, cd->size);
180 break;
181 case OMAP_AESS_CMEM_SDT_COEFS_ID:
182 abe->equ.sdt.profile_size = cd->size / cd->count;
183 abe->equ.sdt.num_profiles = cd->count;
184 abe->equ.sdt.coeff_data = kmalloc(cd->size, GFP_KERNEL);
185 if (abe->equ.sdt.coeff_data == NULL)
186 return -ENOMEM;
187 memcpy(abe->equ.sdt.coeff_data, coeff_data, cd->size);
188 break;
189 case OMAP_AESS_CMEM_96_48_AMIC_COEFS_ID:
190 abe->equ.amic.profile_size = cd->size / cd->count;
191 abe->equ.amic.num_profiles = cd->count;
192 abe->equ.amic.coeff_data = kmalloc(cd->size, GFP_KERNEL);
193 if (abe->equ.amic.coeff_data == NULL)
194 return -ENOMEM;
195 memcpy(abe->equ.amic.coeff_data, coeff_data, cd->size);
196 break;
197 case OMAP_AESS_CMEM_96_48_DMIC_COEFS_ID:
198 abe->equ.dmic.profile_size = cd->size / cd->count;
199 abe->equ.dmic.num_profiles = cd->count;
200 abe->equ.dmic.coeff_data = kmalloc(cd->size, GFP_KERNEL);
201 if (abe->equ.dmic.coeff_data == NULL)
202 return -ENOMEM;
203 memcpy(abe->equ.dmic.coeff_data, coeff_data, cd->size);
204 break;
205 default:
206 dev_err(platform->dev, "invalid coefficient ID %d\n", cd->id);
207 return -EINVAL;
208 }
210 return 0;
211 }
213 static int abe_load_fw(struct snd_soc_platform *platform,
214 struct snd_soc_fw_hdr *hdr)
215 {
216 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
217 const void *fw_data = snd_soc_fw_get_data(hdr);
219 /* get firmware and coefficients header info */
220 memcpy(&abe->hdr, fw_data, sizeof(struct fw_header));
221 if (hdr->size > OMAP_ABE_MAX_FW_SIZE) {
222 dev_err(abe->dev, "Firmware too large at %d bytes\n",
223 hdr->size);
224 return -ENOMEM;
225 }
226 dev_info(abe->dev, "ABE firmware size %d bytes\n", hdr->size);
227 dev_info(abe->dev, "ABE mem P %d C %d D %d S %d bytes\n",
228 abe->hdr.pmem_size, abe->hdr.cmem_size,
229 abe->hdr.dmem_size, abe->hdr.smem_size);
231 dev_info(abe->dev, "ABE Firmware version %x\n", abe->hdr.version);
232 #if 0
233 if (omap_abe_get_supported_fw_version() <= abe->hdr.firmware_version) {
234 dev_err(abe->dev, "firmware version too old. Need %x have %x\n",
235 omap_abe_get_supported_fw_version(),
236 abe->hdr.firmware_version);
237 return -EINVAL;
238 }
239 #endif
240 /* store ABE firmware for later context restore */
241 abe->fw_data = fw_data;
243 return 0;
244 }
246 static int abe_load_config(struct snd_soc_platform *platform,
247 struct snd_soc_fw_hdr *hdr)
248 {
249 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
250 const void *fw_data = snd_soc_fw_get_data(hdr);
252 /* store ABE config for later context restore */
253 dev_info(abe->dev, "ABE Config size %d bytes\n", hdr->size);
255 abe->fw_config = fw_data;
257 return 0;
258 }
260 static void abe_free_fw(struct omap_abe *abe)
261 {
262 /* This below should be done in HAL - oposite of init_mem()*/
263 if (!abe->aess)
264 return;
266 if (abe->aess->fw_info) {
267 kfree(abe->aess->fw_info);
268 }
269 }
271 /* callback to handle vendor data */
272 static int abe_vendor_load(struct snd_soc_platform *platform,
273 struct snd_soc_fw_hdr *hdr)
274 {
276 switch (hdr->type) {
277 case SND_SOC_FW_VENDOR_FW:
278 return abe_load_fw(platform, hdr);
279 case SND_SOC_FW_VENDOR_CONFIG:
280 return abe_load_config(platform, hdr);
281 case SND_SOC_FW_COEFF:
282 return abe_load_coeffs(platform, hdr);
283 case SND_SOC_FW_VENDOR_CODEC:
284 default:
285 dev_err(platform->dev, "vendor type %d:%d not supported\n",
286 hdr->type, hdr->vendor_type);
287 return 0;
288 }
289 return 0;
290 }
292 static struct snd_soc_fw_platform_ops soc_fw_ops = {
293 .vendor_load = abe_vendor_load,
294 .io_ops = abe_ops,
295 .io_ops_count = 7,
296 };
298 static int abe_probe(struct snd_soc_platform *platform)
299 {
300 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
301 int ret = 0, i;
303 pm_runtime_enable(abe->dev);
304 pm_runtime_irq_safe(abe->dev);
306 ret = snd_soc_fw_load_platform(platform, &soc_fw_ops, abe->fw, 0);
307 if (ret < 0) {
308 dev_err(platform->dev, "request for ABE FW failed %d\n", ret);
309 goto err_fw;
310 }
312 ret = devm_request_threaded_irq(abe->dev, abe->irq, NULL, abe_irq_handler,
313 IRQF_ONESHOT, "ABE", (void *)abe);
314 if (ret) {
315 dev_err(platform->dev, "request for ABE IRQ %d failed %d\n",
316 abe->irq, ret);
317 goto err_irq;
318 }
320 ret = abe_opp_init_initial_opp(abe);
321 if (ret < 0) {
322 dev_info(platform->dev, "No OPP definition\n");
323 ret = 0;
324 }
325 /* aess_clk has to be enabled to access hal register.
326 * Disable the clk after it has been used.
327 */
328 pm_runtime_get_sync(abe->dev);
330 /* lrg - rework for better init flow */
331 abe->aess = omap_abe_port_mgr_get();
332 omap_aess_init_mem(abe->aess, abe->dev, abe->io_base, abe->fw_config);
334 omap_aess_reset_hal(abe->aess);
336 /* ZERO_labelID should really be 0 */
337 for (i = 0; i < OMAP_ABE_ROUTES_UL + 2; i++)
338 abe->mixer.route_ul[i] = abe->aess->fw_info->label_id[OMAP_AESS_BUFFER_ZERO_ID];
340 omap_aess_load_fw(abe->aess, abe->fw_data);
342 /* "tick" of the audio engine */
343 omap_aess_write_event_generator(abe->aess, EVENT_TIMER);
344 abe_init_gains(abe->aess);
346 /* Stop the engine */
347 omap_aess_stop_event_generator(abe->aess);
348 omap_aess_disable_irq(abe->aess);
350 pm_runtime_put_sync(abe->dev);
351 abe_init_debugfs(abe);
353 return ret;
355 err_irq:
356 abe_free_fw(abe);
357 err_fw:
358 pm_runtime_disable(abe->dev);
359 return ret;
360 }
362 static int abe_remove(struct snd_soc_platform *platform)
363 {
364 struct omap_abe *abe = snd_soc_platform_get_drvdata(platform);
366 abe_cleanup_debugfs(abe);
367 abe_free_fw(abe);
368 pm_runtime_disable(abe->dev);
370 return 0;
371 }
373 static struct snd_soc_platform_driver omap_aess_platform = {
374 .ops = &omap_aess_pcm_ops,
375 .probe = abe_probe,
376 .remove = abe_remove,
377 .suspend = abe_pm_suspend,
378 .resume = abe_pm_resume,
379 .read = omap_abe_oppwidget_read,
380 .write = omap_abe_oppwidget_write,
381 .stream_event = abe_opp_stream_event,
382 };
384 #ifndef CONFIG_SND_OMAP_SOC_ABE_MODULE
385 void driver_deferred_probe_trigger(void);
386 #endif
388 static void abe_fw_ready(const struct firmware *fw, void *context)
389 {
390 struct platform_device *pdev = (struct platform_device *)context;
391 struct omap_abe *abe = dev_get_drvdata(&pdev->dev);
392 int err;
394 abe->fw = fw;
396 err = snd_soc_register_platform(&pdev->dev, &omap_aess_platform);
397 if (err < 0) {
398 dev_err(&pdev->dev, "failed to register ABE platform %d\n", err);
399 release_firmware(fw);
400 return;
401 }
403 err = snd_soc_register_dais(&pdev->dev, omap_abe_dai,
404 ARRAY_SIZE(omap_abe_dai));
405 if (err < 0) {
406 dev_err(&pdev->dev, "failed to register ABE DAIs %d\n", err);
407 snd_soc_unregister_platform(&pdev->dev);
408 release_firmware(fw);
409 }
410 #ifndef CONFIG_SND_OMAP_SOC_ABE_MODULE
411 driver_deferred_probe_trigger();
412 #endif
413 }
415 static int abe_engine_probe(struct platform_device *pdev)
416 {
417 struct resource *res;
418 struct omap_abe *abe;
419 int ret, i;
421 abe = devm_kzalloc(&pdev->dev, sizeof(struct omap_abe), GFP_KERNEL);
422 if (abe == NULL)
423 return -ENOMEM;
425 for (i = 0; i < OMAP_ABE_IO_RESOURCES; i++) {
426 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
427 abe_memory_bank[i]);
428 if (res == NULL) {
429 dev_err(&pdev->dev, "no resource %s\n",
430 abe_memory_bank[i]);
431 return -ENODEV;
432 }
433 if (!devm_request_mem_region(&pdev->dev, res->start,
434 resource_size(res), abe_memory_bank[i]))
435 return -EBUSY;
437 abe->io_base[i] = devm_ioremap(&pdev->dev, res->start,
438 resource_size(res));
439 if (!abe->io_base[i])
440 return -ENOMEM;
441 }
443 for (i = 0; i < OMAP_ABE_DMA_RESOURCES; i++) {
444 char name[8];
446 sprintf(name, "fifo%d", i);
447 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, name);
448 if (res == NULL) {
449 dev_err(&pdev->dev, "no resource %s\n", name);
450 return -ENODEV;
451 }
452 abe->dma_lines[i] = res->start;
453 }
455 abe->irq = platform_get_irq(pdev, 0);
456 if (abe->irq < 0)
457 return abe->irq;
459 dev_set_drvdata(&pdev->dev, abe);
461 #ifdef CONFIG_PM
462 abe->get_context_lost_count = omap_pm_get_dev_context_loss_count;
463 abe->device_scale = NULL;
464 #endif
465 abe->dev = &pdev->dev;
467 mutex_init(&abe->mutex);
468 mutex_init(&abe->opp.mutex);
469 mutex_init(&abe->opp.req_mutex);
470 INIT_LIST_HEAD(&abe->opp.req);
472 get_device(abe->dev);
473 abe->dev->dma_mask = &omap_abe_dmamask;
474 abe->dev->coherent_dma_mask = omap_abe_dmamask;
475 put_device(abe->dev);
477 ret = request_firmware_nowait(THIS_MODULE, 1, "omap4_abe_new", abe->dev,
478 GFP_KERNEL, pdev, abe_fw_ready);
479 if (!ret)
480 dev_err(abe->dev, "Failed to load firmware %d\n", ret);
482 return ret;
483 }
485 static int abe_engine_remove(struct platform_device *pdev)
486 {
487 struct omap_abe *abe = dev_get_drvdata(&pdev->dev);
489 snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_abe_dai));
490 snd_soc_unregister_platform(&pdev->dev);
492 abe->fw_data = NULL;
493 abe->fw_config = NULL;
494 release_firmware(abe->fw);
496 return 0;
497 }
499 static const struct of_device_id omap_aess_of_match[] = {
500 { .compatible = "ti,omap4-aess", },
501 { }
502 };
503 MODULE_DEVICE_TABLE(of, omap_aess_of_match);
505 static struct platform_driver omap_aess_driver = {
506 .driver = {
507 .name = "aess",
508 .owner = THIS_MODULE,
509 .of_match_table = omap_aess_of_match,
510 },
511 .probe = abe_engine_probe,
512 .remove = abe_engine_remove,
513 };
515 module_platform_driver(omap_aess_driver);
517 MODULE_ALIAS("platform:omap-aess");
518 MODULE_DESCRIPTION("ASoC OMAP4 ABE");
519 MODULE_AUTHOR("Liam Girdwood <lrg@ti.com>");
520 MODULE_LICENSE("GPL");