Wiki

Differences

This shows you the differences between two versions of the page.


Previous revision
Next revision
resources:tools-software:linux-drivers:sound:adau1977 [27 Jan 2014 19:58] – fix source links Lars-Peter Clausen
Line 1: Line 1:
 +====== ADAU1977 Sound CODEC Linux Driver ======
  
 +===== Supported Devices =====
 +
 +  * [[adi>ADAU1977]]
 +  * [[adi>ADAU1978]]
 +  * [[adi>ADAU1979]]
 +
 +===== Evaluation Boards =====
 +
 +  * [[adi>EVAL-ADAU1977Z]]
 +
 +====== Source Code ======
 +
 +==== Status ====
 +
 +^  Source  ^  Mainlined?  ^
 +| [[linux.github>asoc-adau1977?sound/soc/codecs/adau1977.c|git]] | [[git.linux.org>sound/soc/codecs/adau1977.c|In progress]] |
 +
 +==== Files ====
 +
 +^ Function ^ File ^
 +| driver  | [[linux.github>asoc-adau1977?sound/soc/codecs/adau1977.c|sound/soc/codecs/adau1977.c]] |
 +| driver  | [[linux.github>asoc-adau1977?sound/soc/codecs/adau1977-spi.c|sound/soc/codecs/adau1977-spi.c]] |
 +| driver  | [[linux.github>asoc-adau1977?sound/soc/codecs/adau1977-i2c.c|sound/soc/codecs/adau1977-i2c.c]] |
 +| include | [[linux.github>asoc-adau1977?sound/soc/codecs/adau1977.h|sound/soc/codecs/adau1977.h]] |
 +| platform data | [[linux.github>asoc-adau1977?include/linux/platform_data/adau1977.h|include/linux/platform_data/adau1977.h]] |
 +
 +====== Example device initialization ======
 +
 +{{page>software/linux/docs/platform_and_bus_model#Platform Data&noheader&firstseconly&noeditbtn}}
 +
 +The platform data for the ADAU1977 allow to specify the MICBIAS pin voltage. If no platform data is specified (i.e. set to NULL) the default voltage of 8.5 V will be used.
 +
 +<code c>
 +/**
 + * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting
 + * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V
 + * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V
 + * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V
 + * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V
 + * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V
 + * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V
 + * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V
 + * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V
 + * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V
 + */
 +enum adau1977_micbias {
 +    ADAU1977_MICBIAS_5V0 = 0x0,
 +    ADAU1977_MICBIAS_5V5 = 0x1,
 +    ADAU1977_MICBIAS_6V0 = 0x2,
 +    ADAU1977_MICBIAS_6V5 = 0x3,
 +    ADAU1977_MICBIAS_7V0 = 0x4,
 +    ADAU1977_MICBIAS_7V5 = 0x5,
 +    ADAU1977_MICBIAS_8V0 = 0x6,
 +    ADAU1977_MICBIAS_8V5 = 0x7,
 +    ADAU1977_MICBIAS_9V0 = 0x8,
 +};
 +
 +/**
 + * struct adau1977_platform_data - Platform configuration data for the ADAU1977
 + * @micbias: Specifies the voltage for the MICBIAS pin
 + */
 +struct adau1977_platform_data {
 +    enum adau1977_micbias micbias;
 +};
 +</code>
 +
 +
 +===== Voltage Supplies =====
 +
 +The ADAU1977 driver expects a regulator supply for the AVDD voltage to be specified. This allows the driver to disable the supply when not needed, which helps to conserve power. Additionally the driver optionally accepts a supply for the DVDD voltage. If a supply for the DVDD voltage is specified the driver will use that regulator and disable the internal LDO.
 +
 +When using machine board files to register the device the regulators can be specified in the board file.
 +<code c>
 +static struct regulator_consumer_supply adau1977_avdd_consumer_supplies[] = {
 + REGULATOR_SUPPLY("AVDD", "spi0.1"),
 +};
 + 
 +static struct regulator_init_data adau1977_avdd_reg_init_data = {
 + .constraints = {
 + .name = "3V3",
 + .valid_ops_mask = REGULATOR_CHANGE_STATUS,
 + },
 + .consumer_supplies = adau1977_avdd_consumer_supplies,
 + .num_consumer_supplies = ARRAY_SIZE(adau1977_avdd_consumer_supplies),
 +};
 + 
 +static struct fixed_voltage_config adau1977_avdd_pdata = {
 + .supply_name = "board-3V3",
 + .microvolts = 3300000,
 + .gpio = -EINVAL,
 + .enabled_at_boot = 0,
 + .init_data = &adau1977_avdd_reg_init_data,
 +};
 +
 +static struct platform_device adau1977_avdd_voltage_regulator = {
 + .name = "reg-fixed-voltage",
 + .id = 0,
 + .dev = {
 + .platform_data = &adau1977_avdd_pdata,
 + },
 +};
 +
 +/* Optional */
 +static struct regulator_consumer_supply adau1977_dvdd_consumer_supplies[] = {
 + REGULATOR_SUPPLY("DVDD", "spi0.1"),
 +};
 + 
 +static struct regulator_init_data adau1977_dvdd_reg_init_data = {
 + .constraints = {
 + .name = "1V8",
 + .valid_ops_mask = REGULATOR_CHANGE_STATUS,
 + },
 + .consumer_supplies = adau1977_dvdd_consumer_supplies,
 + .num_consumer_supplies = ARRAY_SIZE(adau1977_dvdd_consumer_supplies),
 +};
 + 
 +static struct fixed_voltage_config adau1977_dvdd_pdata = {
 + .supply_name = "board-1V8",
 + .microvolts = 1800000,
 + .gpio = -EINVAL,
 + .enabled_at_boot = 0,
 + .init_data = &adau1977_dvdd_reg_init_data,
 +};
 +
 +static struct platform_device adau1977_dvdd_voltage_regulator = {
 + .name = "reg-fixed-voltage",
 + .id = 1,
 + .dev = {
 + .platform_data = &adau1977_dvdd_pdata,
 + },
 +};
 +</code>
 +
 +When using devicetree the regulators should be specified in the devicetree. For more on how to specify the regulators using devicetree see the [[http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/regulator/regulator.txt|regulator devicetree bindings documentation]] and the devicetree examples below in the SPI and I2C sections.
 +
 +===== Devicetree bindings =====
 +
 +The ADAU1977 driver is fully devicetree compatible. Depending on the bus type the device is connected to different properties must/can be specified.
 +
 +**Shared required properties:**
 +  * **compatible**: Must be "adi,adau1977", "adi,adau1978" or adi,adau1979"
 +  * **AVDD-supply**: A handle to the power supply connected to the AVDD pin
 +
 +**Shared optional properties:**
 +  * **DVDD-supply**: A handle to the power supply connected to the DVDD pin. If specified the internal LDO will be disabled.
 +  * **reset-gpios**: GPIO chip handle and specifier that define which GPIO is connected to the chips PD/RST pin. If not specified the reset pin is assumed to be hardwired to VCC.
 +  * **adi,micbias**: Configures the voltage setting for the MICBIAS pin. If not specified the default value will be 8.5 Volts. This property is only valid for the ADAU1977. Valid values for this property are:
 +    * 0: 5.0V
 +    * 1: 5.5V
 +    * 2: 6.0V
 +    * 3: 6.5V
 +    * 4: 7.0V
 +    * 5: 7.5V
 +    * 6: 8.0V
 +    * 7: 8.5V
 +    * 8: 9.0V
 +
 +**I2C required properties**:
 +  * **reg**: The I2C address of the chip
 +
 +**SPI required properties**:
 +  * **reg**: The SPI chipselect signal of the SPI master associated with this chip
 +  * **spi-max-frequency**: Maximum spi frequency to use.
 +
 +===== I2C =====
 +
 +{{page>software/linux/docs/platform_and_bus_model#Declaring I2C devices&firstseconly&noeditbtn}}
 +
 +The I2C device id depends on the ADDR0 and ADDR1 pin settings and needs to be set according to your board setup.
 +
 +^ ADDR1 ^ ADDR0 ^ I2C device id ^
 +| 0 | 0 | 0x11 |
 +| 0 | 1 | 0x31 |
 +| 1 | 0 | 0x51 |
 +| 1 | 1 | 0x71 |
 +
 +In this example we assume ADDR0=0 and ADDR1=0.
 +
 +<code c>
 +static struct adau1977_platform_data adau1977_pdata = {
 + .micbias = ADAU1977_MICBIAS_6V5,
 +};
 +
 +static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 +
 + [--snip--]
 + {
 + I2C_BOARD_INFO("adau1977", 0x11),
 + .platform_data = &adau1977_pdata,
 + },
 + [--snip--]
 +}
 +
 +</code>
 +
 +<code c>
 +static int __init stamp_init(void)
 +{
 + [--snip--]
 + i2c_register_board_info(0, bfin_i2c_board_info,
 + ARRAY_SIZE(bfin_i2c_board_info));
 + [--snip--]
 +
 + return 0;
 +}
 +arch_initcall(board_init);
 +</code>
 +
 +==== Devicetree ====
 +
 +<code>
 +codec_supply: fixedregulator@0 {
 + compatible = "regulator-fixed";
 + regulator-name = "AVDD";
 + regulator-min-microvolt = <3300000>;
 + regulator-max-microvolt = <3300000>;
 +};
 +
 +i2c@41600000 {
 + compatible = "...;
 + ...
 +
 + #size-cells = <0>;
 + #address-cells = <1>;
 +            
 + adau1977: codec@11 {
 + compatible = "adi,adau1977";
 + reg = <0x11>;
 + reset-gpios = <&gpio 5 0>;
 + AVDD-supply = <&codec_supply>;
 + };
 +};
 +</code>
 +
 +===== SPI =====
 +
 +{{page>software/linux/docs/platform_and_bus_model#Declaring SPI slave devices&firstseconly&noeditbtn}}
 +
 +<code c>
 +static struct adau1977_platform_data adau1977_pdata = {
 + .micbias = ADAU1977_MICBIAS_7V5,
 +};
 +
 +static struct spi_board_info board_spi_board_info[] __initdata = {
 + [--snip--]
 + {
 + .modalias = "adau1977",
 + .max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
 + .bus_num = 0,
 + .chip_select = GPIO_PF10 + MAX_CTRL_CS, /* CS, change it for your board */
 + .mode = SPI_MODE_0,
 + .platform_data = &adau1977_pdata,
 + },
 + [--snip--]
 +};
 +</code>
 +
 +<code c>
 +static int __init board_init(void)
 +{
 + [--snip--]
 +
 + spi_register_board_info(board_spi_board_info, ARRAY_SIZE(board_spi_board_info));
 +
 + [--snip--]
 +
 + return 0;
 +}
 +arch_initcall(board_init);
 +</code>
 +
 +==== Devicetree ====
 +
 +<code>
 +codec_supply: fixedregulator@0 {
 + compatible = "regulator-fixed";
 + regulator-name = "AVDD";
 + regulator-min-microvolt = <3300000>;
 + regulator-max-microvolt = <3300000>;
 +};
 +
 +spi@41600000 {
 + compatible = "...;
 + ...
 +
 + #size-cells = <0>;
 + #address-cells = <1>;
 +            
 + adau1977: codec@1 {
 + compatible = "adi,adau1977";
 + reg = <0x1>;
 + spi-max-frequency = <10000000>;
 + reset-gpios = <&gpio 5 0>;
 + AVDD-supply = <&codec_supply>;
 + adi,micbias = <5>;
 + };
 +};
 +</code>
 +
 +
 +====== ASoC DAPM Widgets ======
 +
 +^ Name ^ Description ^ Configuration ^
 +| AIN1 | Analog Input Channel 1 | |
 +| AIN2 | Analog Input Channel 2  | |
 +| AIN3 | Analog Input Channel 3  | |
 +| AIN4 | Analog Input Channel 4  | |
 +| VREF | Reference Voltage | |
 +| MICBIAS | Microphone Bias Output | ADAU1977 only |
 +
 +====== ALSA Controls ======
 +
 +^ Name ^ Description ^
 +| ADC1 Capture Volume | Post ADC gain for channel 1 |
 +| ADC2 Capture Volume | Post ADC gain for channel 2 |
 +| ADC3 Capture Volume | Post ADC gain for channel 3 |
 +| ADC4 Capture Volume | Post ADC gain for channel 4 |
 +| ADC1 Highpass-Filter Capture Switch | Enables/disables the highpass-filter for channel 1 |
 +| ADC2 Highpass-Filter Capture Switch | Enables/disables the highpass-filter for channel 2 |
 +| ADC3 Highpass-Filter Capture Switch | Enables/disables the highpass-filter for channel 3 |
 +| ADC4 Highpass-Filter Capture Switch | Enables/disables the highpass-filter for channel 4 |
 +| ADC1 DC Substraction Capture Switch | Enables/disables DC offset subtraction for channel 1 |
 +| ADC2 DC Substraction Capture Switch | Enables/disables DC offset subtraction for channel 2 |
 +| ADC3 DC Substraction Capture Switch | Enables/disables DC offset subtraction for channel 3 |
 +| ADC4 DC Substraction Capture Switch | Enables/disables DC offset subtraction for channel 4 |
 +
 +====== DAI configuration ======
 +
 +The codec driver registers one DAI: **adau1977-hifi**
 +
 +===== Supported DAI formats =====
 +
 +^ Name ^ Supported by driver ^ Description ^ Notes ^
 +| SND_SOC_DAIFMT_I2S     | yes | I2S Justified mode | |
 +| SND_SOC_DAIFMT_RIGHT_J | yes | Right Justified mode | |
 +| SND_SOC_DAIFMT_LEFT_J  | yes | Left Justified mode | |
 +| SND_SOC_DAIFMT_DSP_A   | yes | data MSB after FRM LRC | |
 +| SND_SOC_DAIFMT_DSP_B   | yes | data MSB during FRM LRC | |
 +| SND_SOC_DAIFMT_AC97    | no  | AC97 mode | |
 +| SND_SOC_DAIFMT_PDM     | no  | Pulse density modulation | |
 +| | |
 +| SND_SOC_DAIFMT_NB_NF | yes  | Normal bit- and frameclock |
 +| SND_SOC_DAIFMT_NB_IF | yes | Normal bitclock, inverted frameclock | |
 +| SND_SOC_DAIFMT_IB_NF | yes | Inverted frameclock, normal bitclock | |
 +| SND_SOC_DAIFMT_IB_IF | yes | Inverted bit- and frameclock | |
 +| | |
 +| SND_SOC_DAIFMT_CBM_CFM | yes | Codec bit- and frameclock master | Master mode is not supported if the LRCLK is used as clock source |
 +| SND_SOC_DAIFMT_CBS_CFM | no  | Codec bitclock slave, frameclock master | |
 +| SND_SOC_DAIFMT_CBM_CFS | no  | Codec bitclock master, frameclock slave | |
 +| SND_SOC_DAIFMT_CBS_CFS | yes | Codec bit- and frameclock slave | |
 +
 +===== System clock configuration =====
 +
 +The sysclk can either be provided by the internal PLL derived from the MCLK signal or by the LRCLK signal.
 +
 +<code c>
 +enum adau1977_clk_id {
 +    ADAU1977_SYSCLK,
 +};
 +
 +enum adau1977_sysclk_src {
 +    ADAU1977_SYSCLK_SRC_MCLK,
 +    ADAU1977_SYSCLK_SRC_LRCLK,
 +};
 +</code>
 +
 +If the MCLK is used the supported sampling rates of the device is constraint to those sample rates that can be derived from the the MCLK. The constraints are setup in the CODEC driver's startup routine. This means that the sysclk needs to be configured before the CODEC's startup callback is called. This can either be done from the machine driver's startup or init callback.
 +
 +For some hardware configurations it might be possible to change the MCLK frequency at runtime (e.g. to support both 44.1kHz and 48kHz based sample rates). In this case in order for the CODEC driver to not set any sample rate constraints the sysclk frequency should be set to 0 until it has been decided which MCLK frequency is used. This can for example be implemented by setting the sysclk to 0 in the machine driver's startup callback and setting it to the actual frequency in the hw_params callback.
 +
 +===== TDM configuration =====
 +
 +The TDM mode of the ADAU1977 can be configured using the snd_soc_dai_set_tdm_slot() function.
 +
 +  * The number of slots can be either 2, 4, 8 or 16. If the number of slots is set to 0 the device will go to I2S mode.
 +  * The slot width can be 16, 24, 32 bits per slot (In master mode only 16 and 32 bits per slot are supported)
 +  * tx_mask must always be 0.
 +  * Each slot can hold the data sample of one channel. Which slot holds which channel is configured by rx_mask. The first bit that is set in rx_mask is the slot that holds the first channel, the second bit the slot that holds the second channel and so on. If less then 4 bits are set the channels for which no slot has been provided are disabled. (E.g. 0x33, configures channel 0 to slot 0, channel 1 to slot 1, channel 2 to slot 4 and channel 3 to slot 4).
 +
 +Example TDM configuration:
 +<code c>
 + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0f, 4, 32);
 +</code>
 +
 +To configure whether the unused TDM slots should be tristated or actively driven low the snd_soc_dai_set_tristate() function is used. By default they are driven low.
 +
 +Example tristate configuration:
 +<code c>
 + ret = snd_soc_dai_set_tristate(codec_dai, true);
 +</code>
 +
 +===== Example machine driver configuration =====
 +
 +==== Fixed MCLK ====
 +
 +<code c>
 +static int eval_adau1977_init(struct snd_soc_pcm_runtime *rtd)
 +{
 + return snd_snd_soc_codec_set_sysclk_set_sysclk(rtd->codec, ADAU1977_SYSCLK,
 + ADAU1977_SYSCLK_SRC_MCLK, 1228000, SND_SOC_CLOCK_IN);
 +}
 +
 +static struct snd_soc_dai_link eval_adau1977_dai = {
 + .name = "adau1977",
 + .stream_name = "ADAU1977", 
 + .cpu_dai_name = "bfin-i2s.0", 
 + .codec_dai_name = "adau1977-hifi",
 + .platform_name = "bfin-i2s-pcm-audio",
 + .codec_name = "adau1977.0-0011",
 + .init = eval_adau1977_init,
 + .dai_fmt = SND_SOC_DAIFMT_I2S |
 + SND_SOC_DAIFMT_NB_NF |
 + SND_SOC_DAIFMT_CBM_CFM,
 +};
 +</code>
 +
 +
 +==== Configurable MCLK ====
 +
 +<code c>
 +static int eval_adau1977_init(struct snd_soc_pcm_runtime *rtd)
 +{
 + return snd_snd_soc_codec_set_sysclk_set_sysclk(rtd->codec, ADAU1977_SYSCLK,
 + ADAU1977_SYSCLK_SRC_MCLK, 0, SND_SOC_CLOCK_IN);
 +}
 +
 +static int eval_adau1977_hw_params(struct snd_pcm_substream *substream,
 + struct snd_pcm_hw_params *params)
 +{
 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
 + int ret;
 +
 + if (params_rate(params) % 441000 == 0)
 + mclk_rate = 11289600;
 + else
 + mclk_rate = 12288000;
 +
 + clk_set_rate(mclk, mclk_rate);
 +
 + return snd_snd_soc_codec_set_sysclk_set_sysclk(rtd->codec, ADAU1977_SYSCLK,
 + ADAU1977_SYSCLK_SRC_MCLK, mclk_rate, SND_SOC_CLOCK_IN);
 +}
 +
 +static struct snd_soc_ops eval_adau1977_ops = {
 + .hw_params = bfin_eval_adau1x61_hw_params,
 +};
 +
 +static struct snd_soc_dai_link eval_adau1977_dai = {
 + .name = "adau1977",
 + .stream_name = "ADAU1977", 
 + .cpu_dai_name = "bfin-i2s.0", 
 + .codec_dai_name = "adau1977-hifi",
 + .platform_name = "bfin-i2s-pcm-audio",
 + .codec_name = "adau1977.0-0011",
 + .ops = &eval_adau1977_ops,
 + .init = eval_adau1977_init,
 + .dai_fmt = SND_SOC_DAIFMT_I2S |
 + SND_SOC_DAIFMT_NB_NF |
 + SND_SOC_DAIFMT_CBM_CFM,
 +};
 +</code>
 +
 +{{page>resources/tools-software/linux-drivers/need_help#need help&noheader&firstseconly&noeditbtn}}
resources/tools-software/linux-drivers/sound/adau1977.txt · Last modified: 18 Feb 2019 16:49 by dell jin