Hello,
I am kind of lost when it comes to this linux alsa stuff. Basically i am trying to get a WM8580 Codec to work on a custom AM335x board in the latest version of the Sitara SDK (linux-3.2.0-psp06.00.00.00). I have gotten to the point where it can find the card on startup and i can play a wav file, but unfortunately when i play it all that comes out is static. Now the static that comes out sounds the same each time i play a certain file telling me that it is sending the same data to the Codec but maybe in the wrong format or something?
I'll walk through what i have thus far. Here is my hardware setup:
As far as software goes i basically modified the board file to setup the pins for using MCASP0 and I2C0 for communication with the Codec:
static u8 evm_iis_serializer_direction0[] = {
TX_MODE, RX_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
};
static struct snd_platform_data evm_snd_data0 = {
.tx_dma_offset = 0x46000000, /* McASP0 */
.rx_dma_offset = 0x46000000,
.op_mode = DAVINCI_MCASP_IIS_MODE,
.num_serializer = ARRAY_SIZE(evm_iis_serializer_direction0),
.tdm_slots = 2,
.serial_dir = evm_iis_serializer_direction0,
.asp_chan_q = EVENTQ_2,
.version = MCASP_VERSION_3,
.txnumevt = 32,
.rxnumevt = 32,
.get_context_loss_count = omap_pm_get_dev_context_loss_count,
};
/* Module pin mux for I2C0 */
static struct pinmux_config i2c0_pin_mux[] = {
{"i2c0_sda.i2c0_sda", OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW | AM33XX_PULL_ENBL | AM33XX_INPUT_EN}, //!< I2C0 SDA
{"i2c0_scl.i2c0_scl", OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW | AM33XX_PULL_ENBL | AM33XX_INPUT_EN}, //!< I2C0 SCL
{NULL, 0},
};
/* Module pin mux for I2C2 */
static struct pinmux_config i2c2_pin_mux[] = {
{"uart1_ctsn.i2c2_sda", OMAP_MUX_MODE3 | AM33XX_SLEWCTRL_SLOW | AM33XX_PULL_UP | AM33XX_INPUT_EN}, //!< I2C2 SDA
{"uart1_rtsn.i2c2_scl", OMAP_MUX_MODE3 | AM33XX_SLEWCTRL_SLOW | AM33XX_PULL_UP | AM33XX_INPUT_EN}, //!< I2C2 SCL
{NULL, 0},
};
/* Module pin mux for mcasp0 */
static struct pinmux_config mcasp0_pin_mux[] = {
{"mcasp0_aclkx.mcasp0_aclkx", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLDOWN}, //!< MCASP BCLK
{"mcasp0_fsx.mcasp0_fsx", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLDOWN}, //!< MCASP FRAME SYNC
{"mcasp0_axr0.mcasp0_axr0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLDOWN}, //!< MCASP DATA OUT
{"mcasp0_axr1.mcasp0_axr1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLDOWN}, //!< MCASP DATA IN
{"gpmc_a0.gpio1_16", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLDOWN}, //!< AUDIO OUT-TO-IN
//{"xdma_event_intr0.gpio0_19", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP}, //!< AUDIO MCLK
//{"gpmc_csn2.gpio1_31", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT_PULLUP}, //!< AUDIO CS
{NULL, 0},
};
static struct i2c_board_info __initdata evm_i2c0_boardinfo[] = {
{
I2C_BOARD_INFO("wm8580", 0x1b),
},
{
I2C_BOARD_INFO("tps65910", TPS65910_I2C_ID1),
.platform_data = &am335x_tps65910_info,
},
};
/* Setup McASP 0 */
static void mcasp0_init(int profile)
{
/* Configure McASP */
setup_pin_mux(mcasp0_pin_mux);
am335x_register_mcasp(&evm_snd_data0, 0);
return;
}
Then i pretty much replaced sound/soc/davinci/davinci-evm.c with new code for this coded (I used sound/soc/samsung/smdk_wm8580.c as an example):
/*
* ASoC driver for TI DAVINCI EVM platform
*
* Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
* Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.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.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <asm/mach-types.h>
#include <asm/hardware/asp.h>
#include <mach/edma.h>
#if defined(CONFIG_MACH_AM335XEVM)
#include <mach/board-am335xevm.h>
#endif
#include "../codecs/wm8580.h"
#include "davinci-pcm.h"
#include "davinci-i2s.h"
#include "davinci-mcasp.h"
/* Board has a 12MHZ crystal attached to WM8580 */
#define EVM_WM8580_FREQ 12000000
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
//#define AUDIO_FORMAT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM)
volatile int myTestSpeed;
static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out;
int rfs;
int ret;
/* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
* This criterion can't be met if we request PLL output
* as {8000x256, 64000x256, 11025x256}Hz.
* As a wayout, we rather change rfs to a minimum value that
* results in (params_rate(params) * rfs), and itself, acceptable
* to both - the CODEC and the CPU.
*/
myTestSpeed = params_rate(params);
switch (myTestSpeed) {
case 16000:
case 22050:
case 32000:
case 44100:
case 48000:
case 88200:
case 96000:
rfs = 256;
break;
case 64000:
rfs = 384;
break;
case 8000:
case 11025:
rfs = 512;
break;
default:
return -EINVAL;
}
pll_out = params_rate(params) * rfs;
/* Set the Codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
if (ret < 0)
return ret;
/* Set the AP DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
if (ret < 0)
return ret;
/* Set WM8580 to drive MCLK from its PLLA */
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, WM8580_CLKSRC_PLLA);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, EVM_WM8580_FREQ, pll_out);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_ops evm_ops = {
.hw_params = evm_hw_params,
};
/* SMDK Playback widgets */
static const struct snd_soc_dapm_widget evm_wm8580_dapm_widgets[] = {
SND_SOC_DAPM_HP("Front", NULL),
SND_SOC_DAPM_HP("Center+Sub", NULL),
SND_SOC_DAPM_HP("Rear", NULL),
SND_SOC_DAPM_MIC("MicIn", NULL),
SND_SOC_DAPM_LINE("LineIn", NULL),
};
/* SMDK-PAIFTX connections */
static const struct snd_soc_dapm_route evm_wm8580_audio_map[] = {
/* MicIn feeds AINL */
{"AINL", NULL, "MicIn"},
/* LineIn feeds AINL/R */
{"AINL", NULL, "LineIn"},
{"AINR", NULL, "LineIn"},
/* Front Left/Right are fed VOUT1L/R */
{"Front", NULL, "VOUT1L"},
{"Front", NULL, "VOUT1R"},
/* Center/Sub are fed VOUT2L/R */
{"Center+Sub", NULL, "VOUT2L"},
{"Center+Sub", NULL, "VOUT2R"},
/* Rear Left/Right are fed VOUT3L/R */
{"Rear", NULL, "VOUT3L"},
{"Rear", NULL, "VOUT3R"},
};
static int evm_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* Enabling the microphone requires the fitting of a 0R
* resistor to connect the line from the microphone jack.
*/
snd_soc_dapm_disable_pin(dapm, "MicIn");
return 0;
}
enum {
PRI_PLAYBACK = 0,
PRI_CAPTURE,
SEC_PLAYBACK,
};
static struct snd_soc_dai_link evm_dai[] = {
[PRI_PLAYBACK] = { /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
.cpu_dai_name = "davinci-mcasp.0",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "davinci-pcm-audio",
.codec_name = "wm8580.1-001b",
.ops = &evm_ops,
},
[PRI_CAPTURE] = { /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
.cpu_dai_name = "davinci-mcasp.0",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "davinci-pcm-audio",
.codec_name = "wm8580.1-001b",
.init = evm_wm8580_init_paiftx,
.ops = &evm_ops,
},
[SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
.name = "Sec_FIFO TX",
.stream_name = "Playback",
.cpu_dai_name = "davinci-mcasp.0",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "davinci-pcm-audio",
.codec_name = "wm8580.1-001b",
.ops = &evm_ops,
},
};
static struct snd_soc_card evm_snd_soc_card = {
.name = "AM335X WM8580",
.dai_link = evm_dai,
.num_links = 2,
.dapm_widgets = evm_wm8580_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(evm_wm8580_dapm_widgets),
.dapm_routes = evm_wm8580_audio_map,
.num_dapm_routes = ARRAY_SIZE(evm_wm8580_audio_map),
};
static struct platform_device *evm_snd_device;
static int __init evm_init(void)
{
int ret;
evm_snd_device = platform_device_alloc("soc-audio", -1);
if (!evm_snd_device)
return -ENOMEM;
platform_set_drvdata(evm_snd_device, &evm_snd_soc_card);
ret = platform_device_add(evm_snd_device);
if (ret)
platform_device_put(evm_snd_device);
return ret;
}
static void __exit evm_exit(void)
{
platform_device_unregister(evm_snd_device);
}
module_init(evm_init);
module_exit(evm_exit);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
MODULE_LICENSE("GPL");
After those changes i was able to see the soundcard and play files from linux; however, like i said the sound that comes out is just all static. I am basically just looking for suggestions of where to start because i have no idea of what to do from here to track down the problem : /. So any suggestions or assistance would be greatly appreciated!!!



