blob: a521c0dfb5c91f2e977098d08b7936e6faecee0a [file] [log] [blame]
/*
* sound/soc/dummy.c
*
* Author: Cao Rongrong <rrcao@ambarella.com>
* History:
* 2009/03/12 - [Cao Rongrong] Created file
* 2009/06/10 - [Cao Rongrong] Port to 2.6.29
* 2011/03/20 - [Cao Rongrong] Port to 2.6.38
*
* Copyright (C) 2004-2009, Ambarella, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <plat/audio.h>
#include "../codecs/ambarella_dummy.h"
static unsigned int dummy_dai_fmt = 0;
module_param(dummy_dai_fmt, uint, 0644);
MODULE_PARM_DESC(dummy_dai_fmt, "DAI format.");
static unsigned int dummy_disable_codec = 0;
module_param(dummy_disable_codec, uint, 0644);
MODULE_PARM_DESC(dummy_disable_codec, "Disable External Codec.");
static unsigned int dummy_pwr_pin = 12;
module_param(dummy_pwr_pin, uint, 0644);
MODULE_PARM_DESC(dummy_pwr_pin, "External Codec Power Pin.");
static int ambarella_dummy_board_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;
int errorCode = 0, mclk, oversample, i2s_mode;
switch (params_rate(params)) {
case 8000:
mclk = AudioCodec_4_096M;
oversample = AudioCodec_512xfs;
break;
case 11025:
mclk = AudioCodec_5_6448M;
oversample = AudioCodec_512xfs;
break;
case 16000:
mclk = AudioCodec_4_096M;
oversample = AudioCodec_256xfs;
break;
case 22050:
mclk = AudioCodec_5_6448M;
oversample = AudioCodec_256xfs;
break;
case 32000:
mclk = AudioCodec_8_192M;
oversample = AudioCodec_256xfs;
break;
case 44100:
mclk = AudioCodec_11_2896M;
oversample = AudioCodec_256xfs;
break;
case 48000:
mclk = AudioCodec_12_288M;
oversample = AudioCodec_256xfs;
break;
default:
errorCode = -EINVAL;
goto hw_params_exit;
}
if (dummy_dai_fmt == 0)
i2s_mode = SND_SOC_DAIFMT_I2S;
else
i2s_mode = SND_SOC_DAIFMT_DSP_A;
/* set the I2S system data format*/
errorCode = snd_soc_dai_set_fmt(cpu_dai,
i2s_mode | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
if (errorCode < 0) {
printk(KERN_ERR "can't set cpu DAI configuration\n");
goto hw_params_exit;
}
/* set the I2S system clock*/
errorCode = snd_soc_dai_set_sysclk(cpu_dai, AMBARELLA_CLKSRC_ONCHIP, mclk, 0);
if (errorCode < 0) {
printk(KERN_ERR "can't set cpu MCLK configuration\n");
goto hw_params_exit;
}
errorCode = snd_soc_dai_set_clkdiv(cpu_dai, AMBARELLA_CLKDIV_LRCLK, oversample);
if (errorCode < 0) {
printk(KERN_ERR "can't set cpu MCLK/SF ratio\n");
goto hw_params_exit;
}
hw_params_exit:
return errorCode;
}
static struct snd_soc_ops ambarella_dummy_board_ops = {
.hw_params = ambarella_dummy_board_hw_params,
};
static struct snd_soc_dai_link ambarella_dummy_dai_link = {
.name = "AMB-DUMMY",
.stream_name = "AMB-DUMMY-STREAM",
.cpu_dai_name = "ambarella-i2s.0",
.platform_name = "ambarella-pcm-audio",
.codec_dai_name = "AMBARELLA_DUMMY_CODEC",
.codec_name = "ambdummy-codec",
.ops = &ambarella_dummy_board_ops,
};
static struct snd_soc_card snd_soc_card_ambarella_dummy = {
.name = "ambarella_dummy",
.dai_link = &ambarella_dummy_dai_link,
.num_links = 1,
};
static struct platform_device *ambarella_dummy_snd_device;
static int __init ambarella_dummy_board_init(void)
{
int errorCode = 0;
ambarella_dummy_snd_device =
platform_device_alloc("soc-audio", -1);
if (!ambarella_dummy_snd_device) {
errorCode = -ENOMEM;
goto ambarella_dummy_board_init_exit;
}
platform_set_drvdata(ambarella_dummy_snd_device,
&snd_soc_card_ambarella_dummy);
errorCode = platform_device_add(ambarella_dummy_snd_device);
if (errorCode)
goto ambarella_dummy_board_init_exit;
if (dummy_disable_codec) {
errorCode = gpio_request(dummy_pwr_pin, "dummy_disable_codec");
if (errorCode < 0) {
pr_err("Request dummy_disable_codec GPIO(%d) failed\n",
dummy_pwr_pin);
goto ambarella_dummy_board_init_exit;
}
gpio_direction_output(dummy_pwr_pin, GPIO_LOW);
}
return 0;
ambarella_dummy_board_init_exit:
platform_device_del(ambarella_dummy_snd_device);
platform_device_put(ambarella_dummy_snd_device);
return errorCode;
}
static void __exit ambarella_dummy_board_exit(void)
{
if (dummy_disable_codec)
gpio_free(dummy_pwr_pin);
platform_device_unregister(ambarella_dummy_snd_device);
}
module_init(ambarella_dummy_board_init);
module_exit(ambarella_dummy_board_exit);
MODULE_AUTHOR("Anthony Ginger <hfjiang@ambarella.com>");
MODULE_DESCRIPTION("Amabrella A2 Board with internal Codec for ALSA");
MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-soc-a2bub");