Adding a new DAC

From Ubicom Developer

Jump to: navigation, search

Contents

Introduction

The purpose of this page is to describe the process of adding a new audio DAC to the existing Ubicom reference design.  This document walks through the different hardware and software pieces that may need to be changed in order to support a new DAC.


Board Requirements

Most audio DACs share common interfaces and signals.  This section walks through some of the different board level requirements.


Interfaces

Two types of interfaces commonly found on audio DACs are I2S and I2C.  I2S is a standard interface for communicating digital audio and I2C is a common standard for inter-chip communication.  A third interface type can be S/PDIF, though this interface either does not require a DAC or is an interface with a high-end DAC.


I2S & I2C

I2S has three signals:

1. SCLK - bit clock (sample width * sample rate)

2. LRCLK - word clock (sample rate)

3. SDIN - serial audio data

  • note: SCLK and LRCLK should be on the same port.


I2C has two signals:
1. SCL - clock

2. SDA - serial data


I2C also has one other requirement.  Because I2C is a master/slave bus, the slave device must have its own address.  This address can be found from the datasheet of the DAC or can even be changed based on pull-ups/downs placed on the board.  In the picture above, there are two pins on the DAC to allow for four different addresses.


S/PDIF

SPIDF is a format that can be used as either a direct output from the system (through either an optical transmitter or electrical connector) or an interface with a higher end DAC.  In the case of S/PDIF, the clock is embedded into the data signal, requiring only one output pin to implement the interface.


DAC clocking

The DAC, however, must have its own clock to run its internal circuitry.  Some have internal PLLs that multiply off of an external signal (the LRCLK for instance) and some require an external master clock to drive the DAC's internal circuitry.  If the new part requires an external signal, the appropriate clock pins must be used on the Ubicom IP7K.


MCLK options (please note that these pins must be available):

1. PA5 - PWM0.  Divided off the IO clock frequency (typically set at 500MHz).

2. PE4 - PWM1.  Divided off the IO clock frequency (typically set at 500MHz).

3. PD0 - PWM2.  Divided off the IO clock frequency (typically set at 500MHz).

4. PA7 - CLKDIV. Divided off the core clock frequency (see tables below).


Frequency Requirements

The Ubicom IP7K is quite flexible and allows for several clocking schema for I2S. I2S does not specify the exact setup and hold times for the different signals, so the designer must understand if their DAC supports the asymmetric clock scheme outlined below.  The DACs used in the Ubicom reference design all support asymmetric timing.


The table below shows the Asymmetric I2S output from IP7K.  This means that the duty cycle of the LRCLK and SCLK are not exactly 50%.  The output will be very close to symmetrical (within 5%) and guaranteed to not be less than 44%.

Ubicom Processor
I2S Sample Rates
Required Core Clock Frequency
IP7540
44100 & 48000
394MHz
IP7550
44100 & 48000
501MHz
IP7560
44100 & 48000
542MHz


The table below outlines the different frequencies if the DAC requires symmetric timing.

Ubicom Processor
I2S Sample Rates
Required Core Clock Frequency
IP7540
44100
383MHz
IP7540
48000
393MHz
IP7550
44100
496MHz
IP7550
48000
467/492MHz
IP7560
44100 & 48000
542MHz



Ubicom Processor SPDIF Samples Rates Required Core Clock Frequency     
IP7540 44100 361MHz
IP7540 48000 393MHz
IP7550 44100 497MHz
IP7550 48000 492MHz
IP7560 44100 & 48000 541MHz









Ultra Parameters

This section is outlines the parameters that must be set in the ultra project (or board file) in order to achieve the appropriate I2S timing.  For details on how to edit the ultra portion of the Ubicom distro, please read this.


Asymmetric I2S
Ubicom Processor Audio Rate HRT Spacing I2S Sample Rate
IP7540
44100 48000
16 44100/48000
IP7550
44100 48000 32
44100/48000
IP7560
44100 48000 32 44100/48000


Symmetric I2S
Ubicom Processor Audio Rate HRT Spacing I2S Sample Rate
IP7540 17
8
44100
IP7540 16
8
48000
IP7550 11
16
44100
IP7550 [19] 5
[8] 32
48000 - [467] 492
IP7560 6
32
44100
IP7560 11
16
48000


SPDIF
Ubicom Processor Audio Rate HRT Spacing SPDIF Sample Rate
IP7540 4 16 44100
IP7540 4 16 48000
IP7550 11 8 44100
IP7550 5 16 48000
IP7560 11 & 12 8 44100 & 48000








Linux Driver Work

This section outlines the changes needed within the Ubicom Linux Distribution in order for ALSA to recognize the new audio DAC.


An ALSA driver must be written in order for Linux to correctly initialize the audio DAC. This document will not go into detail on how to write a driver.  Please see the following files for examples on how to write a DAC driver (the datasheet must be consulted closely for the register and data settings).

~/ubicom-distro/linux-2.6.x/sound/ubicom32/ubi32-generic.c
~/ubicom-distro/linux-2.6.x/sound/ubicom32/ubi32-cs4350.c
~/ubicom-distro/linux-2.6.x/sound/ubicom32/ubi32-cs4384.c
~/ubicom-distro/linux-2.6.x/arch/ubicom32/include/asm/ubi32-cs4384.h - contains platform options for mclk


The Linux board file must be changed in order to initialize the appropriate ALSA driver.  The two key components are the I2C device address and the audio_device_alloc.

  • Note: the new audio DAC must be correctly configured in linux_menuconfig and compiled into the kernel.  Please run \> make linux_menuconfig from the distro root directory to select the appropriate sound card driver.


~/ubicom-distro/linux-2.6.x/arch/ubicom32/mach-ip7k/board-ip7500iap.c

...
static struct i2c_board_info __initdata ip7500iap_i2c_board_info[] = {
        /*
         * U6, GENERIC DAC, address 0x4B
         */
        {
                .type           = "generic",
                .addr           = 0x4B,
        },
...


/*
* ip7500iap_init
* Called to add the devices which we have on this board
*/
static int __init ip7500iap_init(void)
{
...
        /*
         * Bring up audio devices
         */
        platform_add_devices(ip7500iap_devices, ARRAY_SIZE(ip7500iap_devices));

        audio_dev = audio_device_alloc("snd-ubi32-generic", "audio", "audio-i2sout", sizeof(struct ubi32_generic_platform_data));
        if (audio_dev) {
                ip7500iap_i2c_board_info[0].platform_data = audio_dev;
        }
...



If the Audio DAC requires the IP7K to supply a master clock, the following additions must be made to the linux board file:

~/ubicom-distro/linux-2.6.x/arch/ubicom32/mach-ip7k/board-ip7500av.c

...
#include <asm/ubi32-pcm.h>
#include <asm/ubi32-cs4384.h>
...
/*
 * List of possible mclks we can generate.  This depends on the CPU frequency.
 */
static struct ubi32_cs4384_mclk_entry ip7500av_cs4384_mclk_entries[] = {
        {
                .rate   =       12288000,
                .div    =       44,
        },
        {
                .rate   =       11289600,
                .div    =       48,
        },
};
...

/*
 * ip7500av_init
 *      Called to add the devices which we have on this board
 */
static int __init ip7500av_init(void)
{
        struct platform_device *audio_dev;
        struct ubi32_cs4384_platform_data *cs4384_pd;

        /*
         * CS4384 DAC
         */
        audio_dev = audio_device_alloc("snd-ubi32-cs4384", "audio", "audio-i2sout", sizeof(struct ubi32_cs4384_platform_data));
        if (audio_dev) {
                /*
                 * Attempt to figure out a good divisor.  This will only work
                 * assuming the core frequency is compatible.
                 */
                int i;
                unsigned int freq = processor_frequency();
                for (i = 0; i < ARRAY_SIZE(ip7500av_cs4384_mclk_entries); i++) \
{
                        unsigned int div;
                        unsigned int rate = ip7500av_cs4384_mclk_entries[i].rat\
e / 1000;
                        div = ((freq / rate) + 500) / 1000;
                        ip7500av_cs4384_mclk_entries[i].div = div;
                        printk("CS4384 mclk %d rate %u000Hz div %u act %u\n", i\
, rate, div, freq / div);
                }

                cs4384_pd = audio_device_priv(audio_dev);
                cs4384_pd->mclk_src = UBI32_CS4384_MCLK_PWM_0;
                cs4384_pd->n_mclk = ARRAY_SIZE(ip7500av_cs4384_mclk_entries);
                cs4384_pd->mclk_entries = ip7500av_cs4384_mclk_entries;
                ip7500av_i2c_board_info[0].platform_data = audio_dev;
        }

...


Porting Confirmation

If the processor is able to communicate with the DAC over I2C, then the following boot messages will confirm proper porting (assuming the same coding/debugs are used in the new audio DAC as in the Ubicom reference drivers):


[    2.960000] Advanced Linux Sound Architecture Driver Version 1.0.18rc3.
[    2.960000] Ubi32PCM: channels_min:1 channels_max:2
[    2.960000] Ubi32PCM: rates:80000055 min:5512 max:44100 count:24 fmts:000000000000000c (playback)
[    2.970000] ALSA device list:
[    2.970000]   #0: Ubi32-Generic at sendirq=14.0 recvirq=13.0 regs=400ffd7c