]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blob - sound/soc/omap/omap-abe-core.c
ASoC: OMAP: ABE: Pick working ABE support from LDC audio branch
[android-sdk/kernel-video.git] / sound / soc / omap / omap-abe-core.c
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);
146 static int abe_load_coeffs(struct snd_soc_platform *platform,
147         struct snd_soc_fw_hdr *hdr)
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;
213 static int abe_load_fw(struct snd_soc_platform *platform,
214         struct snd_soc_fw_hdr *hdr)
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;
246 static int abe_load_config(struct snd_soc_platform *platform,
247         struct snd_soc_fw_hdr *hdr)
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;
260 static void abe_free_fw(struct omap_abe *abe)
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         }
271 /* callback to handle vendor data */
272 static int abe_vendor_load(struct snd_soc_platform *platform,
273         struct snd_soc_fw_hdr *hdr)
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;
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)
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;
362 static int abe_remove(struct snd_soc_platform *platform)
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;
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)
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
415 static int abe_engine_probe(struct platform_device *pdev)
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;
485 static int abe_engine_remove(struct platform_device *pdev)
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;
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");