Other Parts Discussed in Thread: TLV320AIC3104
Tool/software: Linux
I need simultaneous stereo audio output and input.
I'm using Linux kernel 4.4.83-ti-rt-r119 on a BeagleBone Black card (AM3358 processor) with a TLV320AIC3104 audio codec attached to MCASP0 and I2C2 ports. I´m using the snd_soc_davinci_mcasp, snd_soc_tlv320aic31x, and snd_soc_simple_card drivers with no modifications. Stereo audio playback works just fine and alsamixer controls make perfect sense with the codec's datasheet. I can't, however get any sound input on userland apps in Linux. Here's what I'm doing:
First, I load the following device tree during boot.
/* * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /dts-v1/; #include "am33xx.dtsi" #include "am335x-bone-common.dtsi" /* #include "am33xx-overlay-edma-fix.dtsi" */ &spi0 { status = "okay"; }; &spi1 { status = "okay"; }; &mcasp1 { status = "okay"; tdm-slots = <2>; }; /* pruss: pick one: */ /* * /etc/modprobe.d/pruss-blacklist.conf * * blacklist uio_pruss */ #include "am33xx-pruss-rproc.dtsi" /* * /etc/modprobe.d/pruss-blacklist.conf * * blacklist pruss * blacklist pruss_intc * blacklist pru-rproc */ /* #include "am33xx-pruss-uio.dtsi" */ &am33xx_pinmux { mostro_audio_pins: pinmux_mostro_audio_pins { pinctrl-single,pins = < 0x190 0x20 /* BCLK P9.31 MUX_MODE0 (mcasp0_aclkx), INPUT_PULLDOWN */ 0x194 0x20 /* WCLK P9.29 MUX_MODE0 (mcasp0_fsx), INPUT_PULLDOWN */ 0x198 0x20 /* DIN P9.30 MUX_MODE0 (mcasp0_axr0), INPUT_PULLDOWN */ 0x19c 0x02 /* DOUT P9.28 MUX_MODE2 (mcasp0_axr2), OUTPUT_PULLDOWN */ 0x1ac 0x00 /* MCLK P9.25 MUX_MODE0 (mcasp0_ahclkx), OUTPUT_PULLDOWN ) */ >; }; }; &i2c2 { #address-cells = <1>; #size-cells = <0>; clock-frequency = <100000>; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&i2c2_pins>; /* These are defined in am335x-bone-common.dtsi, P9.19 and P9.20 */ tlv320aic3104: tlv320aic3104@18 { #sound-dai-cells = <0>; compatible = "ti,tlv320aic3104"; reg = <0x18>; AVDD-supply = <&ldo2_reg>; // 3.3V voltage regulator defined in am335x-bone-common.dtsi IOVDD-supply = <&ldo2_reg>; DRVDD-supply = <&ldo2_reg>; DVDD-supply = <&ldo2_reg>; }; }; &mcasp0 { #sound-dai-cells = <0>; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mostro_audio_pins>; op-mode = <0>; /* MCASP_IIS_MODE */ tdm-slots = <2>; num-serializer = <16>; serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 >; tx-num-evt = <1>; rx-num-evt = <1>; /* interrupts = <80>, <81>; */ /* interrupt-names = "tx", "rx"; */ /* dmas = <&edma 8 2>, */ /* <&edma 9 2>; */ /* dma-names = "tx", "rx"; */ }; &ldo3_reg { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-always-on; }; &mmc1 { vmmc-supply = <&vmmcsd_fixed>; }; &mmc2 { vmmc-supply = <&vmmcsd_fixed>; pinctrl-names = "default"; pinctrl-0 = <&emmc_pins>; bus-width = <8>; status = "okay"; }; &cpu0_opp_table { /* * All PG 2.0 silicon may not support 1GHz but some of the early * BeagleBone Blacks have PG 2.0 silicon which is guaranteed * to support 1GHz OPP so enable it for PG 2.0 on this board. */ oppnitro@1000000000 { opp-supported-hw = <0x06 0x0100>; }; }; / { model = "TI AM335x BeagleBone Green"; compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx"; clk_mcasp0_fixed: clk_mcasp0_fixed { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24576000>; }; clk_mcasp0: clk_mcasp0 { #clock-cells = <0>; compatible = "gpio-gate-clock"; clocks = <&clk_mcasp0_fixed>; enable-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>; /* BeagleBone Black Clk enable on GPIO1_27 */ }; sound { compatible = "simple-audio-card"; simple-audio-card,name = "Mostro Audio"; simple-audio-card,widgets = "Headphone", "Headphone Jack", "Line", "Line In Jack"; simple-audio-card,routing = "Headphone Jack", "HPLOUT", "Headphone Jack", "HPROUT", "LINE1L", "Line In Jack", "LINE1R", "Line In Jack"; simple-audio-card,format = "dsp_b"; simple-audio-card,bitclock-master = <&sound_master>; simple-audio-card,frame-master = <&sound_master>; simple-audio-card,bitclock-inversion; simple-audio-card,cpu { sound-dai = <&mcasp0>; }; sound_master: simple-audio-card,codec { #sound-dai-cells = <0>; sound-dai = <&tlv320aic3104>; clocks = <&clk_mcasp0>; clock-names = "mclk"; }; }; };
Then, I load the modules:
modprobe snd_soc_tlv320aic3x
modprobe snd_soc_davinci_mcasp
modprobe snd_soc_simple_card
Then, I load alsamixer values with `alsactl restore`. Here are the contents of the asound.state file (created by `alsactl store`):
state.Audio { control.1 { iface MIXER name 'PCM Playback Volume' value.0 127 value.1 127 comment { access 'read write' type INTEGER count 2 range '0 - 127' dbmin -6350 dbmax 0 dbvalue.0 0 dbvalue.1 0 } } control.2 { iface MIXER name 'Left Line Mixer PGAR Bypass Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.3 { iface MIXER name 'Left Line Mixer DACR1 Playback Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.4 { iface MIXER name 'Right Line Mixer PGAL Bypass Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.5 { iface MIXER name 'Right Line Mixer DACL1 Playback Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.6 { iface MIXER name 'Left HP Mixer PGAR Bypass Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.7 { iface MIXER name 'Left HP Mixer DACR1 Playback Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.8 { iface MIXER name 'Right HP Mixer PGAL Bypass Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.9 { iface MIXER name 'Right HP Mixer DACL1 Playback Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.10 { iface MIXER name 'Left HPCOM Mixer PGAR Bypass Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.11 { iface MIXER name 'Left HPCOM Mixer DACR1 Playback Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.12 { iface MIXER name 'Right HPCOM Mixer PGAL Bypass Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.13 { iface MIXER name 'Right HPCOM Mixer DACL1 Playback Volume' value 0 comment { access 'read write' type INTEGER count 1 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 } } control.14 { iface MIXER name 'Line PGA Bypass Volume' value.0 0 value.1 0 comment { access 'read write' type INTEGER count 2 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 dbvalue.1 -9999999 } } control.15 { iface MIXER name 'Line DAC Playback Volume' value.0 118 value.1 118 comment { access 'read write' type INTEGER count 2 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 0 dbvalue.1 0 } } control.16 { iface MIXER name 'HP PGA Bypass Volume' value.0 0 value.1 0 comment { access 'read write' type INTEGER count 2 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 dbvalue.1 -9999999 } } control.17 { iface MIXER name 'HP DAC Playback Volume' value.0 118 value.1 118 comment { access 'read write' type INTEGER count 2 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 0 dbvalue.1 0 } } control.18 { iface MIXER name 'HPCOM PGA Bypass Volume' value.0 0 value.1 0 comment { access 'read write' type INTEGER count 2 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 dbvalue.1 -9999999 } } control.19 { iface MIXER name 'HPCOM DAC Playback Volume' value.0 0 value.1 0 comment { access 'read write' type INTEGER count 2 range '0 - 118' dbmin -9999999 dbmax 0 dbvalue.0 -9999999 dbvalue.1 -9999999 } } control.20 { iface MIXER name 'Line Playback Switch' value.0 true value.1 true comment { access 'read write' type BOOLEAN count 2 } } control.21 { iface MIXER name 'HP Playback Switch' value.0 true value.1 true comment { access 'read write' type BOOLEAN count 2 } } control.22 { iface MIXER name 'HPCOM Playback Switch' value.0 false value.1 false comment { access 'read write' type BOOLEAN count 2 } } control.23 { iface MIXER name 'AGC Switch' value.0 false value.1 false comment { access 'read write' type BOOLEAN count 2 } } control.24 { iface MIXER name 'Left AGC Target level' value '-5.5dB' comment { access 'read write' type ENUMERATED count 1 item.0 '-5.5dB' item.1 '-8dB' item.2 '-10dB' item.3 '-12dB' item.4 '-14dB' item.5 '-17dB' item.6 '-20dB' item.7 '-24dB' } } control.25 { iface MIXER name 'Right AGC Target level' value '-5.5dB' comment { access 'read write' type ENUMERATED count 1 item.0 '-5.5dB' item.1 '-8dB' item.2 '-10dB' item.3 '-12dB' item.4 '-14dB' item.5 '-17dB' item.6 '-20dB' item.7 '-24dB' } } control.26 { iface MIXER name 'Left AGC Attack time' value '8ms' comment { access 'read write' type ENUMERATED count 1 item.0 '8ms' item.1 '11ms' item.2 '16ms' item.3 '20ms' } } control.27 { iface MIXER name 'Right AGC Attack time' value '8ms' comment { access 'read write' type ENUMERATED count 1 item.0 '8ms' item.1 '11ms' item.2 '16ms' item.3 '20ms' } } control.28 { iface MIXER name 'Left AGC Decay time' value '100ms' comment { access 'read write' type ENUMERATED count 1 item.0 '100ms' item.1 '200ms' item.2 '400ms' item.3 '500ms' } } control.29 { iface MIXER name 'Right AGC Decay time' value '100ms' comment { access 'read write' type ENUMERATED count 1 item.0 '100ms' item.1 '200ms' item.2 '400ms' item.3 '500ms' } } control.30 { iface MIXER name 'De-emphasis Switch' value.0 false value.1 false comment { access 'read write' type BOOLEAN count 2 } } control.31 { iface MIXER name 'PGA Capture Volume' value.0 60 value.1 60 comment { access 'read write' type INTEGER count 2 range '0 - 119' dbmin 0 dbmax 5950 dbvalue.0 3000 dbvalue.1 3000 } } control.32 { iface MIXER name 'PGA Capture Switch' value.0 true value.1 true comment { access 'read write' type BOOLEAN count 2 } } control.33 { iface MIXER name 'ADC HPF Cut-off' value.0 Disabled value.1 Disabled comment { access 'read write' type ENUMERATED count 2 item.0 Disabled item.1 '0.0045xFs' item.2 '0.0125xFs' item.3 '0.025xFs' } } control.34 { iface MIXER name 'Output Driver Power-On time' value '0us' comment { access 'read write' type ENUMERATED count 1 item.0 '0us' item.1 '10us' item.2 '100us' item.3 '1ms' item.4 '10ms' item.5 '50ms' item.6 '100ms' item.7 '200ms' item.8 '400ms' item.9 '800ms' item.10 '2s' item.11 '4s' } } control.35 { iface MIXER name 'Output Driver Ramp-up step' value '0ms' comment { access 'read write' type ENUMERATED count 1 item.0 '0ms' item.1 '1ms' item.2 '2ms' item.3 '4ms' } } control.36 { iface MIXER name 'Left DAC Mux' value DAC_L1 comment { access 'read write' type ENUMERATED count 1 item.0 DAC_L1 item.1 DAC_L3 item.2 DAC_L2 } } control.37 { iface MIXER name 'Left HPCOM Mux' value 'differential of HPLOUT' comment { access 'read write' type ENUMERATED count 1 item.0 'differential of HPLOUT' item.1 'constant VCM' item.2 single-ended } } control.38 { iface MIXER name 'Right DAC Mux' value DAC_R1 comment { access 'read write' type ENUMERATED count 1 item.0 DAC_R1 item.1 DAC_R3 item.2 DAC_R2 } } control.39 { iface MIXER name 'Right HPCOM Mux' value 'differential of HPROUT' comment { access 'read write' type ENUMERATED count 1 item.0 'differential of HPROUT' item.1 'constant VCM' item.2 single-ended item.3 'differential of HPLCOM' item.4 'external feedback' } } control.40 { iface MIXER name 'Left Line1L Mux' value single-ended comment { access 'read write' type ENUMERATED count 1 item.0 single-ended item.1 differential } } control.41 { iface MIXER name 'Left Line1R Mux' value single-ended comment { access 'read write' type ENUMERATED count 1 item.0 single-ended item.1 differential } } control.42 { iface MIXER name 'Right Line1L Mux' value single-ended comment { access 'read write' type ENUMERATED count 1 item.0 single-ended item.1 differential } } control.43 { iface MIXER name 'Right Line1R Mux' value single-ended comment { access 'read write' type ENUMERATED count 1 item.0 single-ended item.1 differential } } control.44 { iface MIXER name 'Left PGA Mixer Line1L Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.45 { iface MIXER name 'Left PGA Mixer Line1R Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.46 { iface MIXER name 'Left PGA Mixer Mic2L Switch' value true comment { access 'read write' type BOOLEAN count 1 } } control.47 { iface MIXER name 'Left PGA Mixer Mic2R Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.48 { iface MIXER name 'Right PGA Mixer Line1R Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.49 { iface MIXER name 'Right PGA Mixer Line1L Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.50 { iface MIXER name 'Right PGA Mixer Mic2L Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.51 { iface MIXER name 'Right PGA Mixer Mic2R Switch' value true comment { access 'read write' type BOOLEAN count 1 } } control.52 { iface MIXER name 'Left Line Mixer PGAL Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.53 { iface MIXER name 'Left Line Mixer DACL1 Switch' value true comment { access 'read write' type BOOLEAN count 1 } } control.54 { iface MIXER name 'Left Line Mixer PGAR Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.55 { iface MIXER name 'Left Line Mixer DACR1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.56 { iface MIXER name 'Right Line Mixer PGAL Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.57 { iface MIXER name 'Right Line Mixer DACL1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.58 { iface MIXER name 'Right Line Mixer PGAR Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.59 { iface MIXER name 'Right Line Mixer DACR1 Switch' value true comment { access 'read write' type BOOLEAN count 1 } } control.60 { iface MIXER name 'Left HP Mixer PGAL Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.61 { iface MIXER name 'Left HP Mixer DACL1 Switch' value true comment { access 'read write' type BOOLEAN count 1 } } control.62 { iface MIXER name 'Left HP Mixer PGAR Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.63 { iface MIXER name 'Left HP Mixer DACR1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.64 { iface MIXER name 'Right HP Mixer PGAL Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.65 { iface MIXER name 'Right HP Mixer DACL1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.66 { iface MIXER name 'Right HP Mixer PGAR Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.67 { iface MIXER name 'Right HP Mixer DACR1 Switch' value true comment { access 'read write' type BOOLEAN count 1 } } control.68 { iface MIXER name 'Left HPCOM Mixer PGAL Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.69 { iface MIXER name 'Left HPCOM Mixer DACL1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.70 { iface MIXER name 'Left HPCOM Mixer PGAR Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.71 { iface MIXER name 'Left HPCOM Mixer DACR1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.72 { iface MIXER name 'Right HPCOM Mixer PGAL Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.73 { iface MIXER name 'Right HPCOM Mixer DACL1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.74 { iface MIXER name 'Right HPCOM Mixer PGAR Bypass Switch' value false comment { access 'read write' type BOOLEAN count 1 } } control.75 { iface MIXER name 'Right HPCOM Mixer DACR1 Switch' value false comment { access 'read write' type BOOLEAN count 1 } } }
I don't have a asound.conf file and I don't know what should be in it, if anything.
At this point, playing a stereo stream with `aplay -c2 --test sine` works just fine.
Trying to capture audio inputs gives me a i/o error. Here is the code of the recording program I'm using:
#include <stdio.h> #include <stdlib.h> #include <alsa/asoundlib.h> int main (int argc, char *argv[]) { int i; int err; char *buffer; int buffer_frames = 128; unsigned int rate = 44100; snd_pcm_t *capture_handle; snd_pcm_hw_params_t *hw_params; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; if ((err = snd_pcm_open (&capture_handle, argv[1], SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", argv[1], snd_strerror (err)); exit (1); } fprintf(stdout, "audio interface opened\n"); if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params allocated\n"); if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params initialized\n"); if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params access setted\n"); if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, format)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params format setted\n"); if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &rate, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params rate setted\n"); if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params channels setted\n"); if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "hw_params setted\n"); snd_pcm_hw_params_free (hw_params); fprintf(stdout, "hw_params freed\n"); if ((err = snd_pcm_prepare (capture_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); exit (1); } fprintf(stdout, "audio interface prepared\n"); buffer = malloc(128 * snd_pcm_format_width(format) / 8 * 2); fprintf(stdout, "buffer allocated\n"); for (i = 0; i < 10; ++i) { if ((err = snd_pcm_readi (capture_handle, buffer, buffer_frames)) != buffer_frames) { fprintf (stderr, "read from audio interface failed (%s)\n", err, snd_strerror (err)); exit (1); } fprintf(stdout, "read %d done\n", i); int j; for (j = 0; j < buffer_frames; j++) { fprintf(stdout, "%i ", buffer[j]); } fprintf(stdout, "\n"); } free(buffer); fprintf(stdout, "buffer freed\n"); snd_pcm_close (capture_handle); fprintf(stdout, "audio interface closed\n"); exit (0); }
When I run this program, the snd_pcm_readi() function returns the error code -5 (I/O error).
When the program is running, I can see all the MCASP and I2C signals correctly on a logic analyzer, so it seems like this is not a hardware or codec configuration error but maybe a mcasp driver bug or missconfiguration?
I have also tried a simple program using the portaudio asyncronous api and the capture callback is never triggered. arecord also gives me a i/o error.
Please, can someone provide some recommendations on how to fix this issue? For example, in which kernel module and in which function is the rx interrupt handled? I'm thinking the rx interrupt is either not being handled correctly, or it's not being requested at all.
Please help, I'm running out of ideas here :)