mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
Merge branch 'topic/asoc' into for-linus
Conflicts: arch/powerpc/platforms/85xx/p1022_ds.c
This commit is contained in:
commit
aa5c14d5c0
380 changed files with 31455 additions and 16117 deletions
|
|
@ -179,7 +179,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
runtime->dma_bytes = params_buffer_bytes(params);
|
||||
|
||||
prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
|
||||
prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
|
||||
|
||||
prtd->dma_buffer = runtime->dma_addr;
|
||||
|
|
@ -374,14 +374,14 @@ static int atmel_pcm_new(struct snd_card *card,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = 0xffffffff;
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = atmel_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
pr_debug("at32-pcm:"
|
||||
"Allocating PCM capture DMA buffer\n");
|
||||
ret = atmel_pcm_preallocate_dma_buffer(pcm,
|
||||
|
|
@ -414,12 +414,9 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
|
||||
static int atmel_pcm_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_pcm *pcm = dai_link->pcm;
|
||||
struct snd_pcm_str *stream = &pcm->streams[0];
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_pcm_runtime *runtime = dai->runtime;
|
||||
struct atmel_runtime_data *prtd;
|
||||
struct atmel_pcm_dma_params *params;
|
||||
|
||||
|
|
@ -441,12 +438,9 @@ static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
|
||||
static int atmel_pcm_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_pcm *pcm = dai_link->pcm;
|
||||
struct snd_pcm_str *stream = &pcm->streams[0];
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_pcm_runtime *runtime = dai->runtime;
|
||||
struct atmel_runtime_data *prtd;
|
||||
struct atmel_pcm_dma_params *params;
|
||||
|
||||
|
|
@ -470,27 +464,46 @@ static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
|
|||
#define atmel_pcm_resume NULL
|
||||
#endif
|
||||
|
||||
struct snd_soc_platform atmel_soc_platform = {
|
||||
.name = "atmel-audio",
|
||||
.pcm_ops = &atmel_pcm_ops,
|
||||
static struct snd_soc_platform_driver atmel_soc_platform = {
|
||||
.ops = &atmel_pcm_ops,
|
||||
.pcm_new = atmel_pcm_new,
|
||||
.pcm_free = atmel_pcm_free_dma_buffers,
|
||||
.suspend = atmel_pcm_suspend,
|
||||
.resume = atmel_pcm_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(atmel_soc_platform);
|
||||
|
||||
static int __init atmel_pcm_modinit(void)
|
||||
static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&atmel_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
|
||||
}
|
||||
module_init(atmel_pcm_modinit);
|
||||
|
||||
static void __exit atmel_pcm_modexit(void)
|
||||
static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&atmel_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(atmel_pcm_modexit);
|
||||
|
||||
static struct platform_driver atmel_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "atmel-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = atmel_soc_platform_probe,
|
||||
.remove = __devexit_p(atmel_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_atmel_pcm_init(void)
|
||||
{
|
||||
return platform_driver_register(&atmel_pcm_driver);
|
||||
}
|
||||
module_init(snd_atmel_pcm_init);
|
||||
|
||||
static void __exit snd_atmel_pcm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&atmel_pcm_driver);
|
||||
}
|
||||
module_exit(snd_atmel_pcm_exit);
|
||||
|
||||
MODULE_AUTHOR("Sedji Gaouaou <[email protected]>");
|
||||
MODULE_DESCRIPTION("Atmel PCM module");
|
||||
|
|
|
|||
|
|
@ -74,9 +74,6 @@ struct atmel_pcm_dma_params {
|
|||
void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
|
||||
};
|
||||
|
||||
extern struct snd_soc_platform atmel_soc_platform;
|
||||
|
||||
|
||||
/*
|
||||
* SSC register access (since ssc_writel() / ssc_readl() require literal name)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
|
|||
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
int dir_mask;
|
||||
|
||||
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
|
||||
|
|
@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
|||
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir, dir_mask;
|
||||
|
||||
|
|
@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
int id = rtd->dai->cpu_dai->id;
|
||||
int id = dai->id;
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir, channels, bits;
|
||||
|
|
@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
* function. It should not be used for other purposes
|
||||
* as it is common to all substreams.
|
||||
*/
|
||||
snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
|
||||
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
|
||||
|
||||
channels = params_channels(params);
|
||||
|
||||
|
|
@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir;
|
||||
|
||||
|
|
@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
|
|||
# define atmel_ssc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int atmel_ssc_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
int ret = 0;
|
||||
|
||||
snd_soc_dai_set_drvdata(dai, ssc_p);
|
||||
|
||||
/*
|
||||
* Request SSC device
|
||||
*/
|
||||
ssc_p->ssc = ssc_request(dai->id);
|
||||
if (IS_ERR(ssc_p->ssc)) {
|
||||
printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
|
||||
ret = PTR_ERR(ssc_p->ssc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_ssc_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
ssc_free(ssc_p->ssc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
|
||||
|
||||
|
|
@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
|
|||
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
|
||||
};
|
||||
|
||||
struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
||||
{ .name = "atmel-ssc0",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
||||
{
|
||||
.name = "atmel-ssc-dai.0",
|
||||
.probe = atmel_ssc_probe,
|
||||
.remove = atmel_ssc_remove,
|
||||
.suspend = atmel_ssc_suspend,
|
||||
.resume = atmel_ssc_resume,
|
||||
.playback = {
|
||||
|
|
@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|||
.rates = ATMEL_SSC_RATES,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
.private_data = &ssc_info[0],
|
||||
},
|
||||
#if NUM_SSC_DEVICES == 3
|
||||
{ .name = "atmel-ssc1",
|
||||
.id = 1,
|
||||
{
|
||||
.name = "atmel-ssc-dai.1",
|
||||
.probe = atmel_ssc_probe,
|
||||
.remove = atmel_ssc_remove,
|
||||
.suspend = atmel_ssc_suspend,
|
||||
.resume = atmel_ssc_resume,
|
||||
.playback = {
|
||||
|
|
@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|||
.rates = ATMEL_SSC_RATES,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
.private_data = &ssc_info[1],
|
||||
},
|
||||
{ .name = "atmel-ssc2",
|
||||
.id = 2,
|
||||
{
|
||||
.name = "atmel-ssc-dai.2",
|
||||
.probe = atmel_ssc_probe,
|
||||
.remove = atmel_ssc_remove,
|
||||
.suspend = atmel_ssc_suspend,
|
||||
.resume = atmel_ssc_resume,
|
||||
.playback = {
|
||||
|
|
@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|||
.rates = ATMEL_SSC_RATES,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
.private_data = &ssc_info[2],
|
||||
},
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(atmel_ssc_dai);
|
||||
|
||||
static int __init atmel_ssc_modinit(void)
|
||||
static __devinit int asoc_ssc_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
|
||||
BUG_ON(pdev->id < 0);
|
||||
BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
|
||||
return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
|
||||
}
|
||||
module_init(atmel_ssc_modinit);
|
||||
|
||||
static void __exit atmel_ssc_modexit(void)
|
||||
static int __devexit asoc_ssc_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(atmel_ssc_modexit);
|
||||
|
||||
static struct platform_driver asoc_ssc_driver = {
|
||||
.driver = {
|
||||
.name = "atmel-ssc-dai",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = asoc_ssc_probe,
|
||||
.remove = __devexit_p(asoc_ssc_remove),
|
||||
};
|
||||
|
||||
/**
|
||||
* atmel_ssc_set_audio - Allocate the specified SSC for audio use.
|
||||
*/
|
||||
int atmel_ssc_set_audio(int ssc_id)
|
||||
{
|
||||
struct ssc_device *ssc;
|
||||
static struct platform_device *dma_pdev;
|
||||
struct platform_device *ssc_pdev;
|
||||
int ret;
|
||||
|
||||
if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate a dummy device for DMA if we don't have one already */
|
||||
if (!dma_pdev) {
|
||||
dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
|
||||
if (!dma_pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = platform_device_add(dma_pdev);
|
||||
if (ret < 0) {
|
||||
platform_device_put(dma_pdev);
|
||||
dma_pdev = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
|
||||
if (!ssc_pdev) {
|
||||
ssc_free(ssc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* If we can grab the SSC briefly to parent the DAI device off it */
|
||||
ssc = ssc_request(ssc_id);
|
||||
if (IS_ERR(ssc))
|
||||
pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
|
||||
PTR_ERR(ssc));
|
||||
else
|
||||
ssc_pdev->dev.parent = &(ssc->pdev->dev);
|
||||
ssc_free(ssc);
|
||||
|
||||
ret = platform_device_add(ssc_pdev);
|
||||
if (ret < 0)
|
||||
platform_device_put(ssc_pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
|
||||
|
||||
static int __init snd_atmel_ssc_init(void)
|
||||
{
|
||||
return platform_driver_register(&asoc_ssc_driver);
|
||||
}
|
||||
module_init(snd_atmel_ssc_init);
|
||||
|
||||
static void __exit snd_atmel_ssc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&asoc_ssc_driver);
|
||||
}
|
||||
module_exit(snd_atmel_ssc_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Sedji Gaouaou, [email protected], www.atmel.com");
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ struct atmel_ssc_info {
|
|||
struct atmel_pcm_dma_params *dma_params[2];
|
||||
struct atmel_ssc_state ssc_state;
|
||||
};
|
||||
extern struct snd_soc_dai atmel_ssc_dai[];
|
||||
|
||||
int atmel_ssc_set_audio(int ssc);
|
||||
|
||||
#endif /* _AT91_SSC_DAI_H */
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct at32_ssc_info *ssc_p = cpu_dai->private_data;
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
struct ssc_clock_data cd;
|
||||
unsigned int rate, width_bits, channels;
|
||||
|
|
@ -131,9 +131,9 @@ static int playpaq_wm8510_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 *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct at32_ssc_info *ssc_p = cpu_dai->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
|
||||
int ret;
|
||||
|
|
@ -315,8 +315,9 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
|
||||
|
||||
|
||||
static int playpaq_wm8510_init(struct snd_soc_codec *codec)
|
||||
static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
|
@ -342,7 +343,7 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
|
|||
|
||||
|
||||
/* Make CSB show PLL rate */
|
||||
snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
|
||||
snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
|
||||
WM8510_OPCLKDIV_1 | 4);
|
||||
|
||||
return 0;
|
||||
|
|
@ -353,8 +354,10 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_dai_link playpaq_wm8510_dai = {
|
||||
.name = "WM8510",
|
||||
.stream_name = "WM8510 PCM",
|
||||
.cpu_dai = &at32_ssc_dai[0],
|
||||
.codec_dai = &wm8510_dai,
|
||||
.cpu_dai_name= "atmel-ssc-dai.0",
|
||||
.platform_name = "atmel-pcm-audio",
|
||||
.codec_name = "wm8510-codec.0-0x1a",
|
||||
.codec_dai_name = "wm8510-hifi",
|
||||
.init = playpaq_wm8510_init,
|
||||
.ops = &playpaq_wm8510_ops,
|
||||
};
|
||||
|
|
@ -363,46 +366,16 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
|
|||
|
||||
static struct snd_soc_card snd_soc_playpaq = {
|
||||
.name = "LRS_PlayPaq_WM8510",
|
||||
.platform = &at32_soc_platform,
|
||||
.dai_link = &playpaq_wm8510_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct wm8510_setup_data playpaq_wm8510_setup = {
|
||||
.i2c_bus = 0,
|
||||
.i2c_address = 0x1a,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_device playpaq_wm8510_snd_devdata = {
|
||||
.card = &snd_soc_playpaq,
|
||||
.codec_dev = &soc_codec_dev_wm8510,
|
||||
.codec_data = &playpaq_wm8510_setup,
|
||||
};
|
||||
|
||||
static struct platform_device *playpaq_snd_device;
|
||||
|
||||
|
||||
static int __init playpaq_asoc_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Request SSC device
|
||||
*/
|
||||
ssc = ssc_request(0);
|
||||
if (IS_ERR(ssc)) {
|
||||
ret = PTR_ERR(ssc);
|
||||
goto err_ssc;
|
||||
}
|
||||
ssc_p->ssc = ssc;
|
||||
|
||||
|
||||
/*
|
||||
* Configure MCLK for WM8510
|
||||
|
|
@ -439,8 +412,7 @@ static int __init playpaq_asoc_init(void)
|
|||
goto err_device_alloc;
|
||||
}
|
||||
|
||||
platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
|
||||
playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
|
||||
platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
|
||||
|
||||
ret = platform_device_add(playpaq_snd_device);
|
||||
if (ret) {
|
||||
|
|
@ -468,25 +440,12 @@ err_pll0:
|
|||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
}
|
||||
err_gclk0:
|
||||
ssc_free(ssc);
|
||||
err_ssc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void __exit playpaq_asoc_exit(void)
|
||||
{
|
||||
struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc;
|
||||
|
||||
if (ssc_p != NULL) {
|
||||
ssc = ssc_p->ssc;
|
||||
if (ssc != NULL)
|
||||
ssc_free(ssc);
|
||||
ssc_p->ssc = NULL;
|
||||
}
|
||||
|
||||
if (_gclk0 != NULL) {
|
||||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ static int at91sam9g20ek_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 *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int ret;
|
||||
|
||||
/* set codec DAI configuration */
|
||||
|
|
@ -136,16 +136,17 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
/*
|
||||
* Logic for a wm8731 as connected on a at91sam9g20ek board.
|
||||
*/
|
||||
static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
|
||||
static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = &codec->dai[0];
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
printk(KERN_DEBUG
|
||||
"at91sam9g20ek_wm8731 "
|
||||
": at91sam9g20ek_wm8731_init() called\n");
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
MCLK_RATE, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
|
||||
|
|
@ -179,37 +180,37 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_dai_link at91sam9g20ek_dai = {
|
||||
.name = "WM8731",
|
||||
.stream_name = "WM8731 PCM",
|
||||
.cpu_dai = &atmel_ssc_dai[0],
|
||||
.codec_dai = &wm8731_dai,
|
||||
.cpu_dai_name = "atmel-ssc-dai.0",
|
||||
.codec_dai_name = "wm8731-hifi",
|
||||
.init = at91sam9g20ek_wm8731_init,
|
||||
.platform_name = "atmel-pcm-audio",
|
||||
.codec_name = "wm8731-codec.0-001b",
|
||||
.ops = &at91sam9g20ek_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_at91sam9g20ek = {
|
||||
.name = "AT91SAMG20-EK",
|
||||
.platform = &atmel_soc_platform,
|
||||
.dai_link = &at91sam9g20ek_dai,
|
||||
.num_links = 1,
|
||||
.set_bias_level = at91sam9g20ek_set_bias_level,
|
||||
};
|
||||
|
||||
static struct snd_soc_device at91sam9g20ek_snd_devdata = {
|
||||
.card = &snd_soc_at91sam9g20ek,
|
||||
.codec_dev = &soc_codec_dev_wm8731,
|
||||
};
|
||||
|
||||
static struct platform_device *at91sam9g20ek_snd_device;
|
||||
|
||||
static int __init at91sam9g20ek_init(void)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc = NULL;
|
||||
struct clk *pllb;
|
||||
int ret;
|
||||
|
||||
if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
|
||||
return -ENODEV;
|
||||
|
||||
ret = atmel_ssc_set_audio(0);
|
||||
if (ret != 0) {
|
||||
pr_err("Failed to set SSC 0 for audio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Codec MCLK is supplied by PCK0 - set it up.
|
||||
*/
|
||||
|
|
@ -235,18 +236,6 @@ static int __init at91sam9g20ek_init(void)
|
|||
|
||||
clk_set_rate(mclk, MCLK_RATE);
|
||||
|
||||
/*
|
||||
* Request SSC device
|
||||
*/
|
||||
ssc = ssc_request(0);
|
||||
if (IS_ERR(ssc)) {
|
||||
printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
|
||||
ret = PTR_ERR(ssc);
|
||||
ssc = NULL;
|
||||
goto err_ssc;
|
||||
}
|
||||
ssc_p->ssc = ssc;
|
||||
|
||||
at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!at91sam9g20ek_snd_device) {
|
||||
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
|
||||
|
|
@ -254,8 +243,7 @@ static int __init at91sam9g20ek_init(void)
|
|||
}
|
||||
|
||||
platform_set_drvdata(at91sam9g20ek_snd_device,
|
||||
&at91sam9g20ek_snd_devdata);
|
||||
at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
|
||||
&snd_soc_at91sam9g20ek);
|
||||
|
||||
ret = platform_device_add(at91sam9g20ek_snd_device);
|
||||
if (ret) {
|
||||
|
|
@ -265,9 +253,6 @@ static int __init at91sam9g20ek_init(void)
|
|||
|
||||
return ret;
|
||||
|
||||
err_ssc:
|
||||
ssc_free(ssc);
|
||||
ssc_p->ssc = NULL;
|
||||
err_mclk:
|
||||
clk_put(mclk);
|
||||
mclk = NULL;
|
||||
|
|
@ -277,16 +262,6 @@ err:
|
|||
|
||||
static void __exit at91sam9g20ek_exit(void)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc;
|
||||
|
||||
if (ssc_p != NULL) {
|
||||
ssc = ssc_p->ssc;
|
||||
if (ssc != NULL)
|
||||
ssc_free(ssc);
|
||||
ssc_p->ssc = NULL;
|
||||
}
|
||||
|
||||
platform_device_unregister(at91sam9g20ek_snd_device);
|
||||
at91sam9g20ek_snd_device = NULL;
|
||||
clk_put(mclk);
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ static int afeb9260_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 *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int err;
|
||||
|
||||
/* Set codec DAI configuration */
|
||||
|
|
@ -102,8 +102,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|||
{"MICIN", NULL, "Mic Jack"},
|
||||
};
|
||||
|
||||
static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
|
||||
static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* Add afeb9260 specific widgets */
|
||||
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
|
||||
|
|
@ -125,8 +126,10 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_dai_link afeb9260_dai = {
|
||||
.name = "TLV320AIC23",
|
||||
.stream_name = "AIC23",
|
||||
.cpu_dai = &atmel_ssc_dai[0],
|
||||
.codec_dai = &tlv320aic23_dai,
|
||||
.cpu_dai_name = "atmel-ssc-dai.0",
|
||||
.codec_dai_name = "tlv320aic23-hifi",
|
||||
.platform_name = "atmel_pcm-audio",
|
||||
.codec_name = "tlv320aic23-codec.0-0x1a",
|
||||
.init = afeb9260_tlv320aic23_init,
|
||||
.ops = &afeb9260_ops,
|
||||
};
|
||||
|
|
@ -134,37 +137,20 @@ static struct snd_soc_dai_link afeb9260_dai = {
|
|||
/* Audio machine driver */
|
||||
static struct snd_soc_card snd_soc_machine_afeb9260 = {
|
||||
.name = "AFEB9260",
|
||||
.platform = &atmel_soc_platform,
|
||||
.dai_link = &afeb9260_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
/* Audio subsystem */
|
||||
static struct snd_soc_device afeb9260_snd_devdata = {
|
||||
.card = &snd_soc_machine_afeb9260,
|
||||
.codec_dev = &soc_codec_dev_tlv320aic23,
|
||||
};
|
||||
|
||||
static struct platform_device *afeb9260_snd_device;
|
||||
|
||||
static int __init afeb9260_soc_init(void)
|
||||
{
|
||||
int err;
|
||||
struct device *dev;
|
||||
struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
|
||||
struct ssc_device *ssc = NULL;
|
||||
|
||||
if (!(machine_is_afeb9260()))
|
||||
return -ENODEV;
|
||||
|
||||
ssc = ssc_request(0);
|
||||
if (IS_ERR(ssc)) {
|
||||
printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
|
||||
err = PTR_ERR(ssc);
|
||||
ssc = NULL;
|
||||
goto err_ssc;
|
||||
}
|
||||
ssc_p->ssc = ssc;
|
||||
|
||||
afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!afeb9260_snd_device) {
|
||||
|
|
@ -172,8 +158,7 @@ static int __init afeb9260_soc_init(void)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
|
||||
afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
|
||||
platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
|
||||
err = platform_device_add(afeb9260_snd_device);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
|
@ -184,9 +169,7 @@ static int __init afeb9260_soc_init(void)
|
|||
err1:
|
||||
platform_device_del(afeb9260_snd_device);
|
||||
platform_device_put(afeb9260_snd_device);
|
||||
err_ssc:
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static void __exit afeb9260_soc_exit(void)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <asm/mach-au1x00/au1xxx_dbdma.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
#include "../codecs/ac97.h"
|
||||
#include "../codecs/wm8731.h"
|
||||
#include "psc.h"
|
||||
|
||||
|
|
@ -28,20 +27,16 @@
|
|||
static struct snd_soc_dai_link db1200_ac97_dai = {
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai = &au1xpsc_ac97_dai,
|
||||
.codec_dai = &ac97_dai,
|
||||
.codec_dai_name = "ac97-hifi",
|
||||
.cpu_dai_name = "au1xpsc_ac97.1",
|
||||
.platform_name = "au1xpsc-pcm.1",
|
||||
.codec_name = "ac97-codec.1",
|
||||
};
|
||||
|
||||
static struct snd_soc_card db1200_ac97_machine = {
|
||||
.name = "DB1200_AC97",
|
||||
.dai_link = &db1200_ac97_dai,
|
||||
.num_links = 1,
|
||||
.platform = &au1xpsc_soc_platform,
|
||||
};
|
||||
|
||||
static struct snd_soc_device db1200_ac97_devdata = {
|
||||
.card = &db1200_ac97_machine,
|
||||
.codec_dev = &soc_codec_dev_ac97,
|
||||
};
|
||||
|
||||
/*------------------------- I2S PART ---------------------------*/
|
||||
|
|
@ -49,12 +44,12 @@ static struct snd_soc_device db1200_ac97_devdata = {
|
|||
static int db1200_i2s_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int ret;
|
||||
|
||||
/* WM8731 has its own 12MHz crystal */
|
||||
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
|
||||
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
12000000, SND_SOC_CLOCK_IN);
|
||||
|
||||
/* codec is bitclock and lrclk master */
|
||||
|
|
@ -80,8 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
|
|||
static struct snd_soc_dai_link db1200_i2s_dai = {
|
||||
.name = "WM8731",
|
||||
.stream_name = "WM8731 PCM",
|
||||
.cpu_dai = &au1xpsc_i2s_dai,
|
||||
.codec_dai = &wm8731_dai,
|
||||
.codec_dai_name = "wm8731-hifi",
|
||||
.cpu_dai_name = "au1xpsc_i2s.1",
|
||||
.platform_name = "au1xpsc-pcm.1",
|
||||
.codec_name = "wm8731-codec.0-001b",
|
||||
.ops = &db1200_i2s_wm8731_ops,
|
||||
};
|
||||
|
||||
|
|
@ -89,12 +86,6 @@ static struct snd_soc_card db1200_i2s_machine = {
|
|||
.name = "DB1200_I2S",
|
||||
.dai_link = &db1200_i2s_dai,
|
||||
.num_links = 1,
|
||||
.platform = &au1xpsc_soc_platform,
|
||||
};
|
||||
|
||||
static struct snd_soc_device db1200_i2s_devdata = {
|
||||
.card = &db1200_i2s_machine,
|
||||
.codec_dev = &soc_codec_dev_wm8731,
|
||||
};
|
||||
|
||||
/*------------------------- COMMON PART ---------------------------*/
|
||||
|
|
@ -106,18 +97,16 @@ static int __init db1200_audio_load(void)
|
|||
int ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
|
||||
db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
|
||||
if (!db1200_asoc_dev)
|
||||
goto out;
|
||||
|
||||
/* DB1200 board setup set PSC1MUX to preferred audio device */
|
||||
if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
|
||||
else
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
|
||||
|
||||
db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
|
||||
db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
|
||||
ret = platform_device_add(db1200_asoc_dev);
|
||||
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*
|
||||
* DMA glue for Au1x-PSC audio.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
|
|||
int msbits;
|
||||
};
|
||||
|
||||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
|
||||
|
||||
/*
|
||||
* These settings are somewhat okay, at least on my machine audio plays
|
||||
* almost skip-free. Especially the 64kB buffer seems to help a LOT.
|
||||
|
|
@ -199,6 +193,14 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
struct au1xpsc_audio_dmadata *pcd =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
return &pcd[SUBSTREAM_TYPE(ss)];
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
|
|
@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
goto out;
|
||||
|
||||
stype = SUBSTREAM_TYPE(substream);
|
||||
pcd = au1xpsc_audio_pcmdma[stype];
|
||||
pcd = to_dmadata(substream);
|
||||
|
||||
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
|
||||
"runtime->min_align %d\n",
|
||||
|
|
@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
|
||||
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *pcd =
|
||||
au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
|
||||
|
||||
au1xxx_dbdma_reset(pcd->ddma_chan);
|
||||
|
||||
|
|
@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
|
||||
u32 c = to_dmadata(substream)->ddma_chan;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
|
|
@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
static snd_pcm_uframes_t
|
||||
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return bytes_to_frames(substream->runtime,
|
||||
au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
|
||||
return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
||||
|
|
@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
|||
|
||||
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
|
||||
au1x_pcm_dbdma_free(to_dmadata(substream));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* au1xpsc audio platform */
|
||||
struct snd_soc_platform au1xpsc_soc_platform = {
|
||||
.name = "au1xpsc-pcm-dbdma",
|
||||
.probe = au1xpsc_pcm_probe,
|
||||
.remove = au1xpsc_pcm_remove,
|
||||
.pcm_ops = &au1xpsc_pcm_ops,
|
||||
struct snd_soc_platform_driver au1xpsc_soc_platform = {
|
||||
.ops = &au1xpsc_pcm_ops,
|
||||
.pcm_new = au1xpsc_pcm_new,
|
||||
.pcm_free = au1xpsc_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
|
||||
|
||||
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *dmadata;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
|
||||
return -EBUSY;
|
||||
|
||||
/* TX DMA */
|
||||
au1xpsc_audio_pcmdma[PCM_TX]
|
||||
= kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!au1xpsc_audio_pcmdma[PCM_TX])
|
||||
dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
|
|
@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
|||
ret = -ENODEV;
|
||||
goto out1;
|
||||
}
|
||||
(au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
|
||||
dmadata[PCM_TX].ddma_id = r->start;
|
||||
|
||||
/* RX DMA */
|
||||
au1xpsc_audio_pcmdma[PCM_RX]
|
||||
= kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!au1xpsc_audio_pcmdma[PCM_RX])
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out2;
|
||||
goto out1;
|
||||
}
|
||||
(au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
|
||||
dmadata[PCM_RX].ddma_id = r->start;
|
||||
|
||||
ret = snd_soc_register_platform(&au1xpsc_soc_platform);
|
||||
platform_set_drvdata(pdev, dmadata);
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
out2:
|
||||
kfree(au1xpsc_audio_pcmdma[PCM_RX]);
|
||||
au1xpsc_audio_pcmdma[PCM_RX] = NULL;
|
||||
out1:
|
||||
kfree(au1xpsc_audio_pcmdma[PCM_TX]);
|
||||
au1xpsc_audio_pcmdma[PCM_TX] = NULL;
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_platform(&au1xpsc_soc_platform);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (au1xpsc_audio_pcmdma[i]) {
|
||||
au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
|
||||
kfree(au1xpsc_audio_pcmdma[i]);
|
||||
au1xpsc_audio_pcmdma[i] = NULL;
|
||||
}
|
||||
}
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
kfree(dmadata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
|
|||
|
||||
static int __init au1xpsc_audio_dbdma_load(void)
|
||||
{
|
||||
au1xpsc_audio_pcmdma[PCM_TX] = NULL;
|
||||
au1xpsc_audio_pcmdma[PCM_RX] = NULL;
|
||||
return platform_driver_register(&au1xpsc_pcm_driver);
|
||||
}
|
||||
|
||||
|
|
@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
|
|||
res[1].start = res[1].end = id[1];
|
||||
res[0].flags = res[1].flags = IORESOURCE_DMA;
|
||||
|
||||
pd = platform_device_alloc("au1xpsc-pcm", -1);
|
||||
pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
|
||||
if (!pd)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*
|
||||
* Au1xxx-PSC AC97 glue.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
|
@ -56,12 +53,29 @@
|
|||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
|
||||
|
||||
#if 0
|
||||
|
||||
/* this could theoretically work, but ac97->bus->card->private_data can be NULL
|
||||
* when snd_ac97_mixer() is called; I don't know if the rest further down the
|
||||
* chain are always valid either.
|
||||
*/
|
||||
static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
|
||||
{
|
||||
struct snd_soc_card *c = x->bus->card->private_data;
|
||||
return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ac97_to_pscdata(x) au1xpsc_ac97_workdata
|
||||
|
||||
#endif
|
||||
|
||||
/* AC97 controller reads codec register */
|
||||
static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
|
||||
unsigned short reg)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
unsigned short retry, tmo;
|
||||
unsigned long data;
|
||||
|
||||
|
|
@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
|
|||
static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||
unsigned short val)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
unsigned int tmo, retry;
|
||||
|
||||
au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
|
||||
|
|
@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
|||
/* AC97 controller asserts a warm reset */
|
||||
static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
|
||||
au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
|
||||
au_sync();
|
||||
|
|
@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
|
|||
|
||||
static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
|
||||
int i;
|
||||
|
||||
/* disable PSC during cold reset */
|
||||
|
|
@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long r, ro, stat;
|
||||
int chans, t, stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
|
|
@ -283,8 +293,7 @@ out:
|
|||
static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
/* FIXME */
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
ret = 0;
|
||||
|
|
@ -315,27 +324,19 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_ac97_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
return au1xpsc_ac97_workdata ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static void au1xpsc_ac97_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
|
||||
.trigger = au1xpsc_ac97_trigger,
|
||||
.hw_params = au1xpsc_ac97_hw_params,
|
||||
};
|
||||
|
||||
struct snd_soc_dai au1xpsc_ac97_dai = {
|
||||
.name = "au1xpsc_ac97",
|
||||
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
|
||||
.ac97_control = 1,
|
||||
.probe = au1xpsc_ac97_probe,
|
||||
.remove = au1xpsc_ac97_remove,
|
||||
.playback = {
|
||||
.rates = AC97_RATES,
|
||||
.formats = AC97_FMTS,
|
||||
|
|
@ -350,7 +351,6 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
|
|||
},
|
||||
.ops = &au1xpsc_ac97_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
|
||||
|
||||
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -359,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
|||
unsigned long sel;
|
||||
struct au1xpsc_audio_data *wd;
|
||||
|
||||
if (au1xpsc_ac97_workdata)
|
||||
return -EBUSY;
|
||||
|
||||
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
|
||||
if (!wd)
|
||||
return -ENOMEM;
|
||||
|
|
@ -395,18 +392,24 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
|||
au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
|
||||
au_sync();
|
||||
|
||||
ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
|
||||
/* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
|
||||
memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
|
||||
sizeof(struct snd_soc_dai_driver));
|
||||
wd->dai_drv.name = dev_name(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
wd->dmapd = au1xpsc_pcm_add(pdev);
|
||||
if (wd->dmapd) {
|
||||
platform_set_drvdata(pdev, wd);
|
||||
au1xpsc_ac97_workdata = wd; /* MDEV */
|
||||
au1xpsc_ac97_workdata = wd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_ac97_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
|
|
@ -422,7 +425,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
|
|||
if (wd->dmapd)
|
||||
au1xpsc_pcm_destroy(wd->dmapd);
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_ac97_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
/* disable PSC completely */
|
||||
au_writel(0, AC97_CFG(wd));
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*
|
||||
* Au1xxx-PSC I2S glue.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
* NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
|
||||
*/
|
||||
|
||||
|
|
@ -54,13 +51,10 @@
|
|||
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
|
||||
|
||||
|
||||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
|
||||
|
||||
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
unsigned long ct;
|
||||
int ret;
|
||||
|
||||
|
|
@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
int cfgbits;
|
||||
unsigned long stat;
|
||||
|
|
@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
|
|||
static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
switch (cmd) {
|
||||
|
|
@ -263,27 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_i2s_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
return au1xpsc_i2s_workdata ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static void au1xpsc_i2s_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
|
||||
.trigger = au1xpsc_i2s_trigger,
|
||||
.hw_params = au1xpsc_i2s_hw_params,
|
||||
.set_fmt = au1xpsc_i2s_set_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai au1xpsc_i2s_dai = {
|
||||
.name = "au1xpsc_i2s",
|
||||
.probe = au1xpsc_i2s_probe,
|
||||
.remove = au1xpsc_i2s_remove,
|
||||
static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
|
||||
.playback = {
|
||||
.rates = AU1XPSC_I2S_RATES,
|
||||
.formats = AU1XPSC_I2S_FMTS,
|
||||
|
|
@ -298,7 +278,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
|
|||
},
|
||||
.ops = &au1xpsc_i2s_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL(au1xpsc_i2s_dai);
|
||||
|
||||
static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -307,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
|||
int ret;
|
||||
struct au1xpsc_audio_data *wd;
|
||||
|
||||
if (au1xpsc_i2s_workdata)
|
||||
return -EBUSY;
|
||||
|
||||
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
|
||||
if (!wd)
|
||||
return -ENOMEM;
|
||||
|
|
@ -346,19 +322,23 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
|||
* time out.
|
||||
*/
|
||||
|
||||
ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
|
||||
/* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
|
||||
memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
|
||||
sizeof(struct snd_soc_dai_driver));
|
||||
wd->dai_drv.name = dev_name(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
/* finally add the DMA device for this PSC */
|
||||
wd->dmapd = au1xpsc_pcm_add(pdev);
|
||||
if (wd->dmapd) {
|
||||
platform_set_drvdata(pdev, wd);
|
||||
au1xpsc_i2s_workdata = wd;
|
||||
if (wd->dmapd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_i2s_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
|
|
@ -374,7 +354,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
|
|||
if (wd->dmapd)
|
||||
au1xpsc_pcm_destroy(wd->dmapd);
|
||||
|
||||
snd_soc_unregister_dai(&au1xpsc_i2s_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
au_writel(0, I2S_CFG(wd));
|
||||
au_sync();
|
||||
|
|
@ -385,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
|
|||
release_mem_region(r->start, resource_size(r));
|
||||
kfree(wd);
|
||||
|
||||
au1xpsc_i2s_workdata = NULL; /* MDEV */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
|
|||
|
||||
static int __init au1xpsc_i2s_load(void)
|
||||
{
|
||||
au1xpsc_i2s_workdata = NULL;
|
||||
return platform_driver_register(&au1xpsc_i2s_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,19 +8,11 @@
|
|||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* NOTE: all of these drivers can only work with a SINGLE instance
|
||||
* of a PSC. Multiple independent audio devices are impossible
|
||||
* with ASoC v1.
|
||||
*/
|
||||
|
||||
#ifndef _AU1X_PCM_H
|
||||
#define _AU1X_PCM_H
|
||||
|
||||
extern struct snd_soc_dai au1xpsc_ac97_dai;
|
||||
extern struct snd_soc_dai au1xpsc_i2s_dai;
|
||||
extern struct snd_soc_platform au1xpsc_soc_platform;
|
||||
extern struct snd_ac97_bus_ops soc_ac97_ops;
|
||||
|
||||
/* DBDMA helpers */
|
||||
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
|
||||
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
|
||||
|
|
@ -31,6 +23,8 @@ struct au1xpsc_audio_data {
|
|||
unsigned long cfg;
|
||||
unsigned long rate;
|
||||
|
||||
struct snd_soc_dai_driver dai_drv;
|
||||
|
||||
unsigned long pm[2];
|
||||
struct mutex lock;
|
||||
struct platform_device *dmapd;
|
||||
|
|
|
|||
|
|
@ -422,14 +422,14 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
|
|
@ -439,25 +439,44 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct snd_soc_platform bf5xx_ac97_soc_platform = {
|
||||
.name = "bf5xx-audio",
|
||||
.pcm_ops = &bf5xx_pcm_ac97_ops,
|
||||
static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
|
||||
.ops = &bf5xx_pcm_ac97_ops,
|
||||
.pcm_new = bf5xx_pcm_ac97_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
|
||||
|
||||
static int __init bfin_ac97_init(void)
|
||||
static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
|
||||
}
|
||||
module_init(bfin_ac97_init);
|
||||
|
||||
static void __exit bfin_ac97_exit(void)
|
||||
static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(bfin_ac97_exit);
|
||||
|
||||
static struct platform_driver bf5xx_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bf5xx-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = bf5xx_soc_platform_probe,
|
||||
.remove = __devexit_p(bf5xx_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_bf5xx_pcm_init(void)
|
||||
{
|
||||
return platform_driver_register(&bf5xx_pcm_driver);
|
||||
}
|
||||
module_init(snd_bf5xx_pcm_init);
|
||||
|
||||
static void __exit snd_bf5xx_pcm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bf5xx_pcm_driver);
|
||||
}
|
||||
module_exit(snd_bf5xx_pcm_exit);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,4 @@ struct bf5xx_gpio {
|
|||
u32 frm;
|
||||
};
|
||||
|
||||
/* platform data */
|
||||
extern struct snd_soc_platform bf5xx_ac97_soc_platform;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
|
|||
#ifdef CONFIG_PM
|
||||
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = dai->private_data;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
|
|
@ -270,7 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
|
|||
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
struct sport_device *sport = dai->private_data;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
|
|
@ -306,8 +306,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
|||
#define bf5xx_ac97_resume NULL
|
||||
#endif
|
||||
|
||||
static int bf5xx_ac97_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret = 0;
|
||||
cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
|
||||
|
|
@ -379,8 +378,7 @@ peripheral_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void bf5xx_ac97_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
free_page((unsigned long)cmd_count);
|
||||
cmd_count = NULL;
|
||||
|
|
@ -388,11 +386,10 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
|
|||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_dai bfin_ac97_dai = {
|
||||
.name = "bf5xx-ac97",
|
||||
.id = 0,
|
||||
struct snd_soc_dai_driver bfin_ac97_dai = {
|
||||
.ac97_control = 1,
|
||||
.probe = bf5xx_ac97_probe,
|
||||
.remove = bf5xx_ac97_remove,
|
||||
|
|
@ -417,18 +414,40 @@ struct snd_soc_dai bfin_ac97_dai = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(bfin_ac97_dai);
|
||||
|
||||
static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
|
||||
}
|
||||
|
||||
static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver asoc_bfin_ac97_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-ac97",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = asoc_bfin_ac97_probe,
|
||||
.remove = __devexit_p(asoc_bfin_ac97_remove),
|
||||
};
|
||||
|
||||
static int __init bfin_ac97_init(void)
|
||||
{
|
||||
return snd_soc_register_dai(&bfin_ac97_dai);
|
||||
return platform_driver_register(&asoc_bfin_ac97_driver);
|
||||
}
|
||||
module_init(bfin_ac97_init);
|
||||
|
||||
static void __exit bfin_ac97_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&bfin_ac97_dai);
|
||||
platform_driver_unregister(&asoc_bfin_ac97_driver);
|
||||
}
|
||||
module_exit(bfin_ac97_exit);
|
||||
|
||||
|
||||
MODULE_AUTHOR("Roy Huang");
|
||||
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@ struct ac97_frame {
|
|||
#define TAG_PCM_SR 0x0080
|
||||
#define TAG_PCM_LFE 0x0040
|
||||
|
||||
extern struct snd_soc_dai bfin_ac97_dai;
|
||||
|
||||
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
|
||||
size_t count, unsigned int chan_mask);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ static struct snd_soc_card bf5xx_ad1836;
|
|||
static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ static int bf5xx_ad1836_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->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
|
||||
int ret = 0;
|
||||
/* set cpu DAI configuration */
|
||||
|
|
@ -83,23 +83,19 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
|
||||
.name = "ad1836",
|
||||
.stream_name = "AD1836",
|
||||
.cpu_dai = &bf5xx_tdm_dai,
|
||||
.codec_dai = &ad1836_dai,
|
||||
.cpu_dai_name = "bf5xx-tdm",
|
||||
.codec_dai_name = "ad1836-hifi",
|
||||
.platform_name = "bf5xx-tdm-pcm-audio",
|
||||
.codec_name = "ad1836-codec.0",
|
||||
.ops = &bf5xx_ad1836_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad1836 = {
|
||||
.name = "bf5xx_ad1836",
|
||||
.platform = &bf5xx_tdm_soc_platform,
|
||||
.dai_link = &bf5xx_ad1836_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
|
||||
.card = &bf5xx_ad1836,
|
||||
.codec_dev = &soc_codec_dev_ad1836,
|
||||
};
|
||||
|
||||
static struct platform_device *bfxx_ad1836_snd_device;
|
||||
|
||||
static int __init bf5xx_ad1836_init(void)
|
||||
|
|
@ -110,8 +106,7 @@ static int __init bf5xx_ad1836_init(void)
|
|||
if (!bfxx_ad1836_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
|
||||
bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
|
||||
platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
|
||||
ret = platform_device_add(bfxx_ad1836_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ static struct snd_soc_card bf5xx_ad193x;
|
|||
static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -59,8 +59,8 @@ static int bf5xx_ad193x_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->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
int ret = 0;
|
||||
/* set cpu DAI configuration */
|
||||
|
|
@ -97,23 +97,19 @@ static struct snd_soc_ops bf5xx_ad193x_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ad193x_dai = {
|
||||
.name = "ad193x",
|
||||
.stream_name = "AD193X",
|
||||
.cpu_dai = &bf5xx_tdm_dai,
|
||||
.codec_dai = &ad193x_dai,
|
||||
.cpu_dai_name = "bf5xx-tdm",
|
||||
.codec_dai_name ="ad193x-hifi",
|
||||
.platform_name = "bf5xx-tdm-pcm-audio",
|
||||
.codec_name = "ad193x-codec.5",
|
||||
.ops = &bf5xx_ad193x_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad193x = {
|
||||
.name = "bf5xx_ad193x",
|
||||
.platform = &bf5xx_tdm_soc_platform,
|
||||
.dai_link = &bf5xx_ad193x_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
|
||||
.card = &bf5xx_ad193x,
|
||||
.codec_dev = &soc_codec_dev_ad193x,
|
||||
};
|
||||
|
||||
static struct platform_device *bfxx_ad193x_snd_device;
|
||||
|
||||
static int __init bf5xx_ad193x_init(void)
|
||||
|
|
@ -124,8 +120,7 @@ static int __init bf5xx_ad193x_init(void)
|
|||
if (!bfxx_ad193x_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
|
||||
bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
|
||||
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
|
||||
ret = platform_device_add(bfxx_ad193x_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@ static struct snd_soc_card bf5xx_board;
|
|||
static int bf5xx_board_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -70,23 +70,19 @@ static struct snd_soc_ops bf5xx_board_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_board_dai = {
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai = &bfin_ac97_dai,
|
||||
.codec_dai = &ad1980_dai,
|
||||
.cpu_dai_name = "bfin-ac97",
|
||||
.codec_dai_name = "ad1980-hifi",
|
||||
.platform_name = "bfin-pcm-audio",
|
||||
.codec_name = "ad1980-codec",
|
||||
.ops = &bf5xx_board_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_board = {
|
||||
.name = "bf5xx-board",
|
||||
.platform = &bf5xx_ac97_soc_platform,
|
||||
.dai_link = &bf5xx_board_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_board_snd_devdata = {
|
||||
.card = &bf5xx_board,
|
||||
.codec_dev = &soc_codec_dev_ad1980,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_board_snd_device;
|
||||
|
||||
static int __init bf5xx_board_init(void)
|
||||
|
|
@ -97,8 +93,7 @@ static int __init bf5xx_board_init(void)
|
|||
if (!bf5xx_board_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
|
||||
bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
|
||||
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
|
||||
ret = platform_device_add(bf5xx_board_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include "../codecs/ad73311.h"
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
|
||||
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
|
||||
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
|
||||
|
|
@ -150,10 +149,10 @@ static int bf5xx_probe(struct platform_device *pdev)
|
|||
static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +160,7 @@ static int bf5xx_ad73311_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->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
|
||||
|
|
@ -185,24 +184,20 @@ static struct snd_soc_ops bf5xx_ad73311_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ad73311_dai = {
|
||||
.name = "ad73311",
|
||||
.stream_name = "AD73311",
|
||||
.cpu_dai = &bf5xx_i2s_dai,
|
||||
.codec_dai = &ad73311_dai,
|
||||
.cpu_dai_name = "bf5xx-i2s",
|
||||
.codec_dai_name = "ad73311-hifi",
|
||||
.platform_name = "bfin-pcm-audio",
|
||||
.codec_name = "ad73311-codec",
|
||||
.ops = &bf5xx_ad73311_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad73311 = {
|
||||
.name = "bf5xx_ad73311",
|
||||
.platform = &bf5xx_i2s_soc_platform,
|
||||
.probe = bf5xx_probe,
|
||||
.dai_link = &bf5xx_ad73311_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
|
||||
.card = &bf5xx_ad73311,
|
||||
.codec_dev = &soc_codec_dev_ad73311,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ad73311_snd_device;
|
||||
|
||||
static int __init bf5xx_ad73311_init(void)
|
||||
|
|
@ -214,8 +209,7 @@ static int __init bf5xx_ad73311_init(void)
|
|||
if (!bf5xx_ad73311_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
|
||||
bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
|
||||
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
|
||||
ret = platform_device_add(bf5xx_ad73311_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include <asm/dma.h>
|
||||
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
static void bf5xx_dma_irq(void *data)
|
||||
|
|
@ -257,14 +256,14 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
|
|
@ -274,25 +273,44 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct snd_soc_platform bf5xx_i2s_soc_platform = {
|
||||
.name = "bf5xx-audio",
|
||||
.pcm_ops = &bf5xx_pcm_i2s_ops,
|
||||
static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
|
||||
.ops = &bf5xx_pcm_i2s_ops,
|
||||
.pcm_new = bf5xx_pcm_i2s_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
|
||||
|
||||
static int __init bfin_i2s_init(void)
|
||||
static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
|
||||
}
|
||||
module_init(bfin_i2s_init);
|
||||
|
||||
static void __exit bfin_i2s_exit(void)
|
||||
static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(bfin_i2s_exit);
|
||||
|
||||
static struct platform_driver bfin_i2s_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = bfin_i2s_soc_platform_probe,
|
||||
.remove = __devexit_p(bfin_i2s_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_bfin_i2s_pcm_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_i2s_pcm_driver);
|
||||
}
|
||||
module_init(snd_bfin_i2s_pcm_init);
|
||||
|
||||
static void __exit snd_bfin_i2s_pcm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_i2s_pcm_driver);
|
||||
}
|
||||
module_exit(snd_bfin_i2s_pcm_exit);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,4 @@ struct bf5xx_gpio {
|
|||
u32 frm;
|
||||
};
|
||||
|
||||
/* platform data */
|
||||
extern struct snd_soc_platform bf5xx_i2s_soc_platform;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#include <linux/gpio.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
|
||||
struct bf5xx_i2s_port {
|
||||
u16 tcr1;
|
||||
|
|
@ -195,8 +194,7 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
|
|||
bf5xx_i2s.configured = 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_probe(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
|
||||
|
|
@ -215,11 +213,11 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bf5xx_i2s_remove(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai)
|
||||
static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
peripheral_free_list(&sport_req[sport_num][0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
@ -228,9 +226,9 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
|
|||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
|
||||
if (dai->capture.active)
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport_handle);
|
||||
if (dai->playback.active)
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -277,9 +275,7 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
|
|||
.set_fmt = bf5xx_i2s_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai bf5xx_i2s_dai = {
|
||||
.name = "bf5xx-i2s",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver bf5xx_i2s_dai = {
|
||||
.probe = bf5xx_i2s_probe,
|
||||
.remove = bf5xx_i2s_remove,
|
||||
.suspend = bf5xx_i2s_suspend,
|
||||
|
|
@ -296,18 +292,39 @@ struct snd_soc_dai bf5xx_i2s_dai = {
|
|||
.formats = BF5XX_I2S_FORMATS,},
|
||||
.ops = &bf5xx_i2s_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
|
||||
|
||||
static int bfin_i2s_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
|
||||
}
|
||||
|
||||
static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_driver = {
|
||||
.probe = bfin_i2s_drv_probe,
|
||||
.remove = __devexit_p(bfin_i2s_drv_remove),
|
||||
|
||||
.driver = {
|
||||
.name = "bf5xx-i2s",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init bfin_i2s_init(void)
|
||||
{
|
||||
return snd_soc_register_dai(&bf5xx_i2s_dai);
|
||||
return platform_driver_register(&bfin_i2s_driver);
|
||||
}
|
||||
module_init(bfin_i2s_init);
|
||||
|
||||
static void __exit bfin_i2s_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&bf5xx_i2s_dai);
|
||||
platform_driver_unregister(&bfin_i2s_driver);
|
||||
}
|
||||
|
||||
module_init(bfin_i2s_init);
|
||||
module_exit(bfin_i2s_exit);
|
||||
|
||||
/* Module information */
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* sound/soc/blackfin/bf5xx-i2s.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BF5XX_I2S_H
|
||||
#define _BF5XX_I2S_H
|
||||
|
||||
extern struct snd_soc_dai bf5xx_i2s_dai;
|
||||
|
||||
#endif
|
||||
|
|
@ -42,17 +42,16 @@
|
|||
#include "../codecs/ssm2602.h"
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
#include "bf5xx-i2s.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602;
|
||||
|
||||
static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
cpu_dai->private_data = sport_handle;
|
||||
snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -60,8 +59,8 @@ static int bf5xx_ssm2602_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 *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
unsigned int clk = 0;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -118,36 +117,19 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = {
|
|||
static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
|
||||
.name = "ssm2602",
|
||||
.stream_name = "SSM2602",
|
||||
.cpu_dai = &bf5xx_i2s_dai,
|
||||
.codec_dai = &ssm2602_dai,
|
||||
.cpu_dai_name = "bf5xx-i2s",
|
||||
.codec_dai_name = "ssm2602-hifi",
|
||||
.platform_name = "bf5xx-pcm-audio",
|
||||
.codec_name = "ssm2602-codec.0-0x1b",
|
||||
.ops = &bf5xx_ssm2602_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* SSM2602 2 wire address is determined by CSB
|
||||
* state during powerup.
|
||||
* low = 0x1a
|
||||
* high = 0x1b
|
||||
*/
|
||||
|
||||
static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
|
||||
.i2c_bus = 0,
|
||||
.i2c_address = 0x1b,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602 = {
|
||||
.name = "bf5xx_ssm2602",
|
||||
.platform = &bf5xx_i2s_soc_platform,
|
||||
.dai_link = &bf5xx_ssm2602_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
|
||||
.card = &bf5xx_ssm2602,
|
||||
.codec_dev = &soc_codec_dev_ssm2602,
|
||||
.codec_data = &bf5xx_ssm2602_setup,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ssm2602_snd_device;
|
||||
|
||||
static int __init bf5xx_ssm2602_init(void)
|
||||
|
|
@ -159,9 +141,7 @@ static int __init bf5xx_ssm2602_init(void)
|
|||
if (!bf5xx_ssm2602_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ssm2602_snd_device,
|
||||
&bf5xx_ssm2602_snd_devdata);
|
||||
bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
|
||||
platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
|
||||
ret = platform_device_add(bf5xx_ssm2602_snd_device);
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -290,14 +290,14 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
if (dai->playback.channels_min) {
|
||||
if (dai->driver->playback.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dai->capture.channels_min) {
|
||||
if (dai->driver->capture.channels_min) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
|
|
@ -307,25 +307,44 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct snd_soc_platform bf5xx_tdm_soc_platform = {
|
||||
.name = "bf5xx-audio",
|
||||
.pcm_ops = &bf5xx_pcm_tdm_ops,
|
||||
static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
|
||||
.ops = &bf5xx_pcm_tdm_ops,
|
||||
.pcm_new = bf5xx_pcm_tdm_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
|
||||
|
||||
static int __init bfin_pcm_tdm_init(void)
|
||||
static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
|
||||
return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
|
||||
}
|
||||
module_init(bfin_pcm_tdm_init);
|
||||
|
||||
static void __exit bfin_pcm_tdm_exit(void)
|
||||
static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(bfin_pcm_tdm_exit);
|
||||
|
||||
static struct platform_driver bfin_tdm_driver = {
|
||||
.driver = {
|
||||
.name = "bf5xx-tdm-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = bf5xx_soc_platform_probe,
|
||||
.remove = __devexit_p(bf5xx_soc_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_bfin_tdm_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_tdm_driver);
|
||||
}
|
||||
module_init(snd_bfin_tdm_init);
|
||||
|
||||
static void __exit snd_bfin_tdm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_tdm_driver);
|
||||
}
|
||||
module_exit(snd_bfin_tdm_exit);
|
||||
|
||||
MODULE_AUTHOR("Barry Song");
|
||||
MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
|
||||
|
|
|
|||
|
|
@ -15,7 +15,4 @@ struct bf5xx_pcm_dma_params {
|
|||
char *name; /* stream identifier */
|
||||
};
|
||||
|
||||
/* platform data */
|
||||
extern struct snd_soc_platform bf5xx_tdm_soc_platform;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -214,9 +214,9 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
|
|||
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
if (dai->capture.active)
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport);
|
||||
if (dai->playback.active)
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
|
|||
static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
struct sport_device *sport = dai->private_data;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
|
|
@ -262,9 +262,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
|
|||
.set_channel_map = bf5xx_tdm_set_channel_map,
|
||||
};
|
||||
|
||||
struct snd_soc_dai bf5xx_tdm_dai = {
|
||||
.name = "bf5xx-tdm",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver bf5xx_tdm_dai = {
|
||||
.suspend = bf5xx_tdm_suspend,
|
||||
.resume = bf5xx_tdm_resume,
|
||||
.playback = {
|
||||
|
|
@ -279,7 +277,6 @@ struct snd_soc_dai bf5xx_tdm_dai = {
|
|||
.formats = SNDRV_PCM_FMTBIT_S32_LE,},
|
||||
.ops = &bf5xx_tdm_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
|
||||
|
||||
static int __devinit bfin_tdm_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -320,7 +317,7 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
|
|||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&bf5xx_tdm_dai);
|
||||
ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
|
|
@ -337,7 +334,7 @@ sport_config_err:
|
|||
static int __devexit bfin_tdm_remove(struct platform_device *pdev)
|
||||
{
|
||||
peripheral_free_list(&sport_req[sport_num][0]);
|
||||
snd_soc_unregister_dai(&bf5xx_tdm_dai);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,4 @@ struct bf5xx_tdm_port {
|
|||
int configured;
|
||||
};
|
||||
|
||||
extern struct snd_soc_dai bf5xx_tdm_dai;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
1486
sound/soc/codecs/88pm860x-codec.c
Normal file
1486
sound/soc/codecs/88pm860x-codec.c
Normal file
File diff suppressed because it is too large
Load diff
97
sound/soc/codecs/88pm860x-codec.h
Normal file
97
sound/soc/codecs/88pm860x-codec.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
|
||||
*
|
||||
* Copyright 2010 Marvell International Ltd.
|
||||
* Haojian Zhuang <haojian.zhuang@marvell.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.
|
||||
*/
|
||||
|
||||
#ifndef __88PM860X_H
|
||||
#define __88PM860X_H
|
||||
|
||||
/* The offset of these registers are 0xb0 */
|
||||
#define PM860X_PCM_IFACE_1 0x00
|
||||
#define PM860X_PCM_IFACE_2 0x01
|
||||
#define PM860X_PCM_IFACE_3 0x02
|
||||
#define PM860X_PCM_RATE 0x03
|
||||
#define PM860X_EC_PATH 0x04
|
||||
#define PM860X_SIDETONE_L_GAIN 0x05
|
||||
#define PM860X_SIDETONE_R_GAIN 0x06
|
||||
#define PM860X_SIDETONE_SHIFT 0x07
|
||||
#define PM860X_ADC_OFFSET_1 0x08
|
||||
#define PM860X_ADC_OFFSET_2 0x09
|
||||
#define PM860X_DMIC_DELAY 0x0a
|
||||
|
||||
#define PM860X_I2S_IFACE_1 0x0b
|
||||
#define PM860X_I2S_IFACE_2 0x0c
|
||||
#define PM860X_I2S_IFACE_3 0x0d
|
||||
#define PM860X_I2S_IFACE_4 0x0e
|
||||
#define PM860X_EQUALIZER_N0_1 0x0f
|
||||
#define PM860X_EQUALIZER_N0_2 0x10
|
||||
#define PM860X_EQUALIZER_N1_1 0x11
|
||||
#define PM860X_EQUALIZER_N1_2 0x12
|
||||
#define PM860X_EQUALIZER_D1_1 0x13
|
||||
#define PM860X_EQUALIZER_D1_2 0x14
|
||||
#define PM860X_LOFI_GAIN_LEFT 0x15
|
||||
#define PM860X_LOFI_GAIN_RIGHT 0x16
|
||||
#define PM860X_HIFIL_GAIN_LEFT 0x17
|
||||
#define PM860X_HIFIL_GAIN_RIGHT 0x18
|
||||
#define PM860X_HIFIR_GAIN_LEFT 0x19
|
||||
#define PM860X_HIFIR_GAIN_RIGHT 0x1a
|
||||
#define PM860X_DAC_OFFSET 0x1b
|
||||
#define PM860X_OFFSET_LEFT_1 0x1c
|
||||
#define PM860X_OFFSET_LEFT_2 0x1d
|
||||
#define PM860X_OFFSET_RIGHT_1 0x1e
|
||||
#define PM860X_OFFSET_RIGHT_2 0x1f
|
||||
#define PM860X_ADC_ANA_1 0x20
|
||||
#define PM860X_ADC_ANA_2 0x21
|
||||
#define PM860X_ADC_ANA_3 0x22
|
||||
#define PM860X_ADC_ANA_4 0x23
|
||||
#define PM860X_ANA_TO_ANA 0x24
|
||||
#define PM860X_HS1_CTRL 0x25
|
||||
#define PM860X_HS2_CTRL 0x26
|
||||
#define PM860X_LO1_CTRL 0x27
|
||||
#define PM860X_LO2_CTRL 0x28
|
||||
#define PM860X_EAR_CTRL_1 0x29
|
||||
#define PM860X_EAR_CTRL_2 0x2a
|
||||
#define PM860X_AUDIO_SUPPLIES_1 0x2b
|
||||
#define PM860X_AUDIO_SUPPLIES_2 0x2c
|
||||
#define PM860X_ADC_EN_1 0x2d
|
||||
#define PM860X_ADC_EN_2 0x2e
|
||||
#define PM860X_DAC_EN_1 0x2f
|
||||
#define PM860X_DAC_EN_2 0x31
|
||||
#define PM860X_AUDIO_CAL_1 0x32
|
||||
#define PM860X_AUDIO_CAL_2 0x33
|
||||
#define PM860X_AUDIO_CAL_3 0x34
|
||||
#define PM860X_AUDIO_CAL_4 0x35
|
||||
#define PM860X_AUDIO_CAL_5 0x36
|
||||
#define PM860X_ANA_INPUT_SEL_1 0x37
|
||||
#define PM860X_ANA_INPUT_SEL_2 0x38
|
||||
|
||||
#define PM860X_PCM_IFACE_4 0x39
|
||||
#define PM860X_I2S_IFACE_5 0x3a
|
||||
|
||||
#define PM860X_SHORTS 0x3b
|
||||
#define PM860X_PLL_ADJ_1 0x3c
|
||||
#define PM860X_PLL_ADJ_2 0x3d
|
||||
|
||||
/* bits definition */
|
||||
#define PM860X_CLK_DIR_IN 0
|
||||
#define PM860X_CLK_DIR_OUT 1
|
||||
|
||||
#define PM860X_DET_HEADSET (1 << 0)
|
||||
#define PM860X_DET_MIC (1 << 1)
|
||||
#define PM860X_DET_HOOK (1 << 2)
|
||||
#define PM860X_SHORT_HEADSET (1 << 3)
|
||||
#define PM860X_SHORT_LINEOUT (1 << 4)
|
||||
#define PM860X_DET_MASK 0x1F
|
||||
|
||||
extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
|
||||
int, int, int, int);
|
||||
extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
|
||||
int);
|
||||
|
||||
#endif /* __88PM860X_H */
|
||||
|
|
@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
|
|||
|
||||
config SND_SOC_ALL_CODECS
|
||||
tristate "Build all ASoC CODEC drivers"
|
||||
select SND_SOC_88PM860X if MFD_88PM860X
|
||||
select SND_SOC_L3
|
||||
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD1836 if SPI_MASTER
|
||||
|
|
@ -26,6 +27,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_CS4270 if I2C
|
||||
select SND_SOC_DA7210 if I2C
|
||||
select SND_SOC_JZ4740 if SOC_JZ4740
|
||||
select SND_SOC_MAX98088 if I2C
|
||||
select SND_SOC_MAX9877 if I2C
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_SPDIF
|
||||
|
|
@ -40,6 +42,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_TWL6040 if TWL4030_CORE
|
||||
select SND_SOC_UDA134X
|
||||
select SND_SOC_UDA1380 if I2C
|
||||
select SND_SOC_WL1273 if WL1273_CORE
|
||||
select SND_SOC_WM2000 if I2C
|
||||
select SND_SOC_WM8350 if MFD_WM8350
|
||||
select SND_SOC_WM8400 if MFD_WM8400
|
||||
|
|
@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8900 if I2C
|
||||
select SND_SOC_WM8903 if I2C
|
||||
select SND_SOC_WM8904 if I2C
|
||||
|
|
@ -61,9 +65,11 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_WM8955 if I2C
|
||||
select SND_SOC_WM8960 if I2C
|
||||
select SND_SOC_WM8961 if I2C
|
||||
select SND_SOC_WM8962 if I2C
|
||||
select SND_SOC_WM8971 if I2C
|
||||
select SND_SOC_WM8974 if I2C
|
||||
select SND_SOC_WM8978 if I2C
|
||||
select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8990 if I2C
|
||||
select SND_SOC_WM8993 if I2C
|
||||
|
|
@ -84,6 +90,9 @@ config SND_SOC_ALL_CODECS
|
|||
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_88PM860X
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM_HUBS
|
||||
tristate
|
||||
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
|
||||
|
|
@ -150,6 +159,9 @@ config SND_SOC_L3
|
|||
config SND_SOC_DA7210
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98088
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM3008
|
||||
tristate
|
||||
|
||||
|
|
@ -188,6 +200,9 @@ config SND_SOC_UDA134X
|
|||
config SND_SOC_UDA1380
|
||||
tristate
|
||||
|
||||
config SND_SOC_WL1273
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8350
|
||||
tristate
|
||||
|
||||
|
|
@ -227,6 +242,9 @@ config SND_SOC_WM8753
|
|||
config SND_SOC_WM8776
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8804
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8900
|
||||
tristate
|
||||
|
||||
|
|
@ -248,6 +266,9 @@ config SND_SOC_WM8960
|
|||
config SND_SOC_WM8961
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8962
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8971
|
||||
tristate
|
||||
|
||||
|
|
@ -257,6 +278,9 @@ config SND_SOC_WM8974
|
|||
config SND_SOC_WM8978
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8985
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8988
|
||||
tristate
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
snd-soc-88pm860x-objs := 88pm860x-codec.o
|
||||
snd-soc-ac97-objs := ac97.o
|
||||
snd-soc-ad1836-objs := ad1836.o
|
||||
snd-soc-ad193x-objs := ad193x.o
|
||||
|
|
@ -14,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
|
|||
snd-soc-cx20442-objs := cx20442.o
|
||||
snd-soc-da7210-objs := da7210.o
|
||||
snd-soc-l3-objs := l3.o
|
||||
snd-soc-max98088-objs := max98088.o
|
||||
snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-spdif-objs := spdif_transciever.o
|
||||
snd-soc-ssm2602-objs := ssm2602.o
|
||||
|
|
@ -26,6 +28,7 @@ snd-soc-twl4030-objs := twl4030.o
|
|||
snd-soc-twl6040-objs := twl6040.o
|
||||
snd-soc-uda134x-objs := uda134x.o
|
||||
snd-soc-uda1380-objs := uda1380.o
|
||||
snd-soc-wl1273-objs := wl1273.o
|
||||
snd-soc-wm8350-objs := wm8350.o
|
||||
snd-soc-wm8400-objs := wm8400.o
|
||||
snd-soc-wm8510-objs := wm8510.o
|
||||
|
|
@ -39,6 +42,7 @@ snd-soc-wm8741-objs := wm8741.o
|
|||
snd-soc-wm8750-objs := wm8750.o
|
||||
snd-soc-wm8753-objs := wm8753.o
|
||||
snd-soc-wm8776-objs := wm8776.o
|
||||
snd-soc-wm8804-objs := wm8804.o
|
||||
snd-soc-wm8900-objs := wm8900.o
|
||||
snd-soc-wm8903-objs := wm8903.o
|
||||
snd-soc-wm8904-objs := wm8904.o
|
||||
|
|
@ -46,9 +50,11 @@ snd-soc-wm8940-objs := wm8940.o
|
|||
snd-soc-wm8955-objs := wm8955.o
|
||||
snd-soc-wm8960-objs := wm8960.o
|
||||
snd-soc-wm8961-objs := wm8961.o
|
||||
snd-soc-wm8962-objs := wm8962.o
|
||||
snd-soc-wm8971-objs := wm8971.o
|
||||
snd-soc-wm8974-objs := wm8974.o
|
||||
snd-soc-wm8978-objs := wm8978.o
|
||||
snd-soc-wm8985-objs := wm8985.o
|
||||
snd-soc-wm8988-objs := wm8988.o
|
||||
snd-soc-wm8990-objs := wm8990.o
|
||||
snd-soc-wm8993-objs := wm8993.o
|
||||
|
|
@ -66,6 +72,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
|
|||
snd-soc-wm2000-objs := wm2000.o
|
||||
snd-soc-wm9090-objs := wm9090.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
|
||||
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
|
||||
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
|
||||
|
|
@ -83,6 +90,7 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
|||
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
|
||||
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
|
||||
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
|
||||
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
|
||||
|
|
@ -95,6 +103,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
|
|||
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
|
||||
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
|
||||
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
|
||||
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
|
||||
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
|
||||
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
|
||||
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
|
||||
|
|
@ -108,6 +117,7 @@ obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
|
|||
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
|
||||
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
|
||||
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
|
||||
obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
|
||||
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
|
||||
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
|
||||
obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
|
||||
|
|
@ -115,9 +125,11 @@ obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
|
|||
obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o
|
||||
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
|
||||
obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
|
||||
obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o
|
||||
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
|
||||
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
|
||||
obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
|
||||
obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o
|
||||
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
|
||||
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
|
||||
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
|
||||
|
|
|
|||
|
|
@ -21,17 +21,13 @@
|
|||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include "ac97.h"
|
||||
|
||||
#define AC97_VERSION "0.6"
|
||||
|
||||
static int ac97_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
|
||||
|
|
@ -46,8 +42,8 @@ static struct snd_soc_dai_ops ac97_dai_ops = {
|
|||
.prepare = ac97_prepare,
|
||||
};
|
||||
|
||||
struct snd_soc_dai ac97_dai = {
|
||||
.name = "AC97 HiFi",
|
||||
static struct snd_soc_dai_driver ac97_dai = {
|
||||
.name = "ac97-hifi",
|
||||
.ac97_control = 1,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
|
|
@ -63,7 +59,6 @@ struct snd_soc_dai ac97_dai = {
|
|||
.formats = SND_SOC_STD_AC97_FMTS,},
|
||||
.ops = &ac97_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ac97_dai);
|
||||
|
||||
static unsigned int ac97_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
|
|
@ -78,95 +73,41 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ac97_soc_probe(struct platform_device *pdev)
|
||||
static int ac97_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_card *card = socdev->card;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_ac97_bus *ac97_bus;
|
||||
struct snd_ac97_template ac97_template;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
|
||||
|
||||
socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (!socdev->card->codec)
|
||||
return -ENOMEM;
|
||||
codec = socdev->card->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
codec->name = "AC97";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ac97_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->write = ac97_write;
|
||||
codec->read = ac97_read;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
int ret;
|
||||
|
||||
/* add codec as bus device for standard ac97 */
|
||||
ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
|
||||
ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
|
||||
if (ret < 0)
|
||||
goto bus_err;
|
||||
return ret;
|
||||
|
||||
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
|
||||
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
|
||||
if (ret < 0)
|
||||
goto bus_err;
|
||||
|
||||
for (i = 0; i < card->num_links; i++) {
|
||||
if (card->dai_link[i].codec_dai->ac97_control) {
|
||||
snd_ac97_dev_add_pdata(codec->ac97,
|
||||
card->dai_link[i].cpu_dai->ac97_pdata);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
bus_err:
|
||||
snd_soc_free_pcms(socdev);
|
||||
|
||||
err:
|
||||
kfree(socdev->card->codec);
|
||||
socdev->card->codec = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ac97_soc_remove(struct platform_device *pdev)
|
||||
static int ac97_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (!codec)
|
||||
return 0;
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
kfree(socdev->card->codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
|
||||
static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_ac97_suspend(socdev->card->codec->ac97);
|
||||
snd_ac97_suspend(codec->ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac97_soc_resume(struct platform_device *pdev)
|
||||
static int ac97_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_ac97_resume(socdev->card->codec->ac97);
|
||||
snd_ac97_resume(codec->ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -175,14 +116,50 @@ static int ac97_soc_resume(struct platform_device *pdev)
|
|||
#define ac97_soc_resume NULL
|
||||
#endif
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ac97 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
|
||||
.write = ac97_write,
|
||||
.read = ac97_read,
|
||||
.probe = ac97_soc_probe,
|
||||
.remove = ac97_soc_remove,
|
||||
.suspend = ac97_soc_suspend,
|
||||
.resume = ac97_soc_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
|
||||
|
||||
static __devinit int ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ac97, &ac97_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ac97_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ac97-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ac97_probe,
|
||||
.remove = __devexit_p(ac97_remove),
|
||||
};
|
||||
|
||||
static int __init ac97_init(void)
|
||||
{
|
||||
return platform_driver_register(&ac97_codec_driver);
|
||||
}
|
||||
module_init(ac97_init);
|
||||
|
||||
static void __exit ac97_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ac97_codec_driver);
|
||||
}
|
||||
module_exit(ac97_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Soc Generic AC97 driver");
|
||||
MODULE_AUTHOR("Liam Girdwood");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:ac97-codec");
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* linux/sound/codecs/ac97.h -- ALSA SoC Layer
|
||||
*
|
||||
* Author: Liam Girdwood
|
||||
* Created: Dec 1st 2005
|
||||
* Copyright: Wolfson Microelectronics. PLC.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SND_SOC_AC97_H
|
||||
#define __LINUX_SND_SOC_AC97_H
|
||||
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ac97;
|
||||
extern struct snd_soc_dai ac97_dai;
|
||||
|
||||
#endif
|
||||
|
|
@ -33,15 +33,10 @@
|
|||
|
||||
/* codec private data */
|
||||
struct ad1836_priv {
|
||||
struct snd_soc_codec codec;
|
||||
u16 reg_cache[AD1836_NUM_REGS];
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *ad1836_codec;
|
||||
struct snd_soc_codec_device soc_codec_dev_ad1836;
|
||||
static int ad1836_register(struct ad1836_priv *ad1836);
|
||||
static void ad1836_unregister(struct ad1836_priv *ad1836);
|
||||
|
||||
/*
|
||||
* AD1836 volume/mute/de-emphasis etc. controls
|
||||
*/
|
||||
|
|
@ -146,8 +141,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
|
|||
int word_len = 0;
|
||||
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* bit size */
|
||||
switch (params_format(params)) {
|
||||
|
|
@ -173,12 +167,9 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ad1836_soc_suspend(struct platform_device *pdev,
|
||||
static int ad1836_soc_suspend(struct snd_soc_codec *codec,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
/* reset clock control mode */
|
||||
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
|
||||
adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
|
||||
|
|
@ -186,11 +177,8 @@ static int ad1836_soc_suspend(struct platform_device *pdev,
|
|||
return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
|
||||
}
|
||||
|
||||
static int ad1836_soc_resume(struct platform_device *pdev)
|
||||
static int ad1836_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
/* restore clock control mode */
|
||||
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
|
||||
adc_ctrl2 |= AD1836_ADC_AUX;
|
||||
|
|
@ -202,49 +190,14 @@ static int ad1836_soc_resume(struct platform_device *pdev)
|
|||
#define ad1836_soc_resume NULL
|
||||
#endif
|
||||
|
||||
static int __devinit ad1836_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct ad1836_priv *ad1836;
|
||||
|
||||
ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
|
||||
if (ad1836 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &ad1836->codec;
|
||||
codec->control_data = spi;
|
||||
codec->dev = &spi->dev;
|
||||
|
||||
dev_set_drvdata(&spi->dev, ad1836);
|
||||
|
||||
return ad1836_register(ad1836);
|
||||
}
|
||||
|
||||
static int __devexit ad1836_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev);
|
||||
|
||||
ad1836_unregister(ad1836);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad1836_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad1836",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad1836_spi_probe,
|
||||
.remove = __devexit_p(ad1836_spi_remove),
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops ad1836_dai_ops = {
|
||||
.hw_params = ad1836_hw_params,
|
||||
.set_fmt = ad1836_set_dai_fmt,
|
||||
};
|
||||
|
||||
/* codec DAI instance */
|
||||
struct snd_soc_dai ad1836_dai = {
|
||||
.name = "AD1836",
|
||||
static struct snd_soc_dai_driver ad1836_dai = {
|
||||
.name = "ad1836-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -263,35 +216,13 @@ struct snd_soc_dai ad1836_dai = {
|
|||
},
|
||||
.ops = &ad1836_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad1836_dai);
|
||||
|
||||
static int ad1836_register(struct ad1836_priv *ad1836)
|
||||
static int ad1836_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = &ad1836->codec;
|
||||
|
||||
if (ad1836_codec) {
|
||||
dev_err(codec->dev, "Another ad1836 is registered\n");
|
||||
kfree(ad1836);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
snd_soc_codec_set_drvdata(codec, ad1836);
|
||||
codec->reg_cache = ad1836->reg_cache;
|
||||
codec->reg_cache_size = AD1836_NUM_REGS;
|
||||
codec->name = "AD1836";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ad1836_dai;
|
||||
codec->num_dai = 1;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ad1836_dai.dev = codec->dev;
|
||||
ad1836_codec = codec;
|
||||
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
codec->control_data = ad1836->control_data;
|
||||
ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n",
|
||||
|
|
@ -319,81 +250,69 @@ static int ad1836_register(struct ad1836_priv *ad1836)
|
|||
snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
|
||||
snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
kfree(ad1836);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&ad1836_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
kfree(ad1836);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad1836_unregister(struct ad1836_priv *ad1836)
|
||||
{
|
||||
snd_soc_unregister_dai(&ad1836_dai);
|
||||
snd_soc_unregister_codec(&ad1836->codec);
|
||||
kfree(ad1836);
|
||||
ad1836_codec = NULL;
|
||||
}
|
||||
|
||||
static int ad1836_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
if (ad1836_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = ad1836_codec;
|
||||
codec = ad1836_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, ad1836_snd_controls,
|
||||
ARRAY_SIZE(ad1836_snd_controls));
|
||||
snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
|
||||
ARRAY_SIZE(ad1836_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ad1836_remove(struct platform_device *pdev)
|
||||
static int ad1836_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
/* reset clock control mode */
|
||||
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
|
||||
adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ad1836 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
|
||||
.probe = ad1836_probe,
|
||||
.remove = ad1836_remove,
|
||||
.suspend = ad1836_soc_suspend,
|
||||
.resume = ad1836_soc_resume,
|
||||
.reg_cache_size = AD1836_NUM_REGS,
|
||||
.reg_word_size = sizeof(u16),
|
||||
};
|
||||
|
||||
static int __devinit ad1836_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad1836_priv *ad1836;
|
||||
int ret;
|
||||
|
||||
ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
|
||||
if (ad1836 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_set_drvdata(spi, ad1836);
|
||||
ad1836->control_data = spi;
|
||||
ad1836->control_type = SND_SOC_SPI;
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_ad1836, &ad1836_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ad1836);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ad1836_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
kfree(spi_get_drvdata(spi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad1836_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad1836-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad1836_spi_probe,
|
||||
.remove = __devexit_p(ad1836_spi_remove),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
|
||||
|
||||
static int __init ad1836_init(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,6 +60,4 @@
|
|||
|
||||
#define AD1836_NUM_REGS 16
|
||||
|
||||
extern struct snd_soc_dai ad1836_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ad1836;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@
|
|||
|
||||
/* codec private data */
|
||||
struct ad193x_priv {
|
||||
unsigned int sysclk;
|
||||
struct snd_soc_codec codec;
|
||||
u8 reg_cache[AD193X_NUM_REGS];
|
||||
enum snd_soc_control_type bus_type;
|
||||
void *control_data;
|
||||
int sysclk;
|
||||
};
|
||||
|
||||
/* ad193x register cache & default register settings */
|
||||
|
|
@ -34,9 +35,6 @@ static const u8 ad193x_reg[AD193X_NUM_REGS] = {
|
|||
0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *ad193x_codec;
|
||||
struct snd_soc_codec_device soc_codec_dev_ad193x;
|
||||
|
||||
/*
|
||||
* AD193X volume/mute/de-emphasis etc. controls
|
||||
*/
|
||||
|
|
@ -275,8 +273,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
|
|||
int word_len = 0, reg = 0, master_rate = 0;
|
||||
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* bit size */
|
||||
|
|
@ -323,46 +320,46 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
|
||||
static struct snd_soc_dai_ops ad193x_dai_ops = {
|
||||
.hw_params = ad193x_hw_params,
|
||||
.digital_mute = ad193x_mute,
|
||||
.set_tdm_slot = ad193x_set_tdm_slot,
|
||||
.set_sysclk = ad193x_set_dai_sysclk,
|
||||
.set_fmt = ad193x_set_dai_fmt,
|
||||
};
|
||||
|
||||
/* codec DAI instance */
|
||||
static struct snd_soc_dai_driver ad193x_dai = {
|
||||
.name = "ad193x-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &ad193x_dai_ops,
|
||||
};
|
||||
|
||||
static int ad193x_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct ad193x_priv *ad193x;
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (ad193x_codec) {
|
||||
dev_err(dev, "Another ad193x is registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, ad193x);
|
||||
|
||||
codec = &ad193x->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
codec->control_data = ctrl_data;
|
||||
codec->dev = dev;
|
||||
snd_soc_codec_set_drvdata(codec, ad193x);
|
||||
codec->reg_cache = ad193x->reg_cache;
|
||||
codec->reg_cache_size = AD193X_NUM_REGS;
|
||||
codec->name = "AD193X";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ad193x_dai;
|
||||
codec->num_dai = 1;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ad193x_dai.dev = codec->dev;
|
||||
ad193x_codec = codec;
|
||||
|
||||
memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
|
||||
|
||||
if (bus_type == SND_SOC_I2C)
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
|
||||
codec->control_data = ad193x->control_data;
|
||||
if (ad193x->bus_type == SND_SOC_I2C)
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
|
||||
else
|
||||
ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n",
|
||||
ret);
|
||||
|
|
@ -385,89 +382,6 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
|
|||
/* pll input: mclki/xi */
|
||||
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
|
||||
snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
|
||||
ad193x->sysclk = 12288000;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&ad193x_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_bus_remove(struct device *dev)
|
||||
{
|
||||
struct ad193x_priv *ad193x = dev_get_drvdata(dev);
|
||||
|
||||
snd_soc_unregister_dai(&ad193x_dai);
|
||||
snd_soc_unregister_codec(&ad193x->codec);
|
||||
kfree(ad193x);
|
||||
ad193x_codec = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops ad193x_dai_ops = {
|
||||
.hw_params = ad193x_hw_params,
|
||||
.digital_mute = ad193x_mute,
|
||||
.set_tdm_slot = ad193x_set_tdm_slot,
|
||||
.set_sysclk = ad193x_set_dai_sysclk,
|
||||
.set_fmt = ad193x_set_dai_fmt,
|
||||
};
|
||||
|
||||
/* codec DAI instance */
|
||||
struct snd_soc_dai ad193x_dai = {
|
||||
.name = "AD193X",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &ad193x_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad193x_dai);
|
||||
|
||||
static int ad193x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
if (ad193x_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = ad193x_codec;
|
||||
codec = ad193x_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, ad193x_snd_controls,
|
||||
ARRAY_SIZE(ad193x_snd_controls));
|
||||
|
|
@ -475,41 +389,47 @@ static int ad193x_probe(struct platform_device *pdev)
|
|||
ARRAY_SIZE(ad193x_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ad193x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ad193x = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
|
||||
.probe = ad193x_probe,
|
||||
.remove = ad193x_remove,
|
||||
.reg_cache_default = ad193x_reg,
|
||||
.reg_cache_size = AD193X_NUM_REGS,
|
||||
.reg_word_size = sizeof(u16),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit ad193x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
|
||||
struct ad193x_priv *ad193x;
|
||||
int ret;
|
||||
|
||||
ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_set_drvdata(spi, ad193x);
|
||||
ad193x->control_data = spi;
|
||||
ad193x->bus_type = SND_SOC_SPI;
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_ad193x, &ad193x_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ad193x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return ad193x_bus_remove(&spi->dev);
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
kfree(spi_get_drvdata(spi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad193x_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
.name = "ad193x-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad193x_spi_probe,
|
||||
|
|
@ -528,17 +448,34 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id);
|
|||
static int __devinit ad193x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
|
||||
struct ad193x_priv *ad193x;
|
||||
int ret;
|
||||
|
||||
ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, ad193x);
|
||||
ad193x->control_data = client;
|
||||
ad193x->bus_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&client->dev,
|
||||
&soc_codec_dev_ad193x, &ad193x_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ad193x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
return ad193x_bus_remove(&client->dev);
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver ad193x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
.name = "ad193x-codec",
|
||||
},
|
||||
.probe = ad193x_i2c_probe,
|
||||
.remove = __devexit_p(ad193x_i2c_remove),
|
||||
|
|
|
|||
|
|
@ -80,7 +80,4 @@
|
|||
|
||||
#define AD193X_NUM_REGS 17
|
||||
|
||||
extern struct snd_soc_dai ad193x_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ad193x;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,11 +33,6 @@
|
|||
|
||||
#include "ad1980.h"
|
||||
|
||||
static unsigned int ac97_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
static int ac97_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int val);
|
||||
|
||||
/*
|
||||
* AD1980 register cache
|
||||
*/
|
||||
|
|
@ -138,8 +133,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_dai ad1980_dai = {
|
||||
.name = "AC97",
|
||||
static struct snd_soc_dai_driver ad1980_dai = {
|
||||
.name = "ad1980-hifi",
|
||||
.ac97_control = 1,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
|
|
@ -185,53 +180,20 @@ err:
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int ad1980_soc_probe(struct platform_device *pdev)
|
||||
static int ad1980_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
u16 vendor_id2;
|
||||
u16 ext_status;
|
||||
|
||||
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
|
||||
|
||||
socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (socdev->card->codec == NULL)
|
||||
return -ENOMEM;
|
||||
codec = socdev->card->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
codec->reg_cache =
|
||||
kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cache_err;
|
||||
}
|
||||
memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
|
||||
ARRAY_SIZE(ad1980_reg));
|
||||
codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
|
||||
codec->reg_cache_step = 2;
|
||||
codec->name = "AD1980";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ad1980_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->write = ac97_write;
|
||||
codec->read = ac97_read;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
|
||||
goto codec_err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0)
|
||||
goto pcm_err;
|
||||
|
||||
|
||||
ret = ad1980_reset(codec, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
|
||||
|
|
@ -270,41 +232,60 @@ static int ad1980_soc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
reset_err:
|
||||
snd_soc_free_pcms(socdev);
|
||||
|
||||
pcm_err:
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
|
||||
codec_err:
|
||||
kfree(codec->reg_cache);
|
||||
|
||||
cache_err:
|
||||
kfree(socdev->card->codec);
|
||||
socdev->card->codec = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad1980_soc_remove(struct platform_device *pdev)
|
||||
static int ad1980_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec == NULL)
|
||||
return 0;
|
||||
|
||||
snd_soc_dapm_free(socdev);
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
kfree(codec->reg_cache);
|
||||
kfree(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ad1980 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
|
||||
.probe = ad1980_soc_probe,
|
||||
.remove = ad1980_soc_remove,
|
||||
.reg_cache_size = ARRAY_SIZE(ad1980_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = ad1980_reg,
|
||||
.reg_cache_step = 2,
|
||||
.write = ac97_write,
|
||||
.read = ac97_read,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
|
||||
|
||||
static __devinit int ad1980_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ad1980, &ad1980_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit ad1980_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ad1980_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ad1980-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ad1980_probe,
|
||||
.remove = __devexit_p(ad1980_remove),
|
||||
};
|
||||
|
||||
static int __init ad1980_init(void)
|
||||
{
|
||||
return platform_driver_register(&ad1980_codec_driver);
|
||||
}
|
||||
module_init(ad1980_init);
|
||||
|
||||
static void __exit ad1980_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ad1980_codec_driver);
|
||||
}
|
||||
module_exit(ad1980_exit);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
|
||||
MODULE_AUTHOR("Roy Huang, Cliff Cai");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,4 @@
|
|||
#define PR5 0x2000
|
||||
#define PR6 0x4000
|
||||
|
||||
extern struct snd_soc_dai ad1980_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ad1980;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
#include "ad73311.h"
|
||||
|
||||
struct snd_soc_dai ad73311_dai = {
|
||||
.name = "AD73311",
|
||||
static struct snd_soc_dai_driver ad73311_dai = {
|
||||
.name = "ad73311-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -38,68 +38,40 @@ struct snd_soc_dai ad73311_dai = {
|
|||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad73311_dai);
|
||||
|
||||
static int ad73311_soc_probe(struct platform_device *pdev)
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad73311;
|
||||
|
||||
static int ad73311_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
mutex_init(&codec->mutex);
|
||||
codec->name = "AD73311";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ad73311_dai;
|
||||
codec->num_dai = 1;
|
||||
socdev->card->codec = codec;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ad73311: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
kfree(socdev->card->codec);
|
||||
socdev->card->codec = NULL;
|
||||
return ret;
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ad73311, &ad73311_dai, 1);
|
||||
}
|
||||
|
||||
static int ad73311_soc_remove(struct platform_device *pdev)
|
||||
static int ad73311_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec == NULL)
|
||||
return 0;
|
||||
snd_soc_free_pcms(socdev);
|
||||
kfree(codec);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ad73311 = {
|
||||
.probe = ad73311_soc_probe,
|
||||
.remove = ad73311_soc_remove,
|
||||
static struct platform_driver ad73311_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ad73311-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ad73311_probe,
|
||||
.remove = __devexit_p(ad73311_remove),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
|
||||
|
||||
static int __init ad73311_init(void)
|
||||
{
|
||||
return snd_soc_register_dai(&ad73311_dai);
|
||||
return platform_driver_register(&ad73311_codec_driver);
|
||||
}
|
||||
module_init(ad73311_init);
|
||||
|
||||
static void __exit ad73311_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&ad73311_dai);
|
||||
platform_driver_unregister(&ad73311_codec_driver);
|
||||
}
|
||||
module_exit(ad73311_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,4 @@
|
|||
#define REGF_INV (1 << 6)
|
||||
#define REGF_ALB (1 << 7)
|
||||
|
||||
extern struct snd_soc_dai ad73311_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ad73311;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,16 +19,12 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ads117x.h"
|
||||
|
||||
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
|
||||
|
||||
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
struct snd_soc_dai ads117x_dai = {
|
||||
static struct snd_soc_dai_driver ads117x_dai = {
|
||||
/* ADC */
|
||||
.name = "ADS117X ADC",
|
||||
.id = 1,
|
||||
.name = "ads117x-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
|
|
@ -36,75 +32,29 @@ struct snd_soc_dai ads117x_dai = {
|
|||
.rates = ADS117X_RATES,
|
||||
.formats = ADS117X_FORMATS,},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ads117x_dai);
|
||||
|
||||
static int ads117x_probe(struct platform_device *pdev)
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ads117x;
|
||||
|
||||
static __devinit int ads117x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
codec->name = "ADS117X";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ads117x_dai;
|
||||
codec->num_dai = 1;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ads117x: failed to create pcms\n");
|
||||
kfree(codec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ads117x, &ads117x_dai, 1);
|
||||
}
|
||||
|
||||
static int ads117x_remove(struct platform_device *pdev)
|
||||
static int __devexit ads117x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ads117x = {
|
||||
.probe = ads117x_probe,
|
||||
.remove = ads117x_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
|
||||
|
||||
static __devinit int ads117x_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
ads117x_dai.dev = &pdev->dev;
|
||||
return snd_soc_register_dai(&ads117x_dai);
|
||||
}
|
||||
|
||||
static int __devexit ads117x_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&ads117x_dai);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ads117x_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ads117x",
|
||||
.name = "ads117x-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ads117x_platform_probe,
|
||||
.remove = __devexit_p(ads117x_platform_remove),
|
||||
.probe = ads117x_probe,
|
||||
.remove = __devexit_p(ads117x_remove),
|
||||
};
|
||||
|
||||
static int __init ads117x_init(void)
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@
|
|||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
extern struct snd_soc_dai ads117x_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ads117x;
|
||||
extern struct snd_soc_dai_driver ads117x_dai;
|
||||
extern struct snd_soc_codec_driver soc_codec_dev_ads117x;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <sound/asoundef.h>
|
||||
|
||||
#include "ak4104.h"
|
||||
|
||||
/* AK4104 registers addresses */
|
||||
#define AK4104_REG_CONTROL1 0x00
|
||||
#define AK4104_REG_RESERVED 0x01
|
||||
|
|
@ -45,11 +43,11 @@
|
|||
#define AK4104_TX_TXE (1 << 0)
|
||||
#define AK4104_TX_V (1 << 1)
|
||||
|
||||
#define DRV_NAME "ak4104"
|
||||
#define DRV_NAME "ak4104-codec"
|
||||
|
||||
struct ak4104_private {
|
||||
struct snd_soc_codec codec;
|
||||
u8 reg_cache[AK4104_NUM_REGS];
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
static int ak4104_fill_cache(struct snd_soc_codec *codec)
|
||||
|
|
@ -58,7 +56,7 @@ static int ak4104_fill_cache(struct snd_soc_codec *codec)
|
|||
u8 *reg_cache = codec->reg_cache;
|
||||
struct spi_device *spi = codec->control_data;
|
||||
|
||||
for (i = 0; i < codec->reg_cache_size; i++) {
|
||||
for (i = 0; i < codec->driver->reg_cache_size; i++) {
|
||||
int ret = spi_w8r8(spi, i | AK4104_READ);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "SPI write failure\n");
|
||||
|
|
@ -76,7 +74,7 @@ static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
|
|||
{
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
|
||||
if (reg >= codec->reg_cache_size)
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
return reg_cache[reg];
|
||||
|
|
@ -88,7 +86,7 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
u8 *cache = codec->reg_cache;
|
||||
struct spi_device *spi = codec->control_data;
|
||||
|
||||
if (reg >= codec->reg_cache_size)
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
/* only write to the hardware if value has changed */
|
||||
|
|
@ -145,8 +143,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int val = 0;
|
||||
|
||||
/* set the IEC958 bits: consumer mode, no copyright bit */
|
||||
|
|
@ -178,8 +175,8 @@ static struct snd_soc_dai_ops ak4101_dai_ops = {
|
|||
.set_fmt = ak4104_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai ak4104_dai = {
|
||||
.name = DRV_NAME,
|
||||
static struct snd_soc_dai_driver ak4104_dai = {
|
||||
.name = "ak4104-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -192,13 +189,71 @@ struct snd_soc_dai ak4104_dai = {
|
|||
.ops = &ak4101_dai_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *ak4104_codec;
|
||||
static int ak4104_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, val;
|
||||
|
||||
codec->control_data = ak4104->control_data;
|
||||
|
||||
/* read all regs and fill the cache */
|
||||
ret = ak4104_fill_cache(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to fill register cache\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read the 'reserved' register - according to the datasheet, it
|
||||
* should contain 0x5b. Not a good way to verify the presence of
|
||||
* the device, but there is no hardware ID register. */
|
||||
if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
|
||||
AK4104_RESERVED_VAL)
|
||||
return -ENODEV;
|
||||
|
||||
/* set power-up and non-reset bits */
|
||||
val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
|
||||
val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
|
||||
ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* enable transmitter */
|
||||
val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
|
||||
val |= AK4104_TX_TXE;
|
||||
ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_info(codec->dev, "SPI device initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
int val, ret;
|
||||
|
||||
val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
/* clear power-up and non-reset bits */
|
||||
val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
|
||||
ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
|
||||
.probe = ak4104_probe,
|
||||
.remove = ak4104_remove,
|
||||
.reg_cache_size = AK4104_NUM_REGS,
|
||||
.reg_word_size = sizeof(u16),
|
||||
};
|
||||
|
||||
static int ak4104_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct ak4104_private *ak4104;
|
||||
int ret, val;
|
||||
int ret;
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode = SPI_MODE_0;
|
||||
|
|
@ -207,125 +262,27 @@ static int ak4104_spi_probe(struct spi_device *spi)
|
|||
return ret;
|
||||
|
||||
ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
|
||||
if (!ak4104) {
|
||||
dev_err(&spi->dev, "could not allocate codec\n");
|
||||
if (ak4104 == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec = &ak4104->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->dev = &spi->dev;
|
||||
codec->name = DRV_NAME;
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ak4104_dai;
|
||||
codec->num_dai = 1;
|
||||
snd_soc_codec_set_drvdata(codec, ak4104);
|
||||
codec->control_data = spi;
|
||||
codec->reg_cache = ak4104->reg_cache;
|
||||
codec->reg_cache_size = AK4104_NUM_REGS;
|
||||
|
||||
/* read all regs and fill the cache */
|
||||
ret = ak4104_fill_cache(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "failed to fill register cache\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read the 'reserved' register - according to the datasheet, it
|
||||
* should contain 0x5b. Not a good way to verify the presence of
|
||||
* the device, but there is no hardware ID register. */
|
||||
if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
|
||||
AK4104_RESERVED_VAL) {
|
||||
ret = -ENODEV;
|
||||
goto error_free_codec;
|
||||
}
|
||||
|
||||
/* set power-up and non-reset bits */
|
||||
val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
|
||||
val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
|
||||
ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
|
||||
if (ret < 0)
|
||||
goto error_free_codec;
|
||||
|
||||
/* enable transmitter */
|
||||
val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
|
||||
val |= AK4104_TX_TXE;
|
||||
ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
|
||||
if (ret < 0)
|
||||
goto error_free_codec;
|
||||
|
||||
ak4104_codec = codec;
|
||||
ret = snd_soc_register_dai(&ak4104_dai);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "failed to register DAI\n");
|
||||
goto error_free_codec;
|
||||
}
|
||||
|
||||
ak4104->control_data = spi;
|
||||
ak4104->control_type = SND_SOC_SPI;
|
||||
spi_set_drvdata(spi, ak4104);
|
||||
dev_info(&spi->dev, "SPI device initialized\n");
|
||||
return 0;
|
||||
|
||||
error_free_codec:
|
||||
kfree(ak4104);
|
||||
ak4104_dai.dev = NULL;
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_device_ak4104, &ak4104_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ak4104);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ak4104_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
int ret, val;
|
||||
struct ak4104_private *ak4104 = spi_get_drvdata(spi);
|
||||
|
||||
val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
/* clear power-up and non-reset bits */
|
||||
val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
|
||||
ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ak4104_codec = NULL;
|
||||
kfree(ak4104);
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
kfree(spi_get_drvdata(spi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = ak4104_codec;
|
||||
int ret;
|
||||
|
||||
/* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* Register PCMs */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
snd_soc_free_pcms(socdev);
|
||||
return 0;
|
||||
};
|
||||
|
||||
struct snd_soc_codec_device soc_codec_device_ak4104 = {
|
||||
.probe = ak4104_probe,
|
||||
.remove = ak4104_remove
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
|
||||
|
||||
static struct spi_driver ak4104_spi_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef _AK4104_H
|
||||
#define _AK4104_H
|
||||
|
||||
extern struct snd_soc_dai ak4104_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_device_ak4104;
|
||||
|
||||
#endif
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
|
||||
#define AK4535_VERSION "0.3"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ak4535;
|
||||
|
||||
/* codec private data */
|
||||
struct ak4535_priv {
|
||||
unsigned int sysclk;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -313,8 +313,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
|
||||
int rate = params_rate(params), fs = 256;
|
||||
|
|
@ -378,14 +377,16 @@ static int ak4535_mute(struct snd_soc_dai *dai, int mute)
|
|||
static int ak4535_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
u16 i;
|
||||
u16 i, mute_reg;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
ak4535_mute(codec->dai, 0);
|
||||
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
|
||||
ak4535_write(codec, AK4535_DAC, mute_reg);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
ak4535_mute(codec->dai, 1);
|
||||
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
|
||||
ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
i = ak4535_read_reg_cache(codec, AK4535_PM1);
|
||||
|
|
@ -413,8 +414,8 @@ static struct snd_soc_dai_ops ak4535_dai_ops = {
|
|||
.set_sysclk = ak4535_set_dai_sysclk,
|
||||
};
|
||||
|
||||
struct snd_soc_dai ak4535_dai = {
|
||||
.name = "AK4535",
|
||||
static struct snd_soc_dai_driver ak4535_dai = {
|
||||
.name = "ak4535-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -429,54 +430,27 @@ struct snd_soc_dai ak4535_dai = {
|
|||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||
.ops = &ak4535_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ak4535_dai);
|
||||
|
||||
static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_resume(struct platform_device *pdev)
|
||||
static int ak4535_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
ak4535_sync(codec);
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the AK4535 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int ak4535_init(struct snd_soc_device *socdev)
|
||||
static int ak4535_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int ret = 0;
|
||||
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
codec->name = "AK4535";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = ak4535_read_reg_cache;
|
||||
codec->write = ak4535_write;
|
||||
codec->set_bias_level = ak4535_set_bias_level;
|
||||
codec->dai = &ak4535_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
|
||||
codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
|
||||
printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
|
||||
|
||||
if (codec->reg_cache == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ak4535: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
codec->control_data = ak4535->control_data;
|
||||
|
||||
/* power on device */
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
|
@ -485,39 +459,55 @@ static int ak4535_init(struct snd_soc_device *socdev)
|
|||
ARRAY_SIZE(ak4535_snd_controls));
|
||||
ak4535_add_widgets(codec);
|
||||
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
kfree(codec->reg_cache);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_device *ak4535_socdev;
|
||||
/* power down chip */
|
||||
static int ak4535_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
|
||||
.probe = ak4535_probe,
|
||||
.remove = ak4535_remove,
|
||||
.suspend = ak4535_suspend,
|
||||
.resume = ak4535_resume,
|
||||
.read = ak4535_read_reg_cache,
|
||||
.write = ak4535_write,
|
||||
.set_bias_level = ak4535_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(ak4535_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = ak4535_reg,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
static int ak4535_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct snd_soc_device *socdev = ak4535_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct ak4535_priv *ak4535;
|
||||
int ret;
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
codec->control_data = i2c;
|
||||
ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
|
||||
if (ak4535 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ak4535_init(socdev);
|
||||
i2c_set_clientdata(i2c, ak4535);
|
||||
ak4535->control_data = i2c;
|
||||
ak4535->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_ak4535, &ak4535_dai, 1);
|
||||
if (ret < 0)
|
||||
printk(KERN_ERR "failed to initialise AK4535\n");
|
||||
|
||||
kfree(ak4535);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4535_i2c_remove(struct i2c_client *client)
|
||||
static __devexit int ak4535_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct snd_soc_codec *codec = i2c_get_clientdata(client);
|
||||
kfree(codec->reg_cache);
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -529,138 +519,34 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
|
|||
|
||||
static struct i2c_driver ak4535_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "AK4535 I2C Codec",
|
||||
.name = "ak4535-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ak4535_i2c_probe,
|
||||
.remove = ak4535_i2c_remove,
|
||||
.remove = __devexit_p(ak4535_i2c_remove),
|
||||
.id_table = ak4535_i2c_id,
|
||||
};
|
||||
|
||||
static int ak4535_add_i2c_device(struct platform_device *pdev,
|
||||
const struct ak4535_setup_data *setup)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&ak4535_i2c_driver);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "can't add i2c driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = setup->i2c_address;
|
||||
strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
|
||||
|
||||
adapter = i2c_get_adapter(setup->i2c_bus);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "can't get i2c adapter %d\n",
|
||||
setup->i2c_bus);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
client = i2c_new_device(adapter, &info);
|
||||
i2c_put_adapter(adapter);
|
||||
if (!client) {
|
||||
dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
|
||||
(unsigned int)info.addr);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_driver:
|
||||
i2c_del_driver(&ak4535_i2c_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ak4535_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct ak4535_setup_data *setup;
|
||||
struct snd_soc_codec *codec;
|
||||
struct ak4535_priv *ak4535;
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
|
||||
|
||||
setup = socdev->codec_data;
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
|
||||
if (ak4535 == NULL) {
|
||||
kfree(codec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, ak4535);
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ak4535_socdev = socdev;
|
||||
ret = -ENODEV;
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
if (setup->i2c_address) {
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
ret = ak4535_add_i2c_device(pdev, setup);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ak4535_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec->control_data)
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
if (codec->control_data)
|
||||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&ak4535_i2c_driver);
|
||||
#endif
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ak4535 = {
|
||||
.probe = ak4535_probe,
|
||||
.remove = ak4535_remove,
|
||||
.suspend = ak4535_suspend,
|
||||
.resume = ak4535_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
|
||||
|
||||
static int __init ak4535_modinit(void)
|
||||
{
|
||||
return snd_soc_register_dai(&ak4535_dai);
|
||||
int ret = 0;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&ak4535_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(ak4535_modinit);
|
||||
|
||||
static void __exit ak4535_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&ak4535_dai);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&ak4535_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(ak4535_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,12 +36,4 @@
|
|||
|
||||
#define AK4535_CACHEREGNUM 0x10
|
||||
|
||||
struct ak4535_setup_data {
|
||||
int i2c_bus;
|
||||
unsigned short i2c_address;
|
||||
};
|
||||
|
||||
extern struct snd_soc_dai ak4535_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ak4535;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "ak4642.h"
|
||||
|
||||
#define AK4642_VERSION "0.0.1"
|
||||
|
||||
#define PW_MGMT1 0x00
|
||||
|
|
@ -74,6 +72,12 @@
|
|||
|
||||
#define AK4642_CACHEREGNUM 0x25
|
||||
|
||||
/* PW_MGMT1*/
|
||||
#define PMVCM (1 << 6) /* VCOM Power Management */
|
||||
#define PMMIN (1 << 5) /* MIN Input Power Management */
|
||||
#define PMDAC (1 << 2) /* DAC Power Management */
|
||||
#define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
|
||||
|
||||
/* PW_MGMT2 */
|
||||
#define HPMTN (1 << 6)
|
||||
#define PMHPL (1 << 5)
|
||||
|
|
@ -85,6 +89,23 @@
|
|||
#define PMHP_MASK (PMHPL | PMHPR)
|
||||
#define PMHP PMHP_MASK
|
||||
|
||||
/* PW_MGMT3 */
|
||||
#define PMADR (1 << 0) /* MIC L / ADC R Power Management */
|
||||
|
||||
/* SG_SL1 */
|
||||
#define MINS (1 << 6) /* Switch from MIN to Speaker */
|
||||
#define DACL (1 << 4) /* Switch from DAC to Stereo or Receiver */
|
||||
#define PMMP (1 << 2) /* MPWR pin Power Management */
|
||||
#define MGAIN0 (1 << 0) /* MIC amp gain*/
|
||||
|
||||
/* TIMER */
|
||||
#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
|
||||
#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
|
||||
|
||||
/* ALC_CTL1 */
|
||||
#define ALC (1 << 5) /* ALC Enable */
|
||||
#define LMTH0 (1 << 0) /* ALC Limiter / Recovery Level */
|
||||
|
||||
/* MD_CTL1 */
|
||||
#define PLL3 (1 << 7)
|
||||
#define PLL2 (1 << 6)
|
||||
|
|
@ -102,7 +123,11 @@
|
|||
#define FS3 (1 << 5)
|
||||
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ak4642;
|
||||
/* MD_CTL3 */
|
||||
#define BST1 (1 << 3)
|
||||
|
||||
/* MD_CTL4 */
|
||||
#define DACH (1 << 0)
|
||||
|
||||
/*
|
||||
* Playback Volume (table 39)
|
||||
|
|
@ -123,11 +148,11 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
|
|||
|
||||
/* codec private data */
|
||||
struct ak4642_priv {
|
||||
struct snd_soc_codec codec;
|
||||
unsigned int sysclk;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *ak4642_codec;
|
||||
|
||||
/*
|
||||
* ak4642 register cache
|
||||
*/
|
||||
|
|
@ -219,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
|
|||
* This operation came from example code of
|
||||
* "ASAHI KASEI AK4642" (japanese) manual p97.
|
||||
*/
|
||||
ak4642_write(codec, 0x0f, 0x09);
|
||||
ak4642_write(codec, 0x0e, 0x19);
|
||||
ak4642_write(codec, 0x09, 0x91);
|
||||
ak4642_write(codec, 0x0c, 0x91);
|
||||
ak4642_write(codec, 0x00, 0x64);
|
||||
snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
|
||||
snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
|
||||
ak4642_write(codec, L_IVC, 0x91); /* volume */
|
||||
ak4642_write(codec, R_IVC, 0x91); /* volume */
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
|
||||
PMVCM | PMMIN | PMDAC);
|
||||
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
|
||||
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
|
||||
} else {
|
||||
|
|
@ -240,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
|
|||
* This operation came from example code of
|
||||
* "ASAHI KASEI AK4642" (japanese) manual p94.
|
||||
*/
|
||||
ak4642_write(codec, 0x02, 0x05);
|
||||
ak4642_write(codec, 0x06, 0x3c);
|
||||
ak4642_write(codec, 0x08, 0xe1);
|
||||
ak4642_write(codec, 0x0b, 0x00);
|
||||
ak4642_write(codec, 0x07, 0x21);
|
||||
ak4642_write(codec, 0x00, 0x41);
|
||||
ak4642_write(codec, 0x10, 0x01);
|
||||
ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
|
||||
ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
|
||||
ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
|
||||
PMVCM | PMADL);
|
||||
snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -262,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
|
|||
/* stop headphone output */
|
||||
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
|
||||
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
|
||||
ak4642_write(codec, 0x00, 0x40);
|
||||
ak4642_write(codec, 0x0e, 0x11);
|
||||
ak4642_write(codec, 0x0f, 0x08);
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
|
||||
snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
|
||||
snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
|
||||
} else {
|
||||
/* stop stereo input */
|
||||
ak4642_write(codec, 0x00, 0x40);
|
||||
ak4642_write(codec, 0x10, 0x00);
|
||||
ak4642_write(codec, 0x07, 0x01);
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
|
||||
snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
|
||||
snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -393,8 +418,8 @@ static struct snd_soc_dai_ops ak4642_dai_ops = {
|
|||
.hw_params = ak4642_dai_hw_params,
|
||||
};
|
||||
|
||||
struct snd_soc_dai ak4642_dai = {
|
||||
.name = "AK4642",
|
||||
static struct snd_soc_dai_driver ak4642_dai = {
|
||||
.name = "ak4642-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -410,112 +435,65 @@ struct snd_soc_dai ak4642_dai = {
|
|||
.ops = &ak4642_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ak4642_dai);
|
||||
|
||||
static int ak4642_resume(struct platform_device *pdev)
|
||||
static int ak4642_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
ak4642_sync(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the AK4642 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int ak4642_init(struct ak4642_priv *ak4642)
|
||||
|
||||
static int ak4642_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = &ak4642->codec;
|
||||
int ret = 0;
|
||||
struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (ak4642_codec) {
|
||||
dev_err(codec->dev, "Another ak4642 is registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, ak4642);
|
||||
codec->name = "AK4642";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = ak4642_read_reg_cache;
|
||||
codec->write = ak4642_write;
|
||||
codec->dai = &ak4642_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
codec->reg_cache_size = ARRAY_SIZE(ak4642_reg);
|
||||
codec->reg_cache = kmemdup(ak4642_reg,
|
||||
sizeof(ak4642_reg), GFP_KERNEL);
|
||||
codec->control_data = ak4642->control_data;
|
||||
|
||||
if (!codec->reg_cache)
|
||||
return -ENOMEM;
|
||||
snd_soc_add_controls(codec, ak4642_snd_controls,
|
||||
ARRAY_SIZE(ak4642_snd_controls));
|
||||
|
||||
ak4642_dai.dev = codec->dev;
|
||||
ak4642_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto reg_cache_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&ak4642_dai);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
goto reg_cache_err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
reg_cache_err:
|
||||
kfree(codec->reg_cache);
|
||||
codec->reg_cache = NULL;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
|
||||
.probe = ak4642_probe,
|
||||
.resume = ak4642_resume,
|
||||
.read = ak4642_read_reg_cache,
|
||||
.write = ak4642_write,
|
||||
.reg_cache_size = ARRAY_SIZE(ak4642_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = ak4642_reg,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static int ak4642_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ak4642_priv *ak4642;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
|
||||
if (!ak4642)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &ak4642->codec;
|
||||
codec->dev = &i2c->dev;
|
||||
|
||||
i2c_set_clientdata(i2c, ak4642);
|
||||
codec->control_data = i2c;
|
||||
ak4642->control_data = i2c;
|
||||
ak4642->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = ak4642_init(ak4642);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "failed to initialise AK4642\n");
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_ak4642, &ak4642_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ak4642);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4642_i2c_remove(struct i2c_client *client)
|
||||
static __devexit int ak4642_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_dai(&ak4642_dai);
|
||||
snd_soc_unregister_codec(&ak4642->codec);
|
||||
kfree(ak4642->codec.reg_cache);
|
||||
kfree(ak4642);
|
||||
ak4642_codec = NULL;
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -528,64 +506,15 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
|
|||
|
||||
static struct i2c_driver ak4642_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "AK4642 I2C Codec",
|
||||
.name = "ak4642-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ak4642_i2c_probe,
|
||||
.remove = ak4642_i2c_remove,
|
||||
.remove = __devexit_p(ak4642_i2c_remove),
|
||||
.id_table = ak4642_i2c_id,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static int ak4642_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (!ak4642_codec) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = ak4642_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ak4642: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
|
||||
ARRAY_SIZE(ak4642_snd_controls));
|
||||
|
||||
dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ak4642_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ak4642 = {
|
||||
.probe = ak4642_probe,
|
||||
.remove = ak4642_remove,
|
||||
.resume = ak4642_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
|
||||
|
||||
static int __init ak4642_modinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* ak4642.h -- AK4642 Soc Audio driver
|
||||
*
|
||||
* Copyright (C) 2009 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
*
|
||||
* Based on ak4535.c
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AK4642_H
|
||||
#define _AK4642_H
|
||||
|
||||
extern struct snd_soc_dai ak4642_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ak4642;
|
||||
|
||||
#endif
|
||||
|
|
@ -23,11 +23,11 @@
|
|||
|
||||
#include "ak4671.h"
|
||||
|
||||
static struct snd_soc_codec *ak4671_codec;
|
||||
|
||||
/* codec private data */
|
||||
struct ak4671_priv {
|
||||
struct snd_soc_codec codec;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
u8 reg_cache[AK4671_CACHEREGNUM];
|
||||
};
|
||||
|
||||
|
|
@ -619,8 +619,8 @@ static struct snd_soc_dai_ops ak4671_dai_ops = {
|
|||
.set_fmt = ak4671_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai ak4671_dai = {
|
||||
.name = "AK4671",
|
||||
static struct snd_soc_dai_driver ak4671_dai = {
|
||||
.name = "ak4671-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -635,27 +635,18 @@ struct snd_soc_dai ak4671_dai = {
|
|||
.formats = AK4671_FORMATS,},
|
||||
.ops = &ak4671_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ak4671_dai);
|
||||
|
||||
static int ak4671_probe(struct platform_device *pdev)
|
||||
static int ak4671_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (ak4671_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
|
||||
socdev->card->codec = ak4671_codec;
|
||||
codec = ak4671_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, ak4671_snd_controls,
|
||||
|
|
@ -665,121 +656,48 @@ static int ak4671_probe(struct platform_device *pdev)
|
|||
ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4671_remove(struct platform_device *pdev)
|
||||
static int ak4671_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ak4671 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
|
||||
.probe = ak4671_probe,
|
||||
.remove = ak4671_remove,
|
||||
.set_bias_level = ak4671_set_bias_level,
|
||||
.reg_cache_size = AK4671_CACHEREGNUM,
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = ak4671_reg,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
|
||||
|
||||
static int ak4671_register(struct ak4671_priv *ak4671,
|
||||
enum snd_soc_control_type control)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = &ak4671->codec;
|
||||
|
||||
if (ak4671_codec) {
|
||||
dev_err(codec->dev, "Another AK4671 is registered\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, ak4671);
|
||||
codec->name = "AK4671";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = ak4671_set_bias_level;
|
||||
codec->dai = &ak4671_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = AK4671_CACHEREGNUM;
|
||||
codec->reg_cache = &ak4671->reg_cache;
|
||||
|
||||
memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ak4671_dai.dev = codec->dev;
|
||||
ak4671_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&ak4671_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
goto err_codec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err:
|
||||
kfree(ak4671);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ak4671_unregister(struct ak4671_priv *ak4671)
|
||||
{
|
||||
ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_unregister_dai(&ak4671_dai);
|
||||
snd_soc_unregister_codec(&ak4671->codec);
|
||||
kfree(ak4671);
|
||||
ak4671_codec = NULL;
|
||||
}
|
||||
|
||||
static int __devinit ak4671_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ak4671_priv *ak4671;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
|
||||
if (ak4671 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &ak4671->codec;
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
|
||||
i2c_set_clientdata(client, ak4671);
|
||||
codec->control_data = client;
|
||||
ak4671->control_data = client;
|
||||
ak4671->control_type = SND_SOC_I2C;
|
||||
|
||||
codec->dev = &client->dev;
|
||||
|
||||
return ak4671_register(ak4671, SND_SOC_I2C);
|
||||
ret = snd_soc_register_codec(&client->dev,
|
||||
&soc_codec_dev_ak4671, &ak4671_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ak4671);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int ak4671_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
|
||||
|
||||
ak4671_unregister(ak4671);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -791,7 +709,7 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
|
|||
|
||||
static struct i2c_driver ak4671_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak4671",
|
||||
.name = "ak4671-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ak4671_i2c_probe,
|
||||
|
|
|
|||
|
|
@ -150,7 +150,4 @@
|
|||
/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
|
||||
#define AK4671_MUTEN 0x04
|
||||
|
||||
extern struct snd_soc_dai ak4671_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ak4671;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/davinci_voicecodec.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
|
@ -41,8 +42,6 @@
|
|||
|
||||
#include <mach/dm365.h>
|
||||
|
||||
#include "cq93vc.h"
|
||||
|
||||
static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
|
|
@ -130,8 +129,8 @@ static struct snd_soc_dai_ops cq93vc_dai_ops = {
|
|||
.set_sysclk = cq93vc_set_dai_sysclk,
|
||||
};
|
||||
|
||||
struct snd_soc_dai cq93vc_dai = {
|
||||
.name = "CQ93VC",
|
||||
static struct snd_soc_dai_driver cq93vc_dai = {
|
||||
.name = "cq93vc-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -146,36 +145,20 @@ struct snd_soc_dai cq93vc_dai = {
|
|||
.formats = CQ93VC_FORMATS,},
|
||||
.ops = &cq93vc_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cq93vc_dai);
|
||||
|
||||
static int cq93vc_resume(struct platform_device *pdev)
|
||||
static int cq93vc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec *cq93vc_codec;
|
||||
|
||||
static int cq93vc_probe(struct platform_device *pdev)
|
||||
static int cq93vc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
socdev->card->codec = cq93vc_codec;
|
||||
codec = socdev->card->codec;
|
||||
|
||||
/* Register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: failed to create pcms\n", pdev->name);
|
||||
return ret;
|
||||
}
|
||||
davinci_vc->cq93vc.codec = codec;
|
||||
codec->control_data = davinci_vc;
|
||||
|
||||
/* Set controls */
|
||||
snd_soc_add_controls(codec, cq93vc_snd_controls,
|
||||
|
|
@ -187,108 +170,51 @@ static int cq93vc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cq93vc_remove(struct platform_device *pdev)
|
||||
static int cq93vc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_cq93vc = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
|
||||
.read = cq93vc_read,
|
||||
.write = cq93vc_write,
|
||||
.set_bias_level = cq93vc_set_bias_level,
|
||||
.probe = cq93vc_probe,
|
||||
.remove = cq93vc_remove,
|
||||
.resume = cq93vc_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
|
||||
|
||||
static __init int cq93vc_codec_probe(struct platform_device *pdev)
|
||||
static int cq93vc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL) {
|
||||
dev_dbg(davinci_vc->dev,
|
||||
"could not allocate memory for codec data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
davinci_vc->cq93vc.codec = codec;
|
||||
|
||||
cq93vc_dai.dev = &pdev->dev;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
codec->dev = &pdev->dev;
|
||||
codec->name = "CQ93VC";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = cq93vc_read;
|
||||
codec->write = cq93vc_write;
|
||||
codec->set_bias_level = cq93vc_set_bias_level;
|
||||
codec->dai = &cq93vc_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->control_data = davinci_vc;
|
||||
|
||||
cq93vc_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret) {
|
||||
dev_err(davinci_vc->dev, "failed to register codec\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&cq93vc_dai);
|
||||
if (ret) {
|
||||
dev_err(davinci_vc->dev, "could register dai\n");
|
||||
goto fail2;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
snd_soc_unregister_codec(codec);
|
||||
|
||||
fail1:
|
||||
kfree(codec);
|
||||
cq93vc_codec = NULL;
|
||||
|
||||
return ret;
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_cq93vc, &cq93vc_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
|
||||
static int cq93vc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
snd_soc_unregister_dai(&cq93vc_dai);
|
||||
snd_soc_unregister_codec(&codec);
|
||||
|
||||
kfree(codec);
|
||||
cq93vc_codec = NULL;
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cq93vc_codec_driver = {
|
||||
.driver = {
|
||||
.name = "cq93vc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = cq93vc_codec_probe,
|
||||
.remove = __devexit_p(cq93vc_codec_remove),
|
||||
.name = "cq93vc-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = cq93vc_platform_probe,
|
||||
.remove = __devexit_p(cq93vc_platform_remove),
|
||||
};
|
||||
|
||||
static __init int cq93vc_init(void)
|
||||
static int __init cq93vc_init(void)
|
||||
{
|
||||
return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
|
||||
return platform_driver_register(&cq93vc_codec_driver);
|
||||
}
|
||||
module_init(cq93vc_init);
|
||||
|
||||
static __exit void cq93vc_exit(void)
|
||||
static void __exit cq93vc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cq93vc_codec_driver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc
|
||||
*
|
||||
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _CQ93VC_H
|
||||
#define _CQ93VC_H
|
||||
|
||||
extern struct snd_soc_dai cq93vc_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
|
||||
|
||||
#endif
|
||||
|
|
@ -31,8 +31,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "cs4270.h"
|
||||
|
||||
/*
|
||||
* The codec isn't really big-endian or little-endian, since the I2S
|
||||
* interface requires data to be sent serially with the MSbit first.
|
||||
|
|
@ -114,7 +112,8 @@ static const char *supply_names[] = {
|
|||
|
||||
/* Private data for the CS4270 */
|
||||
struct cs4270_private {
|
||||
struct snd_soc_codec codec;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
u8 reg_cache[CS4270_NUMREGS];
|
||||
unsigned int mclk; /* Input frequency of the MCLK pin */
|
||||
unsigned int mode; /* The mode (I2S or left-justified) */
|
||||
|
|
@ -212,44 +211,8 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int rates = 0;
|
||||
unsigned int rate_min = -1;
|
||||
unsigned int rate_max = 0;
|
||||
unsigned int i;
|
||||
|
||||
cs4270->mclk = freq;
|
||||
|
||||
if (cs4270->mclk) {
|
||||
for (i = 0; i < NUM_MCLK_RATIOS; i++) {
|
||||
unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
|
||||
rates |= snd_pcm_rate_to_rate_bit(rate);
|
||||
if (rate < rate_min)
|
||||
rate_min = rate;
|
||||
if (rate > rate_max)
|
||||
rate_max = rate;
|
||||
}
|
||||
/* FIXME: soc should support a rate list */
|
||||
rates &= ~SNDRV_PCM_RATE_KNOT;
|
||||
|
||||
if (!rates) {
|
||||
dev_err(codec->dev, "could not find a valid sample rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/* enable all possible rates */
|
||||
rates = SNDRV_PCM_RATE_8000_192000;
|
||||
rate_min = 8000;
|
||||
rate_max = 192000;
|
||||
}
|
||||
|
||||
codec_dai->playback.rates = rates;
|
||||
codec_dai->playback.rate_min = rate_min;
|
||||
codec_dai->playback.rate_max = rate_max;
|
||||
|
||||
codec_dai->capture.rates = rates;
|
||||
codec_dai->capture.rate_min = rate_min;
|
||||
codec_dai->capture.rate_max = rate_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -410,8 +373,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
unsigned int i;
|
||||
|
|
@ -549,19 +511,6 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
|
|||
snd_soc_get_volsw, cs4270_soc_put_mute),
|
||||
};
|
||||
|
||||
/*
|
||||
* cs4270_codec - global variable to store codec for the ASoC probe function
|
||||
*
|
||||
* If struct i2c_driver had a private_data field, we wouldn't need to use
|
||||
* cs4270_codec. This is the only way to pass the codec structure from
|
||||
* cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good
|
||||
* way to synchronize these two functions. cs4270_i2c_probe() can be called
|
||||
* multiple times before cs4270_probe() is called even once. So for now, we
|
||||
* also only allow cs4270_i2c_probe() to be run once. That means that we do
|
||||
* not support more than one cs4270 device in the system, at least for now.
|
||||
*/
|
||||
static struct snd_soc_codec *cs4270_codec;
|
||||
|
||||
static struct snd_soc_dai_ops cs4270_dai_ops = {
|
||||
.hw_params = cs4270_hw_params,
|
||||
.set_sysclk = cs4270_set_dai_sysclk,
|
||||
|
|
@ -569,25 +518,28 @@ static struct snd_soc_dai_ops cs4270_dai_ops = {
|
|||
.digital_mute = cs4270_dai_mute,
|
||||
};
|
||||
|
||||
struct snd_soc_dai cs4270_dai = {
|
||||
.name = "cs4270",
|
||||
static struct snd_soc_dai_driver cs4270_dai = {
|
||||
.name = "cs4270-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = 0,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 4000,
|
||||
.rate_max = 216000,
|
||||
.formats = CS4270_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = 0,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 4000,
|
||||
.rate_max = 216000,
|
||||
.formats = CS4270_FORMATS,
|
||||
},
|
||||
.ops = &cs4270_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs4270_dai);
|
||||
|
||||
/**
|
||||
* cs4270_probe - ASoC probe function
|
||||
|
|
@ -596,153 +548,19 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
|
|||
* This function is called when ASoC has all the pieces it needs to
|
||||
* instantiate a sound driver.
|
||||
*/
|
||||
static int cs4270_probe(struct platform_device *pdev)
|
||||
static int cs4270_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = cs4270_codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
int i, ret, reg;
|
||||
|
||||
/* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* Register PCMs */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add the non-DAPM controls */
|
||||
ret = snd_soc_add_controls(codec, cs4270_snd_controls,
|
||||
ARRAY_SIZE(cs4270_snd_controls));
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to add controls\n");
|
||||
goto error_free_pcms;
|
||||
}
|
||||
|
||||
/* get the power supply regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
|
||||
cs4270->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
if (ret < 0)
|
||||
goto error_free_pcms;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
if (ret < 0)
|
||||
goto error_free_regulators;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_regulators:
|
||||
regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
|
||||
error_free_pcms:
|
||||
snd_soc_free_pcms(socdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_remove - ASoC remove function
|
||||
* @pdev: platform device
|
||||
*
|
||||
* This function is the counterpart to cs4270_probe().
|
||||
*/
|
||||
static int cs4270_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = cs4270_codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
|
||||
regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* cs4270_i2c_probe - initialize the I2C interface of the CS4270
|
||||
* @i2c_client: the I2C client object
|
||||
* @id: the I2C device ID (ignored)
|
||||
*
|
||||
* This function is called whenever the I2C subsystem finds a device that
|
||||
* matches the device ID given via a prior call to i2c_add_driver().
|
||||
*/
|
||||
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct cs4270_private *cs4270;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
/* For now, we only support one cs4270 device in the system. See the
|
||||
* comment for cs4270_codec.
|
||||
*/
|
||||
if (cs4270_codec) {
|
||||
dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
|
||||
i2c_client->addr);
|
||||
dev_err(&i2c_client->dev, "only one per board allowed\n");
|
||||
/* Should we return something other than ENODEV here? */
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Verify that we have a CS4270 */
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
|
||||
i2c_client->addr);
|
||||
return ret;
|
||||
}
|
||||
/* The top four bits of the chip ID should be 1100. */
|
||||
if ((ret & 0xF0) != 0xC0) {
|
||||
dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
|
||||
i2c_client->addr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&i2c_client->dev, "found device at i2c address %X\n",
|
||||
i2c_client->addr);
|
||||
dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
|
||||
|
||||
/* Allocate enough space for the snd_soc_codec structure
|
||||
and our private data together. */
|
||||
cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
|
||||
if (!cs4270) {
|
||||
dev_err(&i2c_client->dev, "could not allocate codec\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
codec = &cs4270->codec;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->dev = &i2c_client->dev;
|
||||
codec->name = "CS4270";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &cs4270_dai;
|
||||
codec->num_dai = 1;
|
||||
snd_soc_codec_set_drvdata(codec, cs4270);
|
||||
codec->control_data = i2c_client;
|
||||
codec->read = cs4270_read_reg_cache;
|
||||
codec->write = cs4270_i2c_write;
|
||||
codec->reg_cache = cs4270->reg_cache;
|
||||
codec->reg_cache_size = CS4270_NUMREGS;
|
||||
codec->control_data = cs4270->control_data;
|
||||
|
||||
/* The I2C interface is set up, so pre-fill our register cache */
|
||||
|
||||
ret = cs4270_fill_cache(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to fill register cache\n");
|
||||
goto error_free_codec;
|
||||
dev_err(codec->dev, "failed to fill register cache\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable auto-mute. This feature appears to be buggy. In some
|
||||
|
|
@ -755,7 +573,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
|
|||
reg &= ~CS4270_MUTE_AUTO;
|
||||
ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "i2c write failed\n");
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -769,65 +587,56 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
|
|||
reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
|
||||
ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "i2c write failed\n");
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
|
||||
* structure for each CS4270 device, but the machine driver needs to
|
||||
* have a pointer to the DAI structure, so for now it must be a global
|
||||
* variable.
|
||||
*/
|
||||
cs4270_dai.dev = &i2c_client->dev;
|
||||
|
||||
/* Register the DAI. If all the other ASoC driver have already
|
||||
* registered, then this will call our probe function, so
|
||||
* cs4270_codec needs to be ready.
|
||||
*/
|
||||
cs4270_codec = codec;
|
||||
ret = snd_soc_register_dai(&cs4270_dai);
|
||||
/* Add the non-DAPM controls */
|
||||
ret = snd_soc_add_controls(codec, cs4270_snd_controls,
|
||||
ARRAY_SIZE(cs4270_snd_controls));
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to register DAIe\n");
|
||||
goto error_free_codec;
|
||||
dev_err(codec->dev, "failed to add controls\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs4270);
|
||||
/* get the power supply regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
|
||||
cs4270->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
if (ret < 0)
|
||||
goto error_free_regulators;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_codec:
|
||||
kfree(cs4270);
|
||||
cs4270_codec = NULL;
|
||||
cs4270_dai.dev = NULL;
|
||||
error_free_regulators:
|
||||
regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_i2c_remove - remove an I2C device
|
||||
* @i2c_client: the I2C client object
|
||||
* cs4270_remove - ASoC remove function
|
||||
* @pdev: platform device
|
||||
*
|
||||
* This function is the counterpart to cs4270_i2c_probe().
|
||||
* This function is the counterpart to cs4270_probe().
|
||||
*/
|
||||
static int cs4270_i2c_remove(struct i2c_client *i2c_client)
|
||||
static int cs4270_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
kfree(cs4270);
|
||||
cs4270_codec = NULL;
|
||||
cs4270_dai.dev = NULL;
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
|
||||
regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cs4270_id - I2C device IDs supported by this driver
|
||||
*/
|
||||
static struct i2c_device_id cs4270_id[] = {
|
||||
{"cs4270", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4270_id);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
|
|
@ -840,9 +649,8 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
|
|||
* and all registers are written back to the hardware when resuming.
|
||||
*/
|
||||
|
||||
static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
|
||||
{
|
||||
struct snd_soc_codec *codec = cs4270_codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg, ret;
|
||||
|
||||
|
|
@ -860,9 +668,8 @@ static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cs4270_soc_resume(struct platform_device *pdev)
|
||||
static int cs4270_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = cs4270_codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c_client = codec->control_data;
|
||||
int reg;
|
||||
|
|
@ -895,6 +702,95 @@ static int cs4270_soc_resume(struct platform_device *pdev)
|
|||
#define cs4270_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* ASoC codec device structure
|
||||
*
|
||||
* Assign this variable to the codec_dev field of the machine driver's
|
||||
* snd_soc_device structure.
|
||||
*/
|
||||
static struct snd_soc_codec_driver soc_codec_device_cs4270 = {
|
||||
.probe = cs4270_probe,
|
||||
.remove = cs4270_remove,
|
||||
.suspend = cs4270_soc_suspend,
|
||||
.resume = cs4270_soc_resume,
|
||||
.read = cs4270_read_reg_cache,
|
||||
.write = cs4270_i2c_write,
|
||||
.reg_cache_size = CS4270_NUMREGS,
|
||||
.reg_word_size = sizeof(u8),
|
||||
};
|
||||
|
||||
/**
|
||||
* cs4270_i2c_probe - initialize the I2C interface of the CS4270
|
||||
* @i2c_client: the I2C client object
|
||||
* @id: the I2C device ID (ignored)
|
||||
*
|
||||
* This function is called whenever the I2C subsystem finds a device that
|
||||
* matches the device ID given via a prior call to i2c_add_driver().
|
||||
*/
|
||||
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cs4270_private *cs4270;
|
||||
int ret;
|
||||
|
||||
/* Verify that we have a CS4270 */
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
|
||||
i2c_client->addr);
|
||||
return ret;
|
||||
}
|
||||
/* The top four bits of the chip ID should be 1100. */
|
||||
if ((ret & 0xF0) != 0xC0) {
|
||||
dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
|
||||
i2c_client->addr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&i2c_client->dev, "found device at i2c address %X\n",
|
||||
i2c_client->addr);
|
||||
dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
|
||||
|
||||
cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
|
||||
if (!cs4270) {
|
||||
dev_err(&i2c_client->dev, "could not allocate codec\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs4270);
|
||||
cs4270->control_data = i2c_client;
|
||||
cs4270->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c_client->dev,
|
||||
&soc_codec_device_cs4270, &cs4270_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(cs4270);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_i2c_remove - remove an I2C device
|
||||
* @i2c_client: the I2C client object
|
||||
*
|
||||
* This function is the counterpart to cs4270_i2c_probe().
|
||||
*/
|
||||
static int cs4270_i2c_remove(struct i2c_client *i2c_client)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c_client->dev);
|
||||
kfree(i2c_get_clientdata(i2c_client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cs4270_id - I2C device IDs supported by this driver
|
||||
*/
|
||||
static struct i2c_device_id cs4270_id[] = {
|
||||
{"cs4270", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4270_id);
|
||||
|
||||
/*
|
||||
* cs4270_i2c_driver - I2C device identification
|
||||
*
|
||||
|
|
@ -903,7 +799,7 @@ static int cs4270_soc_resume(struct platform_device *pdev)
|
|||
*/
|
||||
static struct i2c_driver cs4270_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs4270",
|
||||
.name = "cs4270-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.id_table = cs4270_id,
|
||||
|
|
@ -911,20 +807,6 @@ static struct i2c_driver cs4270_i2c_driver = {
|
|||
.remove = cs4270_i2c_remove,
|
||||
};
|
||||
|
||||
/*
|
||||
* ASoC codec device structure
|
||||
*
|
||||
* Assign this variable to the codec_dev field of the machine driver's
|
||||
* snd_soc_device structure.
|
||||
*/
|
||||
struct snd_soc_codec_device soc_codec_device_cs4270 = {
|
||||
.probe = cs4270_probe,
|
||||
.remove = cs4270_remove,
|
||||
.suspend = cs4270_soc_suspend,
|
||||
.resume = cs4270_soc_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
|
||||
|
||||
static int __init cs4270_init(void)
|
||||
{
|
||||
pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Cirrus Logic CS4270 ALSA SoC Codec Driver
|
||||
*
|
||||
* Author: Timur Tabi <timur@freescale.com>
|
||||
*
|
||||
* Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under
|
||||
* the terms of the GNU General Public License version 2. This program
|
||||
* is licensed "as is" without any warranty of any kind, whether express
|
||||
* or implied.
|
||||
*/
|
||||
|
||||
#ifndef _CS4270_H
|
||||
#define _CS4270_H
|
||||
|
||||
/*
|
||||
* The ASoC codec DAI structure for the CS4270. Assign this structure to
|
||||
* the .codec_dai field of your machine driver's snd_soc_dai_link structure.
|
||||
*/
|
||||
extern struct snd_soc_dai cs4270_dai;
|
||||
|
||||
/*
|
||||
* The ASoC codec device structure for the CS4270. Assign this structure
|
||||
* to the .codec_dev field of your machine driver's snd_soc_device
|
||||
* structure.
|
||||
*/
|
||||
extern struct snd_soc_codec_device soc_codec_device_cs4270;
|
||||
|
||||
#endif
|
||||
|
|
@ -42,15 +42,14 @@ enum master_slave_mode {
|
|||
};
|
||||
|
||||
struct cs42l51_private {
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
unsigned int mclk;
|
||||
unsigned int audio_mode; /* The mode (I2S or left-justified) */
|
||||
enum master_slave_mode func;
|
||||
struct snd_soc_codec codec;
|
||||
u8 reg_cache[CS42L51_NUMREGS];
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *cs42l51_codec;
|
||||
|
||||
#define CS42L51_FORMATS ( \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
|
||||
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
|
||||
|
|
@ -75,134 +74,6 @@ static int cs42l51_fill_cache(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct cs42l51_private *cs42l51;
|
||||
int ret = 0;
|
||||
int reg;
|
||||
|
||||
if (cs42l51_codec)
|
||||
return -EBUSY;
|
||||
|
||||
/* Verify that we have a CS42L51 */
|
||||
ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to read I2C\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
|
||||
(ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
|
||||
dev_err(&i2c_client->dev, "Invalid chip id\n");
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
|
||||
ret & 7);
|
||||
|
||||
cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
|
||||
if (!cs42l51) {
|
||||
dev_err(&i2c_client->dev, "could not allocate codec\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
codec = &cs42l51->codec;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->dev = &i2c_client->dev;
|
||||
codec->name = "CS42L51";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &cs42l51_dai;
|
||||
codec->num_dai = 1;
|
||||
snd_soc_codec_set_drvdata(codec, cs42l51);
|
||||
|
||||
codec->control_data = i2c_client;
|
||||
codec->reg_cache = cs42l51->reg_cache;
|
||||
codec->reg_cache_size = CS42L51_NUMREGS;
|
||||
i2c_set_clientdata(i2c_client, codec);
|
||||
|
||||
ret = cs42l51_fill_cache(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to fill register cache\n");
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
/*
|
||||
* DAC configuration
|
||||
* - Use signal processor
|
||||
* - auto mute
|
||||
* - vol changes immediate
|
||||
* - no de-emphasize
|
||||
*/
|
||||
reg = CS42L51_DAC_CTL_DATA_SEL(1)
|
||||
| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
|
||||
ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
|
||||
if (ret < 0)
|
||||
goto error_alloc;
|
||||
|
||||
cs42l51_dai.dev = codec->dev;
|
||||
cs42l51_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&cs42l51_dai);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to register DAIe\n");
|
||||
goto error_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_reg:
|
||||
snd_soc_unregister_codec(codec);
|
||||
error_alloc:
|
||||
kfree(cs42l51);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42l51_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
|
||||
snd_soc_unregister_dai(&cs42l51_dai);
|
||||
snd_soc_unregister_codec(cs42l51_codec);
|
||||
cs42l51_codec = NULL;
|
||||
kfree(cs42l51);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct i2c_device_id cs42l51_id[] = {
|
||||
{"cs42l51", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs42l51_id);
|
||||
|
||||
static struct i2c_driver cs42l51_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "CS42L51 I2C",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.id_table = cs42l51_id,
|
||||
.probe = cs42l51_i2c_probe,
|
||||
.remove = cs42l51_i2c_remove,
|
||||
};
|
||||
|
||||
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
|
|
@ -484,51 +355,8 @@ static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
|
||||
struct cs42l51_ratios *ratios = NULL;
|
||||
int nr_ratios = 0;
|
||||
unsigned int rates = 0;
|
||||
unsigned int rate_min = -1;
|
||||
unsigned int rate_max = 0;
|
||||
int i;
|
||||
|
||||
cs42l51->mclk = freq;
|
||||
|
||||
switch (cs42l51->func) {
|
||||
case MODE_MASTER:
|
||||
return -EINVAL;
|
||||
case MODE_SLAVE:
|
||||
ratios = slave_ratios;
|
||||
nr_ratios = ARRAY_SIZE(slave_ratios);
|
||||
break;
|
||||
case MODE_SLAVE_AUTO:
|
||||
ratios = slave_auto_ratios;
|
||||
nr_ratios = ARRAY_SIZE(slave_auto_ratios);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_ratios; i++) {
|
||||
unsigned int rate = freq / ratios[i].ratio;
|
||||
rates |= snd_pcm_rate_to_rate_bit(rate);
|
||||
if (rate < rate_min)
|
||||
rate_min = rate;
|
||||
if (rate > rate_max)
|
||||
rate_max = rate;
|
||||
}
|
||||
rates &= ~SNDRV_PCM_RATE_KNOT;
|
||||
|
||||
if (!rates) {
|
||||
dev_err(codec->dev, "could not find a valid sample rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
codec_dai->playback.rates = rates;
|
||||
codec_dai->playback.rate_min = rate_min;
|
||||
codec_dai->playback.rate_max = rate_max;
|
||||
|
||||
codec_dai->capture.rates = rates;
|
||||
codec_dai->capture.rate_min = rate_min;
|
||||
codec_dai->capture.rate_max = rate_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -537,8 +365,7 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
unsigned int i;
|
||||
|
|
@ -670,8 +497,8 @@ static struct snd_soc_dai_ops cs42l51_dai_ops = {
|
|||
.digital_mute = cs42l51_dai_mute,
|
||||
};
|
||||
|
||||
struct snd_soc_dai cs42l51_dai = {
|
||||
.name = "CS42L51 HiFi",
|
||||
static struct snd_soc_dai_driver cs42l51_dai = {
|
||||
.name = "cs42l51-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -688,30 +515,39 @@ struct snd_soc_dai cs42l51_dai = {
|
|||
},
|
||||
.ops = &cs42l51_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42l51_dai);
|
||||
|
||||
|
||||
static int cs42l51_probe(struct platform_device *pdev)
|
||||
static int cs42l51_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, reg;
|
||||
|
||||
if (!cs42l51_codec) {
|
||||
dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
codec->control_data = cs42l51->control_data;
|
||||
|
||||
socdev->card->codec = cs42l51_codec;
|
||||
codec = socdev->card->codec;
|
||||
|
||||
/* Register PCMs */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
ret = cs42l51_fill_cache(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create PCMs\n");
|
||||
dev_err(codec->dev, "failed to fill register cache\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* DAC configuration
|
||||
* - Use signal processor
|
||||
* - auto mute
|
||||
* - vol changes immediate
|
||||
* - no de-emphasize
|
||||
*/
|
||||
reg = CS42L51_DAC_CTL_DATA_SEL(1)
|
||||
| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
|
||||
ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
snd_soc_add_controls(codec, cs42l51_snd_controls,
|
||||
ARRAY_SIZE(cs42l51_snd_controls));
|
||||
snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
|
||||
|
|
@ -722,22 +558,77 @@ static int cs42l51_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
|
||||
.probe = cs42l51_probe,
|
||||
.reg_cache_size = CS42L51_NUMREGS,
|
||||
.reg_word_size = sizeof(u8),
|
||||
};
|
||||
|
||||
static int cs42l51_remove(struct platform_device *pdev)
|
||||
static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct cs42l51_private *cs42l51;
|
||||
int ret;
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
/* Verify that we have a CS42L51 */
|
||||
ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to read I2C\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
|
||||
(ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
|
||||
dev_err(&i2c_client->dev, "Invalid chip id\n");
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
|
||||
ret & 7);
|
||||
|
||||
cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
|
||||
if (!cs42l51) {
|
||||
dev_err(&i2c_client->dev, "could not allocate codec\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs42l51);
|
||||
cs42l51->control_data = i2c_client;
|
||||
cs42l51->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c_client->dev,
|
||||
&soc_codec_device_cs42l51, &cs42l51_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(cs42l51);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42l51_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(cs42l51);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_device_cs42l51 = {
|
||||
.probe = cs42l51_probe,
|
||||
.remove = cs42l51_remove
|
||||
static const struct i2c_device_id cs42l51_id[] = {
|
||||
{"cs42l51", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs42l51_id);
|
||||
|
||||
static struct i2c_driver cs42l51_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs42l51-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.id_table = cs42l51_id,
|
||||
.probe = cs42l51_i2c_probe,
|
||||
.remove = cs42l51_i2c_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
|
||||
|
||||
static int __init cs42l51_init(void)
|
||||
{
|
||||
|
|
@ -758,6 +649,6 @@ static void __exit cs42l51_exit(void)
|
|||
}
|
||||
module_exit(cs42l51_exit);
|
||||
|
||||
MODULE_AUTHOR("Arnaud Patard <a[email protected]>");
|
||||
MODULE_AUTHOR("Arnaud Patard <a[email protected]>");
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -158,6 +158,4 @@
|
|||
#define CS42L51_LASTREG 0x20
|
||||
#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
|
||||
|
||||
extern struct snd_soc_dai cs42l51_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_device_cs42l51;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
|
||||
|
||||
struct cx20442_priv {
|
||||
struct snd_soc_codec codec;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
u8 reg_cache[1];
|
||||
};
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
|
|||
{
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
|
||||
if (reg >= codec->reg_cache_size)
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
return reg_cache[reg];
|
||||
|
|
@ -164,16 +165,17 @@ static int cx20442_pm_to_v253_vsp(u8 value)
|
|||
static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
int vls, vsp, old, len;
|
||||
char buf[18];
|
||||
|
||||
if (reg >= codec->reg_cache_size)
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
/* hw_write and control_data pointers required for talking to the modem
|
||||
* are expected to be set by the line discipline initialization code */
|
||||
if (!codec->hw_write || !codec->control_data)
|
||||
if (!codec->hw_write || !cx20442->control_data)
|
||||
return -EIO;
|
||||
|
||||
old = reg_cache[reg];
|
||||
|
|
@ -202,17 +204,13 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return -ENOMEM;
|
||||
|
||||
dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
|
||||
if (codec->hw_write(codec->control_data, buf, len) != len)
|
||||
if (codec->hw_write(cx20442->control_data, buf, len) != len)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Moved up here as line discipline referres it during initialization */
|
||||
static struct snd_soc_codec *cx20442_codec;
|
||||
|
||||
|
||||
/*
|
||||
* Line discpline related code
|
||||
*
|
||||
|
|
@ -228,15 +226,15 @@ static const char *v253_init = "ate0m0q0+fclass=8\r";
|
|||
/* Line discipline .open() */
|
||||
static int v253_open(struct tty_struct *tty)
|
||||
{
|
||||
struct snd_soc_codec *codec = cx20442_codec;
|
||||
int ret, len = strlen(v253_init);
|
||||
|
||||
/* Doesn't make sense without write callback */
|
||||
if (!tty->ops->write)
|
||||
return -EINVAL;
|
||||
|
||||
/* Pass the codec structure address for use by other ldisc callbacks */
|
||||
tty->disc_data = codec;
|
||||
/* Won't work if no codec pointer has been passed by a card driver */
|
||||
if (!tty->disc_data)
|
||||
return -ENODEV;
|
||||
|
||||
if (tty->ops->write(tty, v253_init, len) != len) {
|
||||
ret = -EIO;
|
||||
|
|
@ -253,15 +251,18 @@ err:
|
|||
static void v253_close(struct tty_struct *tty)
|
||||
{
|
||||
struct snd_soc_codec *codec = tty->disc_data;
|
||||
struct cx20442_priv *cx20442;
|
||||
|
||||
tty->disc_data = NULL;
|
||||
|
||||
if (!codec)
|
||||
return;
|
||||
|
||||
cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Prevent the codec driver from further accessing the modem */
|
||||
codec->hw_write = NULL;
|
||||
codec->control_data = NULL;
|
||||
cx20442->control_data = NULL;
|
||||
codec->pop_time = 0;
|
||||
}
|
||||
|
||||
|
|
@ -277,15 +278,18 @@ static void v253_receive(struct tty_struct *tty,
|
|||
const unsigned char *cp, char *fp, int count)
|
||||
{
|
||||
struct snd_soc_codec *codec = tty->disc_data;
|
||||
struct cx20442_priv *cx20442;
|
||||
|
||||
if (!codec)
|
||||
return;
|
||||
|
||||
if (!codec->control_data) {
|
||||
cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!cx20442->control_data) {
|
||||
/* First modem response, complete setup procedure */
|
||||
|
||||
/* Set up codec driver access to modem controls */
|
||||
codec->control_data = tty;
|
||||
cx20442->control_data = tty;
|
||||
codec->hw_write = (hw_write_t)tty->ops->write;
|
||||
codec->pop_time = 1;
|
||||
}
|
||||
|
|
@ -313,8 +317,8 @@ EXPORT_SYMBOL_GPL(v253_ops);
|
|||
* Codec DAI
|
||||
*/
|
||||
|
||||
struct snd_soc_dai cx20442_dai = {
|
||||
.name = "CX20442",
|
||||
static struct snd_soc_dai_driver cx20442_dai = {
|
||||
.name = "cx20442-voice",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -330,142 +334,63 @@ struct snd_soc_dai cx20442_dai = {
|
|||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cx20442_dai);
|
||||
|
||||
static int cx20442_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
if (!cx20442_codec) {
|
||||
dev_err(&pdev->dev, "cx20442 not yet discovered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
codec = cx20442_codec;
|
||||
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
cx20442_add_widgets(codec);
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int cx20442_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device cx20442_codec_dev = {
|
||||
.probe = cx20442_codec_probe,
|
||||
.remove = cx20442_codec_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cx20442_codec_dev);
|
||||
|
||||
static int cx20442_register(struct cx20442_priv *cx20442)
|
||||
{
|
||||
struct snd_soc_codec *codec = &cx20442->codec;
|
||||
int ret;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->name = "CX20442";
|
||||
codec->owner = THIS_MODULE;
|
||||
snd_soc_codec_set_drvdata(codec, cx20442);
|
||||
|
||||
codec->dai = &cx20442_dai;
|
||||
codec->num_dai = 1;
|
||||
|
||||
codec->reg_cache = &cx20442->reg_cache;
|
||||
codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
|
||||
codec->read = cx20442_read_reg_cache;
|
||||
codec->write = cx20442_write;
|
||||
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
||||
cx20442_dai.dev = codec->dev;
|
||||
|
||||
cx20442_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&cx20442_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
goto err_codec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err:
|
||||
cx20442_codec = NULL;
|
||||
kfree(cx20442);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cx20442_unregister(struct cx20442_priv *cx20442)
|
||||
{
|
||||
snd_soc_unregister_dai(&cx20442_dai);
|
||||
snd_soc_unregister_codec(&cx20442->codec);
|
||||
|
||||
cx20442_codec = NULL;
|
||||
kfree(cx20442);
|
||||
}
|
||||
|
||||
static int cx20442_platform_probe(struct platform_device *pdev)
|
||||
static int cx20442_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cx20442_priv *cx20442;
|
||||
struct snd_soc_codec *codec;
|
||||
|
||||
cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
|
||||
if (cx20442 == NULL)
|
||||
return -ENOMEM;
|
||||
snd_soc_codec_set_drvdata(codec, cx20442);
|
||||
|
||||
codec = &cx20442->codec;
|
||||
cx20442_add_widgets(codec);
|
||||
|
||||
codec->control_data = NULL;
|
||||
cx20442->control_data = NULL;
|
||||
codec->hw_write = NULL;
|
||||
codec->pop_time = 0;
|
||||
|
||||
codec->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, cx20442);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cx20442_register(cx20442);
|
||||
/* power down chip */
|
||||
static int cx20442_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (cx20442->control_data) {
|
||||
struct tty_struct *tty = cx20442->control_data;
|
||||
tty_hangup(tty);
|
||||
}
|
||||
|
||||
kfree(cx20442);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver cx20442_codec_dev = {
|
||||
.probe = cx20442_codec_probe,
|
||||
.remove = cx20442_codec_remove,
|
||||
.reg_cache_size = 1,
|
||||
.reg_word_size = sizeof(u8),
|
||||
.read = cx20442_read_reg_cache,
|
||||
.write = cx20442_write,
|
||||
};
|
||||
|
||||
static int cx20442_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&cx20442_codec_dev, &cx20442_dai, 1);
|
||||
}
|
||||
|
||||
static int __exit cx20442_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
|
||||
|
||||
cx20442_unregister(cx20442);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cx20442_platform_driver = {
|
||||
.driver = {
|
||||
.name = "cx20442",
|
||||
.name = "cx20442-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = cx20442_platform_probe,
|
||||
|
|
@ -487,4 +412,4 @@ module_exit(cx20442_exit);
|
|||
MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
|
||||
MODULE_AUTHOR("Janusz Krzysztofik");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:cx20442");
|
||||
MODULE_ALIAS("platform:cx20442-codec");
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
#ifndef _CX20442_CODEC_H
|
||||
#define _CX20442_CODEC_H
|
||||
|
||||
extern struct snd_soc_dai cx20442_dai;
|
||||
extern struct snd_soc_codec_device cx20442_codec_dev;
|
||||
extern struct tty_ldisc_ops v253_ops;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "da7210.h"
|
||||
|
||||
/* DA7210 register space */
|
||||
#define DA7210_STATUS 0x02
|
||||
#define DA7210_STARTUP1 0x03
|
||||
|
|
@ -162,11 +160,10 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
|
|||
|
||||
/* Codec private data */
|
||||
struct da7210_priv {
|
||||
struct snd_soc_codec codec;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *da7210_codec;
|
||||
|
||||
/*
|
||||
* Register cache
|
||||
*/
|
||||
|
|
@ -209,12 +206,12 @@ static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
|
|||
u8 *cache = codec->reg_cache;
|
||||
u8 data[2];
|
||||
|
||||
BUG_ON(codec->volatile_register);
|
||||
BUG_ON(codec->driver->volatile_register);
|
||||
|
||||
data[0] = reg & 0xff;
|
||||
data[1] = value & 0xff;
|
||||
|
||||
if (reg >= codec->reg_cache_size)
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EIO;
|
||||
|
||||
if (2 != codec->hw_write(codec->control_data, data, 2))
|
||||
|
|
@ -267,8 +264,7 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
u32 dai_cfg1;
|
||||
u32 hpf_reg, hpf_mask, hpf_value;
|
||||
u32 fs, bypass;
|
||||
|
|
@ -430,9 +426,8 @@ static struct snd_soc_dai_ops da7210_dai_ops = {
|
|||
.set_fmt = da7210_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai da7210_dai = {
|
||||
.name = "DA7210 IIS",
|
||||
.id = 0,
|
||||
static struct snd_soc_dai_driver da7210_dai = {
|
||||
.name = "da7210-hifi",
|
||||
/* playback capabilities */
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
|
|
@ -452,55 +447,15 @@ struct snd_soc_dai da7210_dai = {
|
|||
.ops = &da7210_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(da7210_dai);
|
||||
|
||||
/*
|
||||
* Initialize the DA7210 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int da7210_init(struct da7210_priv *da7210)
|
||||
static int da7210_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = &da7210->codec;
|
||||
int ret = 0;
|
||||
struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (da7210_codec) {
|
||||
dev_err(codec->dev, "Another da7210 is registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, da7210);
|
||||
codec->name = "DA7210";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = da7210_read;
|
||||
codec->write = da7210_write;
|
||||
codec->dai = &da7210_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->control_data = da7210->control_data;
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
codec->reg_cache_size = ARRAY_SIZE(da7210_reg);
|
||||
codec->reg_cache = kmemdup(da7210_reg,
|
||||
sizeof(da7210_reg), GFP_KERNEL);
|
||||
|
||||
if (!codec->reg_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
da7210_dai.dev = codec->dev;
|
||||
da7210_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to register CODEC: %d\n", ret);
|
||||
goto init_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&da7210_dai);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
goto codec_err;
|
||||
}
|
||||
|
||||
/* FIXME
|
||||
*
|
||||
|
|
@ -583,54 +538,50 @@ static int da7210_init(struct da7210_priv *da7210)
|
|||
/* Activate all enabled subsystem */
|
||||
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
|
||||
|
||||
return ret;
|
||||
snd_soc_add_controls(codec, da7210_snd_controls,
|
||||
ARRAY_SIZE(da7210_snd_controls));
|
||||
|
||||
codec_err:
|
||||
snd_soc_unregister_codec(codec);
|
||||
init_err:
|
||||
kfree(codec->reg_cache);
|
||||
codec->reg_cache = NULL;
|
||||
|
||||
return ret;
|
||||
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
|
||||
.probe = da7210_probe,
|
||||
.read = da7210_read,
|
||||
.write = da7210_write,
|
||||
.reg_cache_size = ARRAY_SIZE(da7210_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = da7210_reg,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct da7210_priv *da7210;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
|
||||
if (!da7210)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &da7210->codec;
|
||||
codec->dev = &i2c->dev;
|
||||
|
||||
i2c_set_clientdata(i2c, da7210);
|
||||
codec->control_data = i2c;
|
||||
da7210->control_data = i2c;
|
||||
da7210->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = da7210_init(da7210);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to initialise da7210 audio codec\n");
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_da7210, &da7210_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(da7210);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit da7210_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct da7210_priv *da7210 = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_dai(&da7210_dai);
|
||||
kfree(da7210->codec.reg_cache);
|
||||
kfree(da7210);
|
||||
da7210_codec = NULL;
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -643,59 +594,15 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
|
|||
/* I2C codec control layer */
|
||||
static struct i2c_driver da7210_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "DA7210 I2C Codec",
|
||||
.name = "da7210-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = da7210_i2c_probe,
|
||||
.remove = __devexit_p(da7210_i2c_remove),
|
||||
.id_table = da7210_i2c_id,
|
||||
.probe = da7210_i2c_probe,
|
||||
.remove = __devexit_p(da7210_i2c_remove),
|
||||
.id_table = da7210_i2c_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int da7210_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
if (!da7210_codec) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = da7210_codec;
|
||||
codec = da7210_codec;
|
||||
|
||||
/* Register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0)
|
||||
goto pcm_err;
|
||||
|
||||
snd_soc_add_controls(da7210_codec, da7210_snd_controls,
|
||||
ARRAY_SIZE(da7210_snd_controls));
|
||||
|
||||
dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da7210_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_da7210 = {
|
||||
.probe = da7210_probe,
|
||||
.remove = da7210_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
|
||||
|
||||
static int __init da7210_modinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* da7210.h -- audio driver for da7210
|
||||
*
|
||||
* Copyright (c) 2009 Dialog Semiconductor
|
||||
* Written by David Chen <Dajun.chen@diasemi.com>
|
||||
*
|
||||
* Copyright (C) 2009 Renesas Solutions Corp.
|
||||
* Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DA7210_H
|
||||
#define _DA7210_H
|
||||
|
||||
extern struct snd_soc_dai da7210_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_da7210;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -74,29 +74,22 @@ static const uint32_t jz4740_codec_regs[] = {
|
|||
struct jz4740_codec {
|
||||
void __iomem *base;
|
||||
struct resource *mem;
|
||||
|
||||
uint32_t reg_cache[2];
|
||||
struct snd_soc_codec codec;
|
||||
};
|
||||
|
||||
static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
|
||||
{
|
||||
return container_of(codec, struct jz4740_codec, codec);
|
||||
}
|
||||
|
||||
static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
|
||||
return readl(jz4740_codec->base + (reg << 2));
|
||||
}
|
||||
|
||||
static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
|
||||
struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
|
||||
u32 *cache = codec->reg_cache;
|
||||
|
||||
jz4740_codec->reg_cache[reg] = val;
|
||||
cache[reg] = val;
|
||||
writel(val, jz4740_codec->base + (reg << 2));
|
||||
|
||||
return 0;
|
||||
|
|
@ -172,8 +165,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
uint32_t val;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec =rtd->codec;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 8000:
|
||||
|
|
@ -219,8 +211,8 @@ static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
|
|||
.hw_params = jz4740_codec_hw_params,
|
||||
};
|
||||
|
||||
struct snd_soc_dai jz4740_codec_dai = {
|
||||
.name = "jz4740",
|
||||
static struct snd_soc_dai_driver jz4740_codec_dai = {
|
||||
.name = "jz4740-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -238,7 +230,6 @@ struct snd_soc_dai jz4740_codec_dai = {
|
|||
.ops = &jz4740_codec_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(jz4740_codec_dai);
|
||||
|
||||
static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
|
||||
{
|
||||
|
|
@ -302,23 +293,10 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec *jz4740_codec_codec;
|
||||
|
||||
static int jz4740_codec_dev_probe(struct platform_device *pdev)
|
||||
static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = jz4740_codec_codec;
|
||||
|
||||
BUG_ON(!codec);
|
||||
|
||||
socdev->card->codec = codec;
|
||||
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
|
||||
JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
|
||||
|
||||
snd_soc_add_controls(codec, jz4740_codec_controls,
|
||||
ARRAY_SIZE(jz4740_codec_controls));
|
||||
|
|
@ -331,34 +309,27 @@ static int jz4740_codec_dev_probe(struct platform_device *pdev)
|
|||
|
||||
snd_soc_dapm_new_widgets(codec);
|
||||
|
||||
jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz4740_codec_dev_remove(struct platform_device *pdev)
|
||||
static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
}
|
||||
|
||||
static int jz4740_codec_resume(struct platform_device *pdev)
|
||||
static int jz4740_codec_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
}
|
||||
|
||||
|
|
@ -367,19 +338,23 @@ static int jz4740_codec_resume(struct platform_device *pdev)
|
|||
#define jz4740_codec_resume NULL
|
||||
#endif
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
|
||||
.probe = jz4740_codec_dev_probe,
|
||||
.remove = jz4740_codec_dev_remove,
|
||||
.suspend = jz4740_codec_suspend,
|
||||
.resume = jz4740_codec_resume,
|
||||
.read = jz4740_codec_read,
|
||||
.write = jz4740_codec_write,
|
||||
.set_bias_level = jz4740_codec_set_bias_level,
|
||||
.reg_cache_default = jz4740_codec_regs,
|
||||
.reg_word_size = sizeof(u32),
|
||||
.reg_cache_size = 2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
|
||||
|
||||
static int __devinit jz4740_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct jz4740_codec *jz4740_codec;
|
||||
struct snd_soc_codec *codec;
|
||||
struct resource *mem;
|
||||
|
||||
jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
|
||||
|
|
@ -408,55 +383,17 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
|
|||
}
|
||||
jz4740_codec->mem = mem;
|
||||
|
||||
jz4740_codec_dai.dev = &pdev->dev;
|
||||
|
||||
codec = &jz4740_codec->codec;
|
||||
|
||||
codec->dev = &pdev->dev;
|
||||
codec->name = "jz4740";
|
||||
codec->owner = THIS_MODULE;
|
||||
|
||||
codec->read = jz4740_codec_read;
|
||||
codec->write = jz4740_codec_write;
|
||||
codec->set_bias_level = jz4740_codec_set_bias_level;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
||||
codec->dai = &jz4740_codec_dai;
|
||||
codec->num_dai = 1;
|
||||
|
||||
codec->reg_cache = jz4740_codec->reg_cache;
|
||||
codec->reg_cache_size = 2;
|
||||
memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
jz4740_codec_codec = codec;
|
||||
|
||||
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
|
||||
JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
|
||||
|
||||
platform_set_drvdata(pdev, jz4740_codec);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
ret = snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register codec\n");
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&jz4740_codec_dai);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register codec dai\n");
|
||||
goto err_unregister_codec;
|
||||
}
|
||||
|
||||
jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err_iounmap:
|
||||
iounmap(jz4740_codec->base);
|
||||
err_release_mem_region:
|
||||
|
|
@ -472,8 +409,7 @@ static int __devexit jz4740_codec_remove(struct platform_device *pdev)
|
|||
struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
|
||||
struct resource *mem = jz4740_codec->mem;
|
||||
|
||||
snd_soc_unregister_dai(&jz4740_codec_dai);
|
||||
snd_soc_unregister_codec(&jz4740_codec->codec);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
iounmap(jz4740_codec->base);
|
||||
release_mem_region(mem->start, resource_size(mem));
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__
|
||||
#define __SND_SOC_CODECS_JZ4740_CODEC_H__
|
||||
|
||||
extern struct snd_soc_dai jz4740_codec_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
|
||||
|
||||
#endif
|
||||
2097
sound/soc/codecs/max98088.c
Normal file
2097
sound/soc/codecs/max98088.c
Normal file
File diff suppressed because it is too large
Load diff
193
sound/soc/codecs/max98088.h
Normal file
193
sound/soc/codecs/max98088.h
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* max98088.h -- MAX98088 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2010 Maxim Integrated Products
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MAX98088_H
|
||||
#define _MAX98088_H
|
||||
|
||||
/*
|
||||
* MAX98088 Registers Definition
|
||||
*/
|
||||
#define M98088_REG_00_IRQ_STATUS 0x00
|
||||
#define M98088_REG_01_MIC_STATUS 0x01
|
||||
#define M98088_REG_02_JACK_STAUS 0x02
|
||||
#define M98088_REG_03_BATTERY_VOLTAGE 0x03
|
||||
#define M98088_REG_0F_IRQ_ENABLE 0x0F
|
||||
#define M98088_REG_10_SYS_CLK 0x10
|
||||
#define M98088_REG_11_DAI1_CLKMODE 0x11
|
||||
#define M98088_REG_12_DAI1_CLKCFG_HI 0x12
|
||||
#define M98088_REG_13_DAI1_CLKCFG_LO 0x13
|
||||
#define M98088_REG_14_DAI1_FORMAT 0x14
|
||||
#define M98088_REG_15_DAI1_CLOCK 0x15
|
||||
#define M98088_REG_16_DAI1_IOCFG 0x16
|
||||
#define M98088_REG_17_DAI1_TDM 0x17
|
||||
#define M98088_REG_18_DAI1_FILTERS 0x18
|
||||
#define M98088_REG_19_DAI2_CLKMODE 0x19
|
||||
#define M98088_REG_1A_DAI2_CLKCFG_HI 0x1A
|
||||
#define M98088_REG_1B_DAI2_CLKCFG_LO 0x1B
|
||||
#define M98088_REG_1C_DAI2_FORMAT 0x1C
|
||||
#define M98088_REG_1D_DAI2_CLOCK 0x1D
|
||||
#define M98088_REG_1E_DAI2_IOCFG 0x1E
|
||||
#define M98088_REG_1F_DAI2_TDM 0x1F
|
||||
#define M98088_REG_20_DAI2_FILTERS 0x20
|
||||
#define M98088_REG_21_SRC 0x21
|
||||
#define M98088_REG_22_MIX_DAC 0x22
|
||||
#define M98088_REG_23_MIX_ADC_LEFT 0x23
|
||||
#define M98088_REG_24_MIX_ADC_RIGHT 0x24
|
||||
#define M98088_REG_25_MIX_HP_LEFT 0x25
|
||||
#define M98088_REG_26_MIX_HP_RIGHT 0x26
|
||||
#define M98088_REG_27_MIX_HP_CNTL 0x27
|
||||
#define M98088_REG_28_MIX_REC_LEFT 0x28
|
||||
#define M98088_REG_29_MIX_REC_RIGHT 0x29
|
||||
#define M98088_REG_2A_MIC_REC_CNTL 0x2A
|
||||
#define M98088_REG_2B_MIX_SPK_LEFT 0x2B
|
||||
#define M98088_REG_2C_MIX_SPK_RIGHT 0x2C
|
||||
#define M98088_REG_2D_MIX_SPK_CNTL 0x2D
|
||||
#define M98088_REG_2E_LVL_SIDETONE 0x2E
|
||||
#define M98088_REG_2F_LVL_DAI1_PLAY 0x2F
|
||||
#define M98088_REG_30_LVL_DAI1_PLAY_EQ 0x30
|
||||
#define M98088_REG_31_LVL_DAI2_PLAY 0x31
|
||||
#define M98088_REG_32_LVL_DAI2_PLAY_EQ 0x32
|
||||
#define M98088_REG_33_LVL_ADC_L 0x33
|
||||
#define M98088_REG_34_LVL_ADC_R 0x34
|
||||
#define M98088_REG_35_LVL_MIC1 0x35
|
||||
#define M98088_REG_36_LVL_MIC2 0x36
|
||||
#define M98088_REG_37_LVL_INA 0x37
|
||||
#define M98088_REG_38_LVL_INB 0x38
|
||||
#define M98088_REG_39_LVL_HP_L 0x39
|
||||
#define M98088_REG_3A_LVL_HP_R 0x3A
|
||||
#define M98088_REG_3B_LVL_REC_L 0x3B
|
||||
#define M98088_REG_3C_LVL_REC_R 0x3C
|
||||
#define M98088_REG_3D_LVL_SPK_L 0x3D
|
||||
#define M98088_REG_3E_LVL_SPK_R 0x3E
|
||||
#define M98088_REG_3F_MICAGC_CFG 0x3F
|
||||
#define M98088_REG_40_MICAGC_THRESH 0x40
|
||||
#define M98088_REG_41_SPKDHP 0x41
|
||||
#define M98088_REG_42_SPKDHP_THRESH 0x42
|
||||
#define M98088_REG_43_SPKALC_COMP 0x43
|
||||
#define M98088_REG_44_PWRLMT_CFG 0x44
|
||||
#define M98088_REG_45_PWRLMT_TIME 0x45
|
||||
#define M98088_REG_46_THDLMT_CFG 0x46
|
||||
#define M98088_REG_47_CFG_AUDIO_IN 0x47
|
||||
#define M98088_REG_48_CFG_MIC 0x48
|
||||
#define M98088_REG_49_CFG_LEVEL 0x49
|
||||
#define M98088_REG_4A_CFG_BYPASS 0x4A
|
||||
#define M98088_REG_4B_CFG_JACKDET 0x4B
|
||||
#define M98088_REG_4C_PWR_EN_IN 0x4C
|
||||
#define M98088_REG_4D_PWR_EN_OUT 0x4D
|
||||
#define M98088_REG_4E_BIAS_CNTL 0x4E
|
||||
#define M98088_REG_4F_DAC_BIAS1 0x4F
|
||||
#define M98088_REG_50_DAC_BIAS2 0x50
|
||||
#define M98088_REG_51_PWR_SYS 0x51
|
||||
#define M98088_REG_52_DAI1_EQ_BASE 0x52
|
||||
#define M98088_REG_84_DAI2_EQ_BASE 0x84
|
||||
#define M98088_REG_B6_DAI1_BIQUAD_BASE 0xB6
|
||||
#define M98088_REG_C0_DAI2_BIQUAD_BASE 0xC0
|
||||
#define M98088_REG_FF_REV_ID 0xFF
|
||||
|
||||
#define M98088_REG_CNT (0xFF+1)
|
||||
|
||||
/* MAX98088 Registers Bit Fields */
|
||||
|
||||
/* M98088_REG_11_DAI1_CLKMODE, M98088_REG_19_DAI2_CLKMODE */
|
||||
#define M98088_CLKMODE_MASK 0xFF
|
||||
|
||||
/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
|
||||
#define M98088_DAI_MAS (1<<7)
|
||||
#define M98088_DAI_WCI (1<<6)
|
||||
#define M98088_DAI_BCI (1<<5)
|
||||
#define M98088_DAI_DLY (1<<4)
|
||||
#define M98088_DAI_TDM (1<<2)
|
||||
#define M98088_DAI_FSW (1<<1)
|
||||
#define M98088_DAI_WS (1<<0)
|
||||
|
||||
/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
|
||||
#define M98088_DAI_BSEL64 (1<<0)
|
||||
#define M98088_DAI_OSR64 (1<<6)
|
||||
|
||||
/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
|
||||
#define M98088_S1NORMAL (1<<6)
|
||||
#define M98088_S2NORMAL (2<<6)
|
||||
#define M98088_SDATA (3<<0)
|
||||
|
||||
/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
|
||||
#define M98088_DAI_DHF (1<<3)
|
||||
|
||||
/* M98088_REG_22_MIX_DAC */
|
||||
#define M98088_DAI1L_TO_DACL (1<<7)
|
||||
#define M98088_DAI1R_TO_DACL (1<<6)
|
||||
#define M98088_DAI2L_TO_DACL (1<<5)
|
||||
#define M98088_DAI2R_TO_DACL (1<<4)
|
||||
#define M98088_DAI1L_TO_DACR (1<<3)
|
||||
#define M98088_DAI1R_TO_DACR (1<<2)
|
||||
#define M98088_DAI2L_TO_DACR (1<<1)
|
||||
#define M98088_DAI2R_TO_DACR (1<<0)
|
||||
|
||||
/* M98088_REG_2A_MIC_REC_CNTL */
|
||||
#define M98088_REC_LINEMODE (1<<7)
|
||||
#define M98088_REC_LINEMODE_MASK (1<<7)
|
||||
|
||||
/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
|
||||
#define M98088_MICPRE_MASK (3<<5)
|
||||
#define M98088_MICPRE_SHIFT 5
|
||||
|
||||
/* M98088_REG_3A_LVL_HP_R */
|
||||
#define M98088_HP_MUTE (1<<7)
|
||||
|
||||
/* M98088_REG_3C_LVL_REC_R */
|
||||
#define M98088_REC_MUTE (1<<7)
|
||||
|
||||
/* M98088_REG_3E_LVL_SPK_R */
|
||||
#define M98088_SP_MUTE (1<<7)
|
||||
|
||||
/* M98088_REG_48_CFG_MIC */
|
||||
#define M98088_EXTMIC_MASK (3<<0)
|
||||
#define M98088_DIGMIC_L (1<<5)
|
||||
#define M98088_DIGMIC_R (1<<4)
|
||||
|
||||
/* M98088_REG_49_CFG_LEVEL */
|
||||
#define M98088_VSEN (1<<6)
|
||||
#define M98088_ZDEN (1<<5)
|
||||
#define M98088_EQ2EN (1<<1)
|
||||
#define M98088_EQ1EN (1<<0)
|
||||
|
||||
/* M98088_REG_4C_PWR_EN_IN */
|
||||
#define M98088_INAEN (1<<7)
|
||||
#define M98088_INBEN (1<<6)
|
||||
#define M98088_MBEN (1<<3)
|
||||
#define M98088_ADLEN (1<<1)
|
||||
#define M98088_ADREN (1<<0)
|
||||
|
||||
/* M98088_REG_4D_PWR_EN_OUT */
|
||||
#define M98088_HPLEN (1<<7)
|
||||
#define M98088_HPREN (1<<6)
|
||||
#define M98088_HPEN ((1<<7)|(1<<6))
|
||||
#define M98088_SPLEN (1<<5)
|
||||
#define M98088_SPREN (1<<4)
|
||||
#define M98088_RECEN (1<<3)
|
||||
#define M98088_DALEN (1<<1)
|
||||
#define M98088_DAREN (1<<0)
|
||||
|
||||
/* M98088_REG_51_PWR_SYS */
|
||||
#define M98088_SHDNRUN (1<<7)
|
||||
#define M98088_PERFMODE (1<<3)
|
||||
#define M98088_HPPLYBACK (1<<2)
|
||||
#define M98088_PWRSV8K (1<<1)
|
||||
#define M98088_PWRSV (1<<0)
|
||||
|
||||
/* Line inputs */
|
||||
#define LINE_INA 0
|
||||
#define LINE_INB 1
|
||||
|
||||
#define M98088_COEFS_PER_BAND 5
|
||||
|
||||
#define M98088_BYTE1(w) ((w >> 8) & 0xff)
|
||||
#define M98088_BYTE0(w) (w & 0xff)
|
||||
|
||||
#endif
|
||||
|
|
@ -32,8 +32,8 @@
|
|||
#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
|
||||
SNDRV_PCM_RATE_48000)
|
||||
|
||||
struct snd_soc_dai pcm3008_dai = {
|
||||
.name = "PCM3008 HiFi",
|
||||
static struct snd_soc_dai_driver pcm3008_dai = {
|
||||
.name = "pcm3008-hifi",
|
||||
.playback = {
|
||||
.stream_name = "PCM3008 Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -49,7 +49,6 @@ struct snd_soc_dai pcm3008_dai = {
|
|||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(pcm3008_dai);
|
||||
|
||||
static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
|
||||
{
|
||||
|
|
@ -59,38 +58,13 @@ static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
|
|||
gpio_free(setup->pdda_pin);
|
||||
}
|
||||
|
||||
static int pcm3008_soc_probe(struct platform_device *pdev)
|
||||
static int pcm3008_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct pcm3008_setup_data *setup = socdev->codec_data;
|
||||
struct pcm3008_setup_data *setup = codec->dev->platform_data;
|
||||
int ret = 0;
|
||||
|
||||
printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
|
||||
|
||||
socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (!socdev->card->codec)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = socdev->card->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
codec->name = "PCM3008";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &pcm3008_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->write = NULL;
|
||||
codec->read = NULL;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
/* Register PCMs. */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "pcm3008: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
/* DEM1 DEM0 DE-EMPHASIS_MODE
|
||||
* Low Low De-emphasis 44.1 kHz ON
|
||||
* Low High De-emphasis OFF
|
||||
|
|
@ -130,33 +104,22 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
|
|||
|
||||
gpio_err:
|
||||
pcm3008_gpio_free(setup);
|
||||
pcm_err:
|
||||
kfree(socdev->card->codec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcm3008_soc_remove(struct platform_device *pdev)
|
||||
static int pcm3008_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct pcm3008_setup_data *setup = socdev->codec_data;
|
||||
|
||||
if (!codec)
|
||||
return 0;
|
||||
struct pcm3008_setup_data *setup = codec->dev->platform_data;
|
||||
|
||||
pcm3008_gpio_free(setup);
|
||||
snd_soc_free_pcms(socdev);
|
||||
kfree(socdev->card->codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
|
||||
static int pcm3008_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct pcm3008_setup_data *setup = socdev->codec_data;
|
||||
struct pcm3008_setup_data *setup = codec->dev->platform_data;
|
||||
|
||||
gpio_set_value(setup->pdad_pin, 0);
|
||||
gpio_set_value(setup->pdda_pin, 0);
|
||||
|
|
@ -164,10 +127,9 @@ static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3008_soc_resume(struct platform_device *pdev)
|
||||
static int pcm3008_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct pcm3008_setup_data *setup = socdev->codec_data;
|
||||
struct pcm3008_setup_data *setup = codec->dev->platform_data;
|
||||
|
||||
gpio_set_value(setup->pdad_pin, 1);
|
||||
gpio_set_value(setup->pdda_pin, 1);
|
||||
|
|
@ -179,23 +141,45 @@ static int pcm3008_soc_resume(struct platform_device *pdev)
|
|||
#define pcm3008_soc_resume NULL
|
||||
#endif
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
|
||||
.probe = pcm3008_soc_probe,
|
||||
.remove = pcm3008_soc_remove,
|
||||
.suspend = pcm3008_soc_suspend,
|
||||
.resume = pcm3008_soc_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
|
||||
|
||||
static int __init pcm3008_init(void)
|
||||
static int __devinit pcm3008_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dai(&pcm3008_dai);
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_pcm3008, &pcm3008_dai, 1);
|
||||
}
|
||||
module_init(pcm3008_init);
|
||||
|
||||
static int __devexit pcm3008_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:pcm3008-codec");
|
||||
|
||||
static struct platform_driver pcm3008_codec_driver = {
|
||||
.probe = pcm3008_codec_probe,
|
||||
.remove = __devexit_p(pcm3008_codec_remove),
|
||||
.driver = {
|
||||
.name = "pcm3008-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pcm3008_modinit(void)
|
||||
{
|
||||
return platform_driver_register(&pcm3008_codec_driver);
|
||||
}
|
||||
module_init(pcm3008_modinit);
|
||||
|
||||
static void __exit pcm3008_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&pcm3008_dai);
|
||||
platform_driver_unregister(&pcm3008_codec_driver);
|
||||
}
|
||||
module_exit(pcm3008_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,4 @@ struct pcm3008_setup_data {
|
|||
unsigned pdda_pin;
|
||||
};
|
||||
|
||||
extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
|
||||
extern struct snd_soc_dai pcm3008_dai;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,57 +21,16 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "spdif_transciever.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
|
||||
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
|
||||
static struct snd_soc_codec *spdif_dit_codec;
|
||||
|
||||
static int spdif_dit_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
static struct snd_soc_codec_driver soc_codec_spdif_dit;
|
||||
|
||||
if (spdif_dit_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = spdif_dit_codec;
|
||||
codec = spdif_dit_codec;
|
||||
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto err_create_pcms;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_create_pcms:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spdif_dit_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
|
||||
.probe = spdif_dit_codec_probe,
|
||||
.remove = spdif_dit_codec_remove,
|
||||
}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
|
||||
|
||||
struct snd_soc_dai dit_stub_dai = {
|
||||
.name = "DIT",
|
||||
static struct snd_soc_dai_driver dit_stub_dai = {
|
||||
.name = "dit-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -80,65 +39,16 @@ struct snd_soc_dai dit_stub_dai = {
|
|||
.formats = STUB_FORMATS,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(dit_stub_dai);
|
||||
|
||||
static int spdif_dit_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
if (spdif_dit_codec) {
|
||||
dev_err(&pdev->dev, "Another Codec is registered\n");
|
||||
ret = -EINVAL;
|
||||
goto err_reg_codec;
|
||||
}
|
||||
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->dev = &pdev->dev;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->name = "spdif-dit";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &dit_stub_dai;
|
||||
codec->num_dai = 1;
|
||||
|
||||
spdif_dit_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err_reg_codec;
|
||||
}
|
||||
|
||||
dit_stub_dai.dev = &pdev->dev;
|
||||
ret = snd_soc_register_dai(&dit_stub_dai);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to register dai: %d\n", ret);
|
||||
goto err_reg_dai;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_dai:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err_reg_codec:
|
||||
kfree(spdif_dit_codec);
|
||||
return ret;
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
|
||||
&dit_stub_dai, 1);
|
||||
}
|
||||
|
||||
static int spdif_dit_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&dit_stub_dai);
|
||||
snd_soc_unregister_codec(spdif_dit_codec);
|
||||
kfree(spdif_dit_codec);
|
||||
spdif_dit_codec = NULL;
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* ALSA SoC DIT/DIR driver header
|
||||
*
|
||||
* Author: Steve Chen, <schen@mvista.com>
|
||||
* Copyright: (C) 2008 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.
|
||||
*/
|
||||
|
||||
#ifndef CODEC_STUBS_H
|
||||
#define CODEC_STUBS_H
|
||||
|
||||
extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
|
||||
extern struct snd_soc_dai dit_stub_dai;
|
||||
|
||||
#endif /* CODEC_STUBS_H */
|
||||
|
|
@ -45,11 +45,11 @@
|
|||
|
||||
#define SSM2602_VERSION "0.1"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ssm2602;
|
||||
|
||||
/* codec private data */
|
||||
struct ssm2602_priv {
|
||||
unsigned int sysclk;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
struct snd_pcm_substream *master_substream;
|
||||
struct snd_pcm_substream *slave_substream;
|
||||
};
|
||||
|
|
@ -276,8 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
u16 srate;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
|
||||
|
|
@ -321,8 +320,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
struct snd_pcm_runtime *master_runtime;
|
||||
|
|
@ -360,8 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
/* set active */
|
||||
ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
|
||||
|
||||
|
|
@ -372,8 +369,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* deactivate */
|
||||
|
|
@ -518,8 +514,8 @@ static struct snd_soc_dai_ops ssm2602_dai_ops = {
|
|||
.set_fmt = ssm2602_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai ssm2602_dai = {
|
||||
.name = "SSM2602",
|
||||
static struct snd_soc_dai_driver ssm2602_dai = {
|
||||
.name = "ssm2602-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -534,21 +530,15 @@ struct snd_soc_dai ssm2602_dai = {
|
|||
.formats = SSM2602_FORMATS,},
|
||||
.ops = &ssm2602_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ssm2602_dai);
|
||||
|
||||
static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssm2602_resume(struct platform_device *pdev)
|
||||
static int ssm2602_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int i;
|
||||
u8 data[2];
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
|
@ -563,36 +553,17 @@ static int ssm2602_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the ssm2602 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int ssm2602_init(struct snd_soc_device *socdev)
|
||||
static int ssm2602_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int reg, ret = 0;
|
||||
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0, reg;
|
||||
|
||||
codec->name = "SSM2602";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = ssm2602_read_reg_cache;
|
||||
codec->write = ssm2602_write;
|
||||
codec->set_bias_level = ssm2602_set_bias_level;
|
||||
codec->dai = &ssm2602_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = sizeof(ssm2602_reg);
|
||||
codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
|
||||
GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL)
|
||||
return -ENOMEM;
|
||||
pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
|
||||
|
||||
codec->control_data = ssm2602->control_data;
|
||||
|
||||
ssm2602_reset(codec);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
pr_err("ssm2602: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
/*power on device*/
|
||||
ssm2602_write(codec, SSM2602_ACTIVE, 0);
|
||||
/* set the update bits */
|
||||
|
|
@ -614,13 +585,27 @@ static int ssm2602_init(struct snd_soc_device *socdev)
|
|||
ssm2602_add_widgets(codec);
|
||||
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
kfree(codec->reg_cache);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_device *ssm2602_socdev;
|
||||
/* remove everything here */
|
||||
static int ssm2602_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
|
||||
.probe = ssm2602_probe,
|
||||
.remove = ssm2602_remove,
|
||||
.suspend = ssm2602_suspend,
|
||||
.resume = ssm2602_resume,
|
||||
.read = ssm2602_read_reg_cache,
|
||||
.write = ssm2602_write,
|
||||
.set_bias_level = ssm2602_set_bias_level,
|
||||
.reg_cache_size = sizeof(ssm2602_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = ssm2602_reg,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
/*
|
||||
|
|
@ -632,24 +617,28 @@ static struct snd_soc_device *ssm2602_socdev;
|
|||
static int ssm2602_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct snd_soc_device *socdev = ssm2602_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct ssm2602_priv *ssm2602;
|
||||
int ret;
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
codec->control_data = i2c;
|
||||
ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
|
||||
if (ssm2602 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ssm2602_init(socdev);
|
||||
i2c_set_clientdata(i2c, ssm2602);
|
||||
ssm2602->control_data = i2c;
|
||||
ssm2602->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
|
||||
if (ret < 0)
|
||||
pr_err("failed to initialise SSM2602\n");
|
||||
|
||||
kfree(ssm2602);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ssm2602_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct snd_soc_codec *codec = i2c_get_clientdata(client);
|
||||
kfree(codec->reg_cache);
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -658,130 +647,39 @@ static const struct i2c_device_id ssm2602_i2c_id[] = {
|
|||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
|
||||
|
||||
/* corgi i2c codec control layer */
|
||||
static struct i2c_driver ssm2602_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "SSM2602 I2C Codec",
|
||||
.name = "ssm2602-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ssm2602_i2c_probe,
|
||||
.remove = ssm2602_i2c_remove,
|
||||
.id_table = ssm2602_i2c_id,
|
||||
};
|
||||
|
||||
static int ssm2602_add_i2c_device(struct platform_device *pdev,
|
||||
const struct ssm2602_setup_data *setup)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&ssm2602_i2c_driver);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "can't add i2c driver\n");
|
||||
return ret;
|
||||
}
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = setup->i2c_address;
|
||||
strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
|
||||
adapter = i2c_get_adapter(setup->i2c_bus);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "can't get i2c adapter %d\n",
|
||||
setup->i2c_bus);
|
||||
goto err_driver;
|
||||
}
|
||||
client = i2c_new_device(adapter, &info);
|
||||
i2c_put_adapter(adapter);
|
||||
if (!client) {
|
||||
dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
|
||||
(unsigned int)info.addr);
|
||||
goto err_driver;
|
||||
}
|
||||
return 0;
|
||||
err_driver:
|
||||
i2c_del_driver(&ssm2602_i2c_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ssm2602_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct ssm2602_setup_data *setup;
|
||||
struct snd_soc_codec *codec;
|
||||
struct ssm2602_priv *ssm2602;
|
||||
int ret = 0;
|
||||
|
||||
pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
|
||||
|
||||
setup = socdev->codec_data;
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
|
||||
if (ssm2602 == NULL) {
|
||||
kfree(codec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, ssm2602);
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ssm2602_socdev = socdev;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
if (setup->i2c_address) {
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
ret = ssm2602_add_i2c_device(pdev, setup);
|
||||
}
|
||||
#else
|
||||
/* other interfaces */
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* remove everything here */
|
||||
static int ssm2602_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec->control_data)
|
||||
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&ssm2602_i2c_driver);
|
||||
#endif
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
|
||||
.probe = ssm2602_probe,
|
||||
.remove = ssm2602_remove,
|
||||
.suspend = ssm2602_suspend,
|
||||
.resume = ssm2602_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
|
||||
|
||||
static int __init ssm2602_modinit(void)
|
||||
{
|
||||
return snd_soc_register_dai(&ssm2602_dai);
|
||||
int ret = 0;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&ssm2602_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(ssm2602_modinit);
|
||||
|
||||
static void __exit ssm2602_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&ssm2602_dai);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&ssm2602_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(ssm2602_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,4 @@ struct ssm2602_setup_data {
|
|||
unsigned short i2c_address;
|
||||
};
|
||||
|
||||
extern struct snd_soc_dai ssm2602_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/soc-of-simple.h>
|
||||
|
||||
#include "stac9766.h"
|
||||
|
||||
|
|
@ -257,20 +256,15 @@ static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stac9766_codec_suspend(struct platform_device *pdev,
|
||||
static int stac9766_codec_suspend(struct snd_soc_codec *codec,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stac9766_codec_resume(struct platform_device *pdev)
|
||||
static int stac9766_codec_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
u16 id, reset;
|
||||
|
||||
reset = 0;
|
||||
|
|
@ -300,10 +294,9 @@ static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
|
|||
.prepare = ac97_digital_prepare,
|
||||
};
|
||||
|
||||
struct snd_soc_dai stac9766_dai[] = {
|
||||
static struct snd_soc_dai_driver stac9766_dai[] = {
|
||||
{
|
||||
.name = "stac9766 analog",
|
||||
.id = 0,
|
||||
.name = "stac9766-hifi-analog",
|
||||
.ac97_control = 1,
|
||||
|
||||
/* stream cababilities */
|
||||
|
|
@ -325,8 +318,7 @@ struct snd_soc_dai stac9766_dai[] = {
|
|||
.ops = &stac9766_dai_ops_analog,
|
||||
},
|
||||
{
|
||||
.name = "stac9766 IEC958",
|
||||
.id = 1,
|
||||
.name = "stac9766-hifi-IEC958",
|
||||
.ac97_control = 1,
|
||||
|
||||
/* stream cababilities */
|
||||
|
|
@ -342,57 +334,24 @@ struct snd_soc_dai stac9766_dai[] = {
|
|||
.ops = &stac9766_dai_ops_digital,
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(stac9766_dai);
|
||||
|
||||
static int stac9766_codec_probe(struct platform_device *pdev)
|
||||
static int stac9766_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
|
||||
|
||||
socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (socdev->card->codec == NULL)
|
||||
return -ENOMEM;
|
||||
codec = socdev->card->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
|
||||
GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cache_err;
|
||||
}
|
||||
codec->reg_cache_size = sizeof(stac9766_reg);
|
||||
codec->reg_cache_step = 2;
|
||||
|
||||
codec->name = "STAC9766";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = stac9766_dai;
|
||||
codec->num_dai = ARRAY_SIZE(stac9766_dai);
|
||||
codec->write = stac9766_ac97_write;
|
||||
codec->read = stac9766_ac97_read;
|
||||
codec->set_bias_level = stac9766_set_bias_level;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
|
||||
if (ret < 0)
|
||||
goto codec_err;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0)
|
||||
goto pcm_err;
|
||||
|
||||
/* do a cold reset for the controller and then try
|
||||
* a warm reset followed by an optional cold reset for codec */
|
||||
stac9766_reset(codec, 0);
|
||||
ret = stac9766_reset(codec, 1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
|
||||
goto reset_err;
|
||||
goto codec_err;
|
||||
}
|
||||
|
||||
stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
|
@ -402,40 +361,63 @@ static int stac9766_codec_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
reset_err:
|
||||
snd_soc_free_pcms(socdev);
|
||||
pcm_err:
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
codec_err:
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
cache_err:
|
||||
kfree(socdev->card->codec);
|
||||
socdev->card->codec = NULL;
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stac9766_codec_remove(struct platform_device *pdev)
|
||||
static int stac9766_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec == NULL)
|
||||
return 0;
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
kfree(codec->reg_cache);
|
||||
kfree(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_stac9766 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
|
||||
.write = stac9766_ac97_write,
|
||||
.read = stac9766_ac97_read,
|
||||
.set_bias_level = stac9766_set_bias_level,
|
||||
.probe = stac9766_codec_probe,
|
||||
.remove = stac9766_codec_remove,
|
||||
.suspend = stac9766_codec_suspend,
|
||||
.resume = stac9766_codec_resume,
|
||||
.reg_cache_size = sizeof(stac9766_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_step = 2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
|
||||
|
||||
static __devinit int stac9766_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
|
||||
}
|
||||
|
||||
static int __devexit stac9766_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver stac9766_codec_driver = {
|
||||
.driver = {
|
||||
.name = "stac9766-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = stac9766_probe,
|
||||
.remove = __devexit_p(stac9766_remove),
|
||||
};
|
||||
|
||||
static int __init stac9766_init(void)
|
||||
{
|
||||
return platform_driver_register(&stac9766_codec_driver);
|
||||
}
|
||||
module_init(stac9766_init);
|
||||
|
||||
static void __exit stac9766_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&stac9766_codec_driver);
|
||||
}
|
||||
module_exit(stac9766_exit);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC stac9766 driver");
|
||||
MODULE_AUTHOR("Jon Smirl <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -14,8 +14,4 @@
|
|||
#define STAC9766_DAI_AC97_ANALOG 0
|
||||
#define STAC9766_DAI_AC97_DIGITAL 1
|
||||
|
||||
extern struct snd_soc_dai stac9766_dai[];
|
||||
extern struct snd_soc_codec_device soc_codec_dev_stac9766;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -240,7 +240,8 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
|
||||
/* AIC23 driver data */
|
||||
struct aic23 {
|
||||
struct snd_soc_codec codec;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
int mclk;
|
||||
int requested_adc;
|
||||
int requested_dac;
|
||||
|
|
@ -404,11 +405,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
u16 iface_reg;
|
||||
int ret;
|
||||
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
|
||||
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
|
||||
u32 sample_rate_adc = aic23->requested_adc;
|
||||
u32 sample_rate_dac = aic23->requested_dac;
|
||||
u32 sample_rate = params_rate(params);
|
||||
|
|
@ -452,8 +452,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* set active */
|
||||
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
|
||||
|
|
@ -465,9 +464,8 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* deactivate */
|
||||
if (!codec->active) {
|
||||
|
|
@ -546,8 +544,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
|
||||
struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
|
||||
aic23->mclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -594,8 +591,8 @@ static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
|
|||
.set_sysclk = tlv320aic23_set_dai_sysclk,
|
||||
};
|
||||
|
||||
struct snd_soc_dai tlv320aic23_dai = {
|
||||
.name = "tlv320aic23",
|
||||
static struct snd_soc_dai_driver tlv320aic23_dai = {
|
||||
.name = "tlv320aic23-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -610,23 +607,17 @@ struct snd_soc_dai tlv320aic23_dai = {
|
|||
.formats = AIC23_FORMATS,},
|
||||
.ops = &tlv320aic23_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tlv320aic23_dai);
|
||||
|
||||
static int tlv320aic23_suspend(struct platform_device *pdev,
|
||||
static int tlv320aic23_suspend(struct snd_soc_codec *codec,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_resume(struct platform_device *pdev)
|
||||
static int tlv320aic23_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
u16 reg;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
|
|
@ -639,39 +630,19 @@ static int tlv320aic23_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the AIC23 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int tlv320aic23_init(struct snd_soc_device *socdev)
|
||||
static int tlv320aic23_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int ret = 0;
|
||||
u16 reg;
|
||||
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg;
|
||||
|
||||
codec->name = "tlv320aic23";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = tlv320aic23_read_reg_cache;
|
||||
codec->write = tlv320aic23_write;
|
||||
codec->set_bias_level = tlv320aic23_set_bias_level;
|
||||
codec->dai = &tlv320aic23_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
|
||||
codec->reg_cache =
|
||||
kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL)
|
||||
return -ENOMEM;
|
||||
printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
|
||||
codec->control_data = aic23->control_data;
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
codec->hw_read = NULL;
|
||||
|
||||
/* Reset codec */
|
||||
tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
/* power on device */
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
|
|
@ -707,13 +678,27 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
|
|||
ARRAY_SIZE(tlv320aic23_snd_controls));
|
||||
tlv320aic23_add_widgets(codec);
|
||||
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
kfree(codec->reg_cache);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
static struct snd_soc_device *tlv320aic23_socdev;
|
||||
|
||||
static int tlv320aic23_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
|
||||
.reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = tlv320aic23_reg,
|
||||
.probe = tlv320aic23_probe,
|
||||
.remove = tlv320aic23_remove,
|
||||
.suspend = tlv320aic23_suspend,
|
||||
.resume = tlv320aic23_resume,
|
||||
.read = tlv320aic23_read_reg_cache,
|
||||
.write = tlv320aic23_write,
|
||||
.set_bias_level = tlv320aic23_set_bias_level,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
/*
|
||||
|
|
@ -723,31 +708,30 @@ static struct snd_soc_device *tlv320aic23_socdev;
|
|||
static int tlv320aic23_codec_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *i2c_id)
|
||||
{
|
||||
struct snd_soc_device *socdev = tlv320aic23_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct aic23 *aic23;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EINVAL;
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
codec->control_data = i2c;
|
||||
aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
|
||||
if (aic23 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = tlv320aic23_init(socdev);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
|
||||
goto err;
|
||||
}
|
||||
return ret;
|
||||
i2c_set_clientdata(i2c, aic23);
|
||||
aic23->control_data = i2c;
|
||||
aic23->control_type = SND_SOC_I2C;
|
||||
|
||||
err:
|
||||
kfree(codec);
|
||||
kfree(i2c);
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(aic23);
|
||||
return ret;
|
||||
}
|
||||
static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
put_device(&i2c->dev);
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
kfree(i2c_get_clientdata(i2c));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -760,7 +744,7 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
|
|||
|
||||
static struct i2c_driver tlv320aic23_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320aic23",
|
||||
.name = "tlv320aic23-codec",
|
||||
},
|
||||
.probe = tlv320aic23_codec_probe,
|
||||
.remove = __exit_p(tlv320aic23_i2c_remove),
|
||||
|
|
@ -769,71 +753,25 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
|
|||
|
||||
#endif
|
||||
|
||||
static int tlv320aic23_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct aic23 *aic23;
|
||||
int ret = 0;
|
||||
|
||||
printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
|
||||
|
||||
aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
|
||||
if (aic23 == NULL)
|
||||
return -ENOMEM;
|
||||
codec = &aic23->codec;
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
tlv320aic23_socdev = socdev;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
codec->hw_write = (hw_write_t) i2c_master_send;
|
||||
codec->hw_read = NULL;
|
||||
ret = i2c_add_driver(&tlv320aic23_i2c_driver);
|
||||
if (ret != 0)
|
||||
printk(KERN_ERR "can't add i2c driver");
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tlv320aic23_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
|
||||
|
||||
if (codec->control_data)
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&tlv320aic23_i2c_driver);
|
||||
#endif
|
||||
kfree(codec->reg_cache);
|
||||
kfree(aic23);
|
||||
|
||||
return 0;
|
||||
}
|
||||
struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
|
||||
.probe = tlv320aic23_probe,
|
||||
.remove = tlv320aic23_remove,
|
||||
.suspend = tlv320aic23_suspend,
|
||||
.resume = tlv320aic23_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
|
||||
|
||||
static int __init tlv320aic23_modinit(void)
|
||||
{
|
||||
return snd_soc_register_dai(&tlv320aic23_dai);
|
||||
int ret;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&tlv320aic23_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(tlv320aic23_modinit);
|
||||
|
||||
static void __exit tlv320aic23_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&tlv320aic23_dai);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&tlv320aic23_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(tlv320aic23_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,4 @@
|
|||
#define TLV320AIC23_SIDETONE_12 0x080
|
||||
#define TLV320AIC23_SIDETONE_18 0x0c0
|
||||
|
||||
extern struct snd_soc_dai tlv320aic23_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
|
||||
|
||||
#endif /* _TLV320AIC23_H */
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/soc-of-simple.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "tlv320aic26.h"
|
||||
|
|
@ -130,8 +129,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
|
||||
int fsref, divisor, wlen, pval, jval, dval, qval;
|
||||
u16 reg;
|
||||
|
|
@ -278,8 +276,8 @@ static struct snd_soc_dai_ops aic26_dai_ops = {
|
|||
.set_fmt = aic26_set_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai aic26_dai = {
|
||||
.name = "tlv320aic26",
|
||||
static struct snd_soc_dai_driver aic26_dai = {
|
||||
.name = "tlv320aic26-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -296,7 +294,6 @@ struct snd_soc_dai aic26_dai = {
|
|||
},
|
||||
.ops = &aic26_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(aic26_dai);
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* ALSA controls
|
||||
|
|
@ -318,61 +315,6 @@ static const struct snd_kcontrol_new aic26_snd_controls[] = {
|
|||
SOC_ENUM("Capture Source", aic26_capture_src_enum),
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* SoC CODEC portion of driver: probe and release routines
|
||||
*/
|
||||
static int aic26_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct aic26 *aic26;
|
||||
int ret, err;
|
||||
|
||||
dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
|
||||
dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
|
||||
dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
|
||||
|
||||
/* Fetch the relevant aic26 private data here (it's already been
|
||||
* stored in the .codec pointer) */
|
||||
aic26 = socdev->codec_data;
|
||||
if (aic26 == NULL) {
|
||||
dev_err(&pdev->dev, "aic26: missing codec pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
codec = &aic26->codec;
|
||||
socdev->card->codec = codec;
|
||||
|
||||
dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
|
||||
&pdev->dev, socdev->dev);
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "aic26: failed to create pcms\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* register controls */
|
||||
dev_dbg(&pdev->dev, "Registering controls\n");
|
||||
err = snd_soc_add_controls(codec, aic26_snd_controls,
|
||||
ARRAY_SIZE(aic26_snd_controls));
|
||||
WARN_ON(err < 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aic26_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
snd_soc_free_pcms(socdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device aic26_soc_codec_dev = {
|
||||
.probe = aic26_probe,
|
||||
.remove = aic26_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* SPI device portion of driver: sysfs files for debugging
|
||||
*/
|
||||
|
|
@ -408,6 +350,55 @@ static ssize_t aic26_keyclick_set(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* SoC CODEC portion of driver: probe and release routines
|
||||
*/
|
||||
static int aic26_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, err, i, reg;
|
||||
|
||||
dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
|
||||
|
||||
/* Reset the codec to power on defaults */
|
||||
aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
|
||||
|
||||
/* Power up CODEC */
|
||||
aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
|
||||
|
||||
/* Audio Control 3 (master mode, fsref rate) */
|
||||
reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
|
||||
reg &= ~0xf800;
|
||||
reg |= 0x0800; /* set master mode */
|
||||
aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
|
||||
|
||||
/* Fill register cache */
|
||||
for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
|
||||
aic26_reg_read(codec, i);
|
||||
|
||||
/* Register the sysfs files for debugging */
|
||||
/* Create SysFS files */
|
||||
ret = device_create_file(codec->dev, &dev_attr_keyclick);
|
||||
if (ret)
|
||||
dev_info(codec->dev, "error creating sysfs files\n");
|
||||
|
||||
/* register controls */
|
||||
dev_dbg(codec->dev, "Registering controls\n");
|
||||
err = snd_soc_add_controls(codec, aic26_snd_controls,
|
||||
ARRAY_SIZE(aic26_snd_controls));
|
||||
WARN_ON(err < 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver aic26_soc_codec_dev = {
|
||||
.probe = aic26_probe,
|
||||
.read = aic26_reg_read,
|
||||
.write = aic26_reg_write,
|
||||
.reg_cache_size = AIC26_NUM_REGS,
|
||||
.reg_word_size = sizeof(u16),
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* SPI device portion of driver: probe and release routines and SPI
|
||||
* driver registration.
|
||||
|
|
@ -415,7 +406,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
|
|||
static int aic26_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct aic26 *aic26;
|
||||
int ret, i, reg;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
|
||||
|
||||
|
|
@ -427,59 +418,13 @@ static int aic26_spi_probe(struct spi_device *spi)
|
|||
/* Initialize the driver data */
|
||||
aic26->spi = spi;
|
||||
dev_set_drvdata(&spi->dev, aic26);
|
||||
|
||||
/* Setup what we can in the codec structure so that the register
|
||||
* access functions will work as expected. More will be filled
|
||||
* out when it is probed by the SoC CODEC part of this driver */
|
||||
snd_soc_codec_set_drvdata(&aic26->codec, aic26);
|
||||
aic26->codec.name = "aic26";
|
||||
aic26->codec.owner = THIS_MODULE;
|
||||
aic26->codec.dai = &aic26_dai;
|
||||
aic26->codec.num_dai = 1;
|
||||
aic26->codec.read = aic26_reg_read;
|
||||
aic26->codec.write = aic26_reg_write;
|
||||
aic26->master = 1;
|
||||
mutex_init(&aic26->codec.mutex);
|
||||
INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
|
||||
INIT_LIST_HEAD(&aic26->codec.dapm_paths);
|
||||
aic26->codec.reg_cache_size = AIC26_NUM_REGS;
|
||||
aic26->codec.reg_cache = aic26->reg_cache;
|
||||
|
||||
aic26_dai.dev = &spi->dev;
|
||||
ret = snd_soc_register_dai(&aic26_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(&spi->dev, "Failed to register DAI: %d\n", ret);
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&aic26_soc_codec_dev, &aic26_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(aic26);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset the codec to power on defaults */
|
||||
aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
|
||||
|
||||
/* Power up CODEC */
|
||||
aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
|
||||
|
||||
/* Audio Control 3 (master mode, fsref rate) */
|
||||
reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
|
||||
reg &= ~0xf800;
|
||||
reg |= 0x0800; /* set master mode */
|
||||
aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
|
||||
|
||||
/* Fill register cache */
|
||||
for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
|
||||
aic26_reg_read(&aic26->codec, i);
|
||||
|
||||
/* Register the sysfs files for debugging */
|
||||
/* Create SysFS files */
|
||||
ret = device_create_file(&spi->dev, &dev_attr_keyclick);
|
||||
if (ret)
|
||||
dev_info(&spi->dev, "error creating sysfs files\n");
|
||||
|
||||
#if defined(CONFIG_SND_SOC_OF_SIMPLE)
|
||||
/* Tell the of_soc helper about this codec */
|
||||
of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
|
||||
spi->dev.archdata.of_node);
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
dev_dbg(&spi->dev, "SPI device initialized\n");
|
||||
return 0;
|
||||
|
|
@ -487,17 +432,14 @@ static int aic26_spi_probe(struct spi_device *spi)
|
|||
|
||||
static int aic26_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
|
||||
|
||||
snd_soc_unregister_dai(&aic26_dai);
|
||||
kfree(aic26);
|
||||
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
kfree(spi_get_drvdata(spi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver aic26_spi = {
|
||||
.driver = {
|
||||
.name = "tlv320aic26",
|
||||
.name = "tlv320aic26-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = aic26_spi_probe,
|
||||
|
|
|
|||
|
|
@ -90,7 +90,4 @@ enum aic26_wlen {
|
|||
AIC26_WLEN_32 = 3 << 10,
|
||||
};
|
||||
|
||||
extern struct snd_soc_dai aic26_dai;
|
||||
extern struct snd_soc_codec_device aic26_soc_codec_dev;
|
||||
|
||||
#endif /* _TLV320AIC16_H_ */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -81,50 +81,63 @@
|
|||
/* DAC Digital control registers */
|
||||
#define LDAC_VOL 43
|
||||
#define RDAC_VOL 44
|
||||
/* High Power Output control registers */
|
||||
/* Left High Power Output control registers */
|
||||
#define LINE2L_2_HPLOUT_VOL 45
|
||||
#define LINE2R_2_HPROUT_VOL 62
|
||||
#define PGAL_2_HPLOUT_VOL 46
|
||||
#define PGAL_2_HPROUT_VOL 60
|
||||
#define PGAR_2_HPLOUT_VOL 49
|
||||
#define PGAR_2_HPROUT_VOL 63
|
||||
#define DACL1_2_HPLOUT_VOL 47
|
||||
#define DACR1_2_HPROUT_VOL 64
|
||||
#define LINE2R_2_HPLOUT_VOL 48
|
||||
#define PGAR_2_HPLOUT_VOL 49
|
||||
#define DACR1_2_HPLOUT_VOL 50
|
||||
#define HPLOUT_CTRL 51
|
||||
#define HPROUT_CTRL 65
|
||||
/* High Power COM control registers */
|
||||
/* Left High Power COM control registers */
|
||||
#define LINE2L_2_HPLCOM_VOL 52
|
||||
#define LINE2R_2_HPRCOM_VOL 69
|
||||
#define PGAL_2_HPLCOM_VOL 53
|
||||
#define PGAR_2_HPLCOM_VOL 56
|
||||
#define PGAL_2_HPRCOM_VOL 67
|
||||
#define PGAR_2_HPRCOM_VOL 70
|
||||
#define DACL1_2_HPLCOM_VOL 54
|
||||
#define DACR1_2_HPRCOM_VOL 71
|
||||
#define LINE2R_2_HPLCOM_VOL 55
|
||||
#define PGAR_2_HPLCOM_VOL 56
|
||||
#define DACR1_2_HPLCOM_VOL 57
|
||||
#define HPLCOM_CTRL 58
|
||||
/* Right High Power Output control registers */
|
||||
#define LINE2L_2_HPROUT_VOL 59
|
||||
#define PGAL_2_HPROUT_VOL 60
|
||||
#define DACL1_2_HPROUT_VOL 61
|
||||
#define LINE2R_2_HPROUT_VOL 62
|
||||
#define PGAR_2_HPROUT_VOL 63
|
||||
#define DACR1_2_HPROUT_VOL 64
|
||||
#define HPROUT_CTRL 65
|
||||
/* Right High Power COM control registers */
|
||||
#define LINE2L_2_HPRCOM_VOL 66
|
||||
#define PGAL_2_HPRCOM_VOL 67
|
||||
#define DACL1_2_HPRCOM_VOL 68
|
||||
#define LINE2R_2_HPRCOM_VOL 69
|
||||
#define PGAR_2_HPRCOM_VOL 70
|
||||
#define DACR1_2_HPRCOM_VOL 71
|
||||
#define HPRCOM_CTRL 72
|
||||
/* Mono Line Output Plus/Minus control registers */
|
||||
#define LINE2L_2_MONOLOPM_VOL 73
|
||||
#define LINE2R_2_MONOLOPM_VOL 76
|
||||
#define PGAL_2_MONOLOPM_VOL 74
|
||||
#define PGAR_2_MONOLOPM_VOL 77
|
||||
#define DACL1_2_MONOLOPM_VOL 75
|
||||
#define LINE2R_2_MONOLOPM_VOL 76
|
||||
#define PGAR_2_MONOLOPM_VOL 77
|
||||
#define DACR1_2_MONOLOPM_VOL 78
|
||||
#define MONOLOPM_CTRL 79
|
||||
/* Line Output Plus/Minus control registers */
|
||||
/* Class-D speaker driver on tlv320aic3007 */
|
||||
#define CLASSD_CTRL 73
|
||||
/* Left Line Output Plus/Minus control registers */
|
||||
#define LINE2L_2_LLOPM_VOL 80
|
||||
#define LINE2L_2_RLOPM_VOL 87
|
||||
#define LINE2R_2_LLOPM_VOL 83
|
||||
#define LINE2R_2_RLOPM_VOL 90
|
||||
#define PGAL_2_LLOPM_VOL 81
|
||||
#define PGAL_2_RLOPM_VOL 88
|
||||
#define PGAR_2_LLOPM_VOL 84
|
||||
#define PGAR_2_RLOPM_VOL 91
|
||||
#define DACL1_2_LLOPM_VOL 82
|
||||
#define DACL1_2_RLOPM_VOL 89
|
||||
#define DACR1_2_RLOPM_VOL 92
|
||||
#define LINE2R_2_LLOPM_VOL 83
|
||||
#define PGAR_2_LLOPM_VOL 84
|
||||
#define DACR1_2_LLOPM_VOL 85
|
||||
#define LLOPM_CTRL 86
|
||||
/* Right Line Output Plus/Minus control registers */
|
||||
#define LINE2L_2_RLOPM_VOL 87
|
||||
#define PGAL_2_RLOPM_VOL 88
|
||||
#define DACL1_2_RLOPM_VOL 89
|
||||
#define LINE2R_2_RLOPM_VOL 90
|
||||
#define PGAR_2_RLOPM_VOL 91
|
||||
#define DACR1_2_RLOPM_VOL 92
|
||||
#define RLOPM_CTRL 93
|
||||
/* GPIO/IRQ registers */
|
||||
#define AIC3X_STICKY_IRQ_FLAGS_REG 96
|
||||
|
|
@ -199,42 +212,6 @@
|
|||
/* Default input volume */
|
||||
#define DEFAULT_GAIN 0x20
|
||||
|
||||
/* GPIO API */
|
||||
enum {
|
||||
AIC3X_GPIO1_FUNC_DISABLED = 0,
|
||||
AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
|
||||
AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
|
||||
AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
|
||||
AIC3X_GPIO1_FUNC_INPUT = 8,
|
||||
AIC3X_GPIO1_FUNC_OUTPUT = 9,
|
||||
AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
|
||||
AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
|
||||
AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
|
||||
AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
|
||||
AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
|
||||
AIC3X_GPIO1_FUNC_ALL_IRQ = 16
|
||||
};
|
||||
|
||||
enum {
|
||||
AIC3X_GPIO2_FUNC_DISABLED = 0,
|
||||
AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
|
||||
AIC3X_GPIO2_FUNC_INPUT = 3,
|
||||
AIC3X_GPIO2_FUNC_OUTPUT = 4,
|
||||
AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
|
||||
AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
|
||||
AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
|
||||
AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
|
||||
AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
|
||||
AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
|
||||
AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
|
||||
AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
|
||||
AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
|
||||
};
|
||||
|
||||
void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
|
||||
int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
|
||||
|
||||
|
|
@ -281,11 +258,4 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
|
|||
int aic3x_headset_detected(struct snd_soc_codec *codec);
|
||||
int aic3x_button_pressed(struct snd_soc_codec *codec);
|
||||
|
||||
struct aic3x_setup_data {
|
||||
unsigned int gpio_func[2];
|
||||
};
|
||||
|
||||
extern struct snd_soc_dai aic3x_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_aic3x;
|
||||
|
||||
#endif /* _AIC3X_H */
|
||||
|
|
|
|||
|
|
@ -66,8 +66,6 @@
|
|||
static void dac33_calculate_times(struct snd_pcm_substream *substream);
|
||||
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
|
||||
|
||||
static struct snd_soc_codec *tlv320dac33_codec;
|
||||
|
||||
enum dac33_state {
|
||||
DAC33_IDLE = 0,
|
||||
DAC33_PREFILL,
|
||||
|
|
@ -93,7 +91,7 @@ struct tlv320dac33_priv {
|
|||
struct mutex mutex;
|
||||
struct workqueue_struct *dac33_wq;
|
||||
struct work_struct work;
|
||||
struct snd_soc_codec codec;
|
||||
struct snd_soc_codec *codec;
|
||||
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
|
||||
struct snd_pcm_substream *substream;
|
||||
int power_gpio;
|
||||
|
|
@ -128,6 +126,8 @@ struct tlv320dac33_priv {
|
|||
unsigned int uthr;
|
||||
|
||||
enum dac33_state state;
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
|
||||
|
|
@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
|
|||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
|
||||
dac33_fifo_mode_texts);
|
||||
|
||||
/* L/R Line Output Gain */
|
||||
static const char *lr_lineout_gain_texts[] = {
|
||||
"Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
|
||||
"Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
|
||||
};
|
||||
|
||||
static const struct soc_enum l_lineout_gain_enum =
|
||||
SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
|
||||
ARRAY_SIZE(lr_lineout_gain_texts),
|
||||
lr_lineout_gain_texts);
|
||||
|
||||
static const struct soc_enum r_lineout_gain_enum =
|
||||
SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
|
||||
ARRAY_SIZE(lr_lineout_gain_texts),
|
||||
lr_lineout_gain_texts);
|
||||
|
||||
/*
|
||||
* DACL/R digital volume control:
|
||||
* from 0 dB to -63.5 in 0.5 dB steps
|
||||
|
|
@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
|
|||
DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
|
||||
SOC_DOUBLE_R("Line to Line Out Volume",
|
||||
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
|
||||
SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
|
||||
SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
|
||||
|
|
@ -650,9 +668,8 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
|
|||
|
||||
static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
|
||||
codec = &dac33->codec;
|
||||
struct snd_soc_codec *codec = dac33->codec;
|
||||
unsigned int delay;
|
||||
|
||||
switch (dac33->fifo_mode) {
|
||||
case DAC33_FIFO_MODE1:
|
||||
|
|
@ -668,8 +685,9 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
|
|||
dac33_write16(codec, DAC33_PREFILL_MSB,
|
||||
DAC33_THRREG(dac33->alarm_threshold));
|
||||
/* Enable Alarm Threshold IRQ with a delay */
|
||||
udelay(SAMPLES_TO_US(dac33->burst_rate,
|
||||
dac33->alarm_threshold));
|
||||
delay = SAMPLES_TO_US(dac33->burst_rate,
|
||||
dac33->alarm_threshold) + 1000;
|
||||
usleep_range(delay, delay + 500);
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
|
||||
break;
|
||||
case DAC33_FIFO_MODE7:
|
||||
|
|
@ -695,9 +713,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
|
|||
|
||||
static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
|
||||
codec = &dac33->codec;
|
||||
struct snd_soc_codec *codec = dac33->codec;
|
||||
|
||||
switch (dac33->fifo_mode) {
|
||||
case DAC33_FIFO_MODE1:
|
||||
|
|
@ -726,7 +742,7 @@ static void dac33_work(struct work_struct *work)
|
|||
u8 reg;
|
||||
|
||||
dac33 = container_of(work, struct tlv320dac33_priv, work);
|
||||
codec = &dac33->codec;
|
||||
codec = dac33->codec;
|
||||
|
||||
mutex_lock(&dac33->mutex);
|
||||
switch (dac33->state) {
|
||||
|
|
@ -771,11 +787,11 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
|
|||
|
||||
static void dac33_oscwait(struct snd_soc_codec *codec)
|
||||
{
|
||||
int timeout = 20;
|
||||
int timeout = 60;
|
||||
u8 reg;
|
||||
|
||||
do {
|
||||
msleep(1);
|
||||
usleep_range(1000, 2000);
|
||||
dac33_read(codec, DAC33_INT_OSC_STATUS, ®);
|
||||
} while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
|
||||
if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
|
||||
|
|
@ -787,8 +803,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Stream started, save the substream pointer */
|
||||
|
|
@ -801,8 +816,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dac33->substream = NULL;
|
||||
|
|
@ -817,8 +831,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* Check parameters for validity */
|
||||
switch (params_rate(params)) {
|
||||
|
|
@ -856,8 +869,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
|
|||
static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
|
||||
u8 aictrl_a, aictrl_b, fifoctrl_a;
|
||||
|
|
@ -1049,8 +1061,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
|||
static void dac33_calculate_times(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int period_size = substream->runtime->period_size;
|
||||
unsigned int rate = substream->runtime->rate;
|
||||
|
|
@ -1129,8 +1140,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -1163,8 +1173,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned long long t0, t1, t_now;
|
||||
unsigned int time_delta, uthr;
|
||||
|
|
@ -1389,24 +1398,46 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_soc_probe(struct platform_device *pdev)
|
||||
static int dac33_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct tlv320dac33_priv *dac33;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!tlv320dac33_codec);
|
||||
codec->control_data = dac33->control_data;
|
||||
codec->hw_write = (hw_write_t) i2c_master_send;
|
||||
codec->idle_bias_off = 1;
|
||||
dac33->codec = codec;
|
||||
|
||||
codec = tlv320dac33_codec;
|
||||
socdev->card->codec = codec;
|
||||
dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
/* Read the tlv320dac33 ID registers */
|
||||
ret = dac33_hard_power(codec, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
|
||||
goto err_power;
|
||||
}
|
||||
dac33_read_id(codec);
|
||||
dac33_hard_power(codec, 0);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
/* Check if the IRQ number is valid and request it */
|
||||
if (dac33->irq >= 0) {
|
||||
ret = request_irq(dac33->irq, dac33_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_DISABLED,
|
||||
codec->name, codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
|
||||
dac33->irq, ret);
|
||||
dac33->irq = -1;
|
||||
}
|
||||
if (dac33->irq != -1) {
|
||||
/* Setup work queue */
|
||||
dac33->dac33_wq =
|
||||
create_singlethread_workqueue("tlv320dac33");
|
||||
if (dac33->dac33_wq == NULL) {
|
||||
free_irq(dac33->irq, codec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_WORK(&dac33->work, dac33_work);
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, dac33_snd_controls,
|
||||
|
|
@ -1420,56 +1451,51 @@ static int dac33_soc_probe(struct platform_device *pdev)
|
|||
snd_soc_add_controls(codec, dac33_fifo_snd_controls,
|
||||
ARRAY_SIZE(dac33_fifo_snd_controls));
|
||||
}
|
||||
|
||||
dac33_add_widgets(codec);
|
||||
|
||||
return 0;
|
||||
|
||||
pcm_err:
|
||||
dac33_hard_power(codec, 0);
|
||||
err_power:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dac33_soc_remove(struct platform_device *pdev)
|
||||
static int dac33_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
if (dac33->irq >= 0) {
|
||||
free_irq(dac33->irq, dac33->codec);
|
||||
destroy_workqueue(dac33->dac33_wq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_soc_resume(struct platform_device *pdev)
|
||||
static int dac33_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
|
||||
.read = dac33_read_reg_cache,
|
||||
.write = dac33_write_locked,
|
||||
.set_bias_level = dac33_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(dac33_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = dac33_reg,
|
||||
.probe = dac33_soc_probe,
|
||||
.remove = dac33_soc_remove,
|
||||
.suspend = dac33_soc_suspend,
|
||||
.resume = dac33_soc_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
|
||||
|
||||
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \
|
||||
SNDRV_PCM_RATE_48000)
|
||||
|
|
@ -1485,8 +1511,8 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
|
|||
.set_fmt = dac33_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai dac33_dai = {
|
||||
.name = "tlv320dac33",
|
||||
static struct snd_soc_dai_driver dac33_dai = {
|
||||
.name = "tlv320dac33-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -1495,14 +1521,12 @@ struct snd_soc_dai dac33_dai = {
|
|||
.formats = DAC33_FORMATS,},
|
||||
.ops = &dac33_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(dac33_dai);
|
||||
|
||||
static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tlv320dac33_platform_data *pdata;
|
||||
struct tlv320dac33_priv *dac33;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret, i;
|
||||
|
||||
if (client->dev.platform_data == NULL) {
|
||||
|
|
@ -1515,33 +1539,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
if (dac33 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &dac33->codec;
|
||||
snd_soc_codec_set_drvdata(codec, dac33);
|
||||
codec->control_data = client;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
dac33->control_data = client;
|
||||
mutex_init(&dac33->mutex);
|
||||
spin_lock_init(&dac33->lock);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->name = "tlv320dac33";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = dac33_read_reg_cache;
|
||||
codec->write = dac33_write_locked;
|
||||
codec->hw_write = (hw_write_t) i2c_master_send;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = dac33_set_bias_level;
|
||||
codec->idle_bias_off = 1;
|
||||
codec->dai = &dac33_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
|
||||
codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
|
||||
GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_reg;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, dac33);
|
||||
|
||||
|
|
@ -1561,125 +1561,59 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
/* Disable FIFO use by default */
|
||||
dac33->fifo_mode = DAC33_FIFO_BYPASS;
|
||||
|
||||
tlv320dac33_codec = codec;
|
||||
|
||||
codec->dev = &client->dev;
|
||||
dac33_dai.dev = codec->dev;
|
||||
|
||||
/* Check if the reset GPIO number is valid and request it */
|
||||
if (dac33->power_gpio >= 0) {
|
||||
ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev,
|
||||
dev_err(&client->dev,
|
||||
"Failed to request reset GPIO (%d)\n",
|
||||
dac33->power_gpio);
|
||||
snd_soc_unregister_dai(&dac33_dai);
|
||||
snd_soc_unregister_codec(codec);
|
||||
goto error_gpio;
|
||||
goto err_gpio;
|
||||
}
|
||||
gpio_direction_output(dac33->power_gpio, 0);
|
||||
}
|
||||
|
||||
/* Check if the IRQ number is valid and request it */
|
||||
if (dac33->irq >= 0) {
|
||||
ret = request_irq(dac33->irq, dac33_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_DISABLED,
|
||||
codec->name, codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
|
||||
dac33->irq, ret);
|
||||
dac33->irq = -1;
|
||||
}
|
||||
if (dac33->irq != -1) {
|
||||
/* Setup work queue */
|
||||
dac33->dac33_wq =
|
||||
create_singlethread_workqueue("tlv320dac33");
|
||||
if (dac33->dac33_wq == NULL) {
|
||||
free_irq(dac33->irq, &dac33->codec);
|
||||
ret = -ENOMEM;
|
||||
goto error_wq;
|
||||
}
|
||||
|
||||
INIT_WORK(&dac33->work, dac33_work);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
|
||||
dac33->supplies[i].supply = dac33_supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
|
||||
ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
|
||||
dac33->supplies);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
|
||||
dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
|
||||
goto err_get;
|
||||
}
|
||||
|
||||
/* Read the tlv320dac33 ID registers */
|
||||
ret = dac33_hard_power(codec, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
|
||||
goto error_codec;
|
||||
}
|
||||
dac33_read_id(codec);
|
||||
dac33_hard_power(codec, 0);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto error_codec;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&dac33_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
goto error_codec;
|
||||
}
|
||||
ret = snd_soc_register_codec(&client->dev,
|
||||
&soc_codec_dev_tlv320dac33, &dac33_dai, 1);
|
||||
if (ret < 0)
|
||||
goto err_register;
|
||||
|
||||
return ret;
|
||||
|
||||
error_codec:
|
||||
err_register:
|
||||
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
|
||||
err_get:
|
||||
if (dac33->irq >= 0) {
|
||||
free_irq(dac33->irq, &dac33->codec);
|
||||
destroy_workqueue(dac33->dac33_wq);
|
||||
}
|
||||
error_wq:
|
||||
if (dac33->power_gpio >= 0)
|
||||
gpio_free(dac33->power_gpio);
|
||||
error_gpio:
|
||||
kfree(codec->reg_cache);
|
||||
error_reg:
|
||||
tlv320dac33_codec = NULL;
|
||||
err_gpio:
|
||||
kfree(dac33);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dac33_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33;
|
||||
|
||||
dac33 = i2c_get_clientdata(client);
|
||||
struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
|
||||
|
||||
if (unlikely(dac33->chip_power))
|
||||
dac33_hard_power(&dac33->codec, 0);
|
||||
dac33_hard_power(dac33->codec, 0);
|
||||
|
||||
if (dac33->power_gpio >= 0)
|
||||
gpio_free(dac33->power_gpio);
|
||||
if (dac33->irq >= 0)
|
||||
free_irq(dac33->irq, &dac33->codec);
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
|
||||
|
||||
destroy_workqueue(dac33->dac33_wq);
|
||||
snd_soc_unregister_dai(&dac33_dai);
|
||||
snd_soc_unregister_codec(&dac33->codec);
|
||||
kfree(dac33->codec.reg_cache);
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(dac33);
|
||||
tlv320dac33_codec = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1694,7 +1628,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = {
|
|||
|
||||
static struct i2c_driver tlv320dac33_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320dac33",
|
||||
.name = "tlv320dac33-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = dac33_i2c_probe,
|
||||
|
|
|
|||
|
|
@ -261,7 +261,4 @@
|
|||
#define TLV320DAC33_MCLK 0
|
||||
#define TLV320DAC33_SLEEPCLK 1
|
||||
|
||||
extern struct snd_soc_dai dac33_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33;
|
||||
|
||||
#endif /* __TLV320DAC33_H */
|
||||
|
|
|
|||
|
|
@ -98,16 +98,21 @@ static u8 tpa6130a2_read(int reg)
|
|||
return data->regs[reg];
|
||||
}
|
||||
|
||||
static void tpa6130a2_initialize(void)
|
||||
static int tpa6130a2_initialize(void)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
BUG_ON(tpa6130a2_client == NULL);
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
for (i = 1; i < TPA6130A2_REG_VERSION; i++)
|
||||
tpa6130a2_i2c_write(i, data->regs[i]);
|
||||
for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
|
||||
ret = tpa6130a2_i2c_write(i, data->regs[i]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpa6130a2_power(int power)
|
||||
|
|
@ -133,7 +138,16 @@ static int tpa6130a2_power(int power)
|
|||
}
|
||||
|
||||
data->power_state = 1;
|
||||
tpa6130a2_initialize();
|
||||
ret = tpa6130a2_initialize();
|
||||
if (ret < 0) {
|
||||
dev_err(&tpa6130a2_client->dev,
|
||||
"Failed to initialize chip\n");
|
||||
if (data->power_gpio >= 0)
|
||||
gpio_set_value(data->power_gpio, 0);
|
||||
regulator_disable(data->supply);
|
||||
data->power_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Clear SWS */
|
||||
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
|
||||
|
|
@ -375,7 +389,9 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct tpa6130a2_data *data;
|
||||
|
||||
BUG_ON(tpa6130a2_client == NULL);
|
||||
if (tpa6130a2_client == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,16 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "twl4030.h"
|
||||
/* Register descriptions are here */
|
||||
#include <linux/mfd/twl4030-codec.h>
|
||||
|
||||
/* Shadow register used by the audio driver */
|
||||
#define TWL4030_REG_SW_SHADOW 0x4A
|
||||
#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
|
||||
|
||||
/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
|
||||
#define TWL4030_HFL_EN 0x01
|
||||
#define TWL4030_HFR_EN 0x02
|
||||
|
||||
/*
|
||||
* twl4030 register cache & default register settings
|
||||
|
|
@ -277,21 +286,19 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
|
|||
|
||||
}
|
||||
|
||||
static void twl4030_init_chip(struct platform_device *pdev)
|
||||
static void twl4030_init_chip(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct twl4030_setup_data *setup = socdev->codec_data;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 reg, byte;
|
||||
int i = 0;
|
||||
|
||||
/* Check defaults, if instructed before anything else */
|
||||
if (setup && setup->check_defaults)
|
||||
if (pdata && pdata->check_defaults)
|
||||
twl4030_check_defaults(codec);
|
||||
|
||||
/* Reset registers, if no setup data or if instructed to do so */
|
||||
if (!setup || (setup && setup->reset_registers))
|
||||
if (!pdata || (pdata && pdata->reset_registers))
|
||||
twl4030_reset_registers(codec);
|
||||
|
||||
/* Refresh APLL_CTL register from HW */
|
||||
|
|
@ -312,20 +319,14 @@ static void twl4030_init_chip(struct platform_device *pdev)
|
|||
twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
|
||||
|
||||
/* Machine dependent setup */
|
||||
if (!setup)
|
||||
if (!pdata)
|
||||
return;
|
||||
|
||||
twl4030->digimic_delay = setup->digimic_delay;
|
||||
|
||||
/* Configuration for headset ramp delay from setup data */
|
||||
if (setup->sysclk != twl4030->sysclk)
|
||||
dev_warn(codec->dev,
|
||||
"Mismatch in APLL mclk: %u (configured: %u)\n",
|
||||
setup->sysclk, twl4030->sysclk);
|
||||
twl4030->digimic_delay = pdata->digimic_delay;
|
||||
|
||||
reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
|
||||
reg &= ~TWL4030_RAMP_DELAY;
|
||||
reg |= (setup->ramp_delay_value << 2);
|
||||
reg |= (pdata->ramp_delay_value << 2);
|
||||
twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
|
||||
|
||||
/* initiate offset cancellation */
|
||||
|
|
@ -333,7 +334,7 @@ static void twl4030_init_chip(struct platform_device *pdev)
|
|||
|
||||
reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
|
||||
reg &= ~TWL4030_OFFSET_CNCL_SEL;
|
||||
reg |= setup->offset_cncl_path;
|
||||
reg |= pdata->offset_cncl_path;
|
||||
twl4030_write(codec, TWL4030_REG_ANAMICL,
|
||||
reg | TWL4030_CNCL_OFFSET_START);
|
||||
|
||||
|
|
@ -718,9 +719,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
|
|||
|
||||
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
||||
{
|
||||
struct snd_soc_device *socdev = codec->socdev;
|
||||
struct twl4030_setup_data *setup = socdev->codec_data;
|
||||
|
||||
struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
|
||||
unsigned char hs_gain, hs_pop;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
/* Base values for ramp delay calculation: 2^19 - 2^26 */
|
||||
|
|
@ -732,9 +731,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
|||
|
||||
/* Enable external mute control, this dramatically reduces
|
||||
* the pop-noise */
|
||||
if (setup && setup->hs_extmute) {
|
||||
if (setup->set_hs_extmute) {
|
||||
setup->set_hs_extmute(1);
|
||||
if (pdata && pdata->hs_extmute) {
|
||||
if (pdata->set_hs_extmute) {
|
||||
pdata->set_hs_extmute(1);
|
||||
} else {
|
||||
hs_pop |= TWL4030_EXTMUTE;
|
||||
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
|
||||
|
|
@ -772,9 +771,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
|||
}
|
||||
|
||||
/* Disable external mute */
|
||||
if (setup && setup->hs_extmute) {
|
||||
if (setup->set_hs_extmute) {
|
||||
setup->set_hs_extmute(0);
|
||||
if (pdata && pdata->hs_extmute) {
|
||||
if (pdata->set_hs_extmute) {
|
||||
pdata->set_hs_extmute(0);
|
||||
} else {
|
||||
hs_pop &= ~TWL4030_EXTMUTE;
|
||||
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
|
||||
|
|
@ -1707,8 +1706,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (twl4030->master_substream) {
|
||||
|
|
@ -1738,8 +1736,7 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (twl4030->master_substream == substream)
|
||||
|
|
@ -1764,8 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode, old_mode, format, old_format;
|
||||
|
||||
|
|
@ -1999,8 +1995,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode;
|
||||
|
||||
|
|
@ -2033,8 +2028,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* Enable voice digital filters */
|
||||
twl4030_voice_enable(codec, substream->stream, 0);
|
||||
|
|
@ -2044,8 +2038,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 old_mode, mode;
|
||||
|
||||
|
|
@ -2175,7 +2168,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
|
|||
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
|
||||
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
|
||||
|
||||
static struct snd_soc_dai_ops twl4030_dai_ops = {
|
||||
static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
|
||||
.startup = twl4030_startup,
|
||||
.shutdown = twl4030_shutdown,
|
||||
.hw_params = twl4030_hw_params,
|
||||
|
|
@ -2193,9 +2186,9 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
|
|||
.set_tristate = twl4030_voice_set_tristate,
|
||||
};
|
||||
|
||||
struct snd_soc_dai twl4030_dai[] = {
|
||||
static struct snd_soc_dai_driver twl4030_dai[] = {
|
||||
{
|
||||
.name = "twl4030",
|
||||
.name = "twl4030-hifi",
|
||||
.playback = {
|
||||
.stream_name = "HiFi Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -2208,10 +2201,10 @@ struct snd_soc_dai twl4030_dai[] = {
|
|||
.channels_max = 4,
|
||||
.rates = TWL4030_RATES,
|
||||
.formats = TWL4030_FORMATS,},
|
||||
.ops = &twl4030_dai_ops,
|
||||
.ops = &twl4030_dai_hifi_ops,
|
||||
},
|
||||
{
|
||||
.name = "twl4030 Voice",
|
||||
.name = "twl4030-voice",
|
||||
.playback = {
|
||||
.stream_name = "Voice Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -2227,164 +2220,91 @@ struct snd_soc_dai twl4030_dai[] = {
|
|||
.ops = &twl4030_dai_voice_ops,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(twl4030_dai);
|
||||
|
||||
static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl4030_soc_resume(struct platform_device *pdev)
|
||||
static int twl4030_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec *twl4030_codec;
|
||||
|
||||
static int twl4030_soc_probe(struct platform_device *pdev)
|
||||
static int twl4030_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
struct twl4030_priv *twl4030;
|
||||
|
||||
BUG_ON(!twl4030_codec);
|
||||
|
||||
codec = twl4030_codec;
|
||||
socdev->card->codec = codec;
|
||||
|
||||
twl4030_init_chip(pdev);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create pcms\n");
|
||||
return ret;
|
||||
twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
|
||||
if (twl4030 == NULL) {
|
||||
printk("Can not allocate memroy\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
snd_soc_codec_set_drvdata(codec, twl4030);
|
||||
/* Set the defaults, and power up the codec */
|
||||
twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
|
||||
codec->idle_bias_off = 1;
|
||||
|
||||
twl4030_init_chip(codec);
|
||||
|
||||
snd_soc_add_controls(codec, twl4030_snd_controls,
|
||||
ARRAY_SIZE(twl4030_snd_controls));
|
||||
twl4030_add_widgets(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl4030_soc_remove(struct platform_device *pdev)
|
||||
static int twl4030_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
/* Reset registers to their chip default before leaving */
|
||||
twl4030_reset_registers(codec);
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
|
||||
.probe = twl4030_soc_probe,
|
||||
.remove = twl4030_soc_remove,
|
||||
.suspend = twl4030_soc_suspend,
|
||||
.resume = twl4030_soc_resume,
|
||||
.read = twl4030_read_reg_cache,
|
||||
.write = twl4030_write,
|
||||
.set_bias_level = twl4030_set_bias_level,
|
||||
.reg_cache_size = sizeof(twl4030_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = twl4030_reg,
|
||||
};
|
||||
|
||||
static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
|
||||
struct snd_soc_codec *codec;
|
||||
struct twl4030_priv *twl4030;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "platform_data is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
|
||||
if (twl4030 == NULL) {
|
||||
dev_err(&pdev->dev, "Can not allocate memroy\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec = &twl4030->codec;
|
||||
snd_soc_codec_set_drvdata(codec, twl4030);
|
||||
codec->dev = &pdev->dev;
|
||||
twl4030_dai[0].dev = &pdev->dev;
|
||||
twl4030_dai[1].dev = &pdev->dev;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->name = "twl4030";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = twl4030_read_reg_cache;
|
||||
codec->write = twl4030_write;
|
||||
codec->set_bias_level = twl4030_set_bias_level;
|
||||
codec->idle_bias_off = 1;
|
||||
codec->dai = twl4030_dai;
|
||||
codec->num_dai = ARRAY_SIZE(twl4030_dai);
|
||||
codec->reg_cache_size = sizeof(twl4030_reg);
|
||||
codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
|
||||
GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_cache;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, twl4030);
|
||||
twl4030_codec = codec;
|
||||
|
||||
/* Set the defaults, and power up the codec */
|
||||
twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto error_codec;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
goto error_codec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_codec:
|
||||
twl4030_codec_enable(codec, 0);
|
||||
kfree(codec->reg_cache);
|
||||
error_cache:
|
||||
kfree(twl4030);
|
||||
return ret;
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
|
||||
twl4030_dai, ARRAY_SIZE(twl4030_dai));
|
||||
}
|
||||
|
||||
static int __devexit twl4030_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
|
||||
struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
|
||||
snd_soc_unregister_codec(&twl4030->codec);
|
||||
kfree(twl4030->codec.reg_cache);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
kfree(twl4030);
|
||||
|
||||
twl4030_codec = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:twl4030_codec_audio");
|
||||
MODULE_ALIAS("platform:twl4030-codec");
|
||||
|
||||
static struct platform_driver twl4030_codec_driver = {
|
||||
.probe = twl4030_codec_probe,
|
||||
.remove = __devexit_p(twl4030_codec_remove),
|
||||
.driver = {
|
||||
.name = "twl4030_codec_audio",
|
||||
.name = "twl4030-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
|
@ -2401,14 +2321,6 @@ static void __exit twl4030_exit(void)
|
|||
}
|
||||
module_exit(twl4030_exit);
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_twl4030 = {
|
||||
.probe = twl4030_soc_probe,
|
||||
.remove = twl4030_soc_remove,
|
||||
.suspend = twl4030_soc_suspend,
|
||||
.resume = twl4030_soc_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
|
||||
MODULE_AUTHOR("Steve Sakoman");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* ALSA SoC TWL4030 codec driver
|
||||
*
|
||||
* Author: Steve Sakoman <steve@sakoman.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.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TWL4030_AUDIO_H__
|
||||
#define __TWL4030_AUDIO_H__
|
||||
|
||||
/* Register descriptions are here */
|
||||
#include <linux/mfd/twl4030-codec.h>
|
||||
|
||||
/* Shadow register used by the audio driver */
|
||||
#define TWL4030_REG_SW_SHADOW 0x4A
|
||||
#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
|
||||
|
||||
/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
|
||||
#define TWL4030_HFL_EN 0x01
|
||||
#define TWL4030_HFR_EN 0x02
|
||||
|
||||
#define TWL4030_DAI_HIFI 0
|
||||
#define TWL4030_DAI_VOICE 1
|
||||
|
||||
extern struct snd_soc_dai twl4030_dai[2];
|
||||
extern struct snd_soc_codec_device soc_codec_dev_twl4030;
|
||||
|
||||
struct twl4030_setup_data {
|
||||
unsigned int ramp_delay_value;
|
||||
unsigned int digimic_delay; /* in ms */
|
||||
unsigned int sysclk;
|
||||
unsigned int offset_cncl_path;
|
||||
unsigned int check_defaults:1;
|
||||
unsigned int reset_registers:1;
|
||||
unsigned int hs_extmute:1;
|
||||
void (*set_hs_extmute)(int mute);
|
||||
};
|
||||
|
||||
#endif /* End of __TWL4030_AUDIO_H__ */
|
||||
|
||||
|
||||
|
|
@ -45,7 +45,6 @@
|
|||
|
||||
/* codec private data */
|
||||
struct twl6040_data {
|
||||
struct snd_soc_codec codec;
|
||||
int audpwron;
|
||||
int naudint;
|
||||
int codec_powered;
|
||||
|
|
@ -770,8 +769,7 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!priv->sysclk) {
|
||||
|
|
@ -803,8 +801,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
u8 lppllctl;
|
||||
int rate;
|
||||
|
|
@ -839,8 +836,7 @@ static int twl6040_trigger(struct snd_pcm_substream *substream,
|
|||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (cmd) {
|
||||
|
|
@ -978,8 +974,8 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
|
|||
.set_sysclk = twl6040_set_dai_sysclk,
|
||||
};
|
||||
|
||||
struct snd_soc_dai twl6040_dai = {
|
||||
.name = "twl6040",
|
||||
static struct snd_soc_dai_driver twl6040_dai = {
|
||||
.name = "twl6040-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -996,24 +992,17 @@ struct snd_soc_dai twl6040_dai = {
|
|||
},
|
||||
.ops = &twl6040_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(twl6040_dai);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int twl6040_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6040_resume(struct platform_device *pdev)
|
||||
static int twl6040_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1023,68 +1012,9 @@ static int twl6040_resume(struct platform_device *pdev)
|
|||
#define twl6040_resume NULL
|
||||
#endif
|
||||
|
||||
static struct snd_soc_codec *twl6040_codec;
|
||||
|
||||
static int twl6040_probe(struct platform_device *pdev)
|
||||
static int twl6040_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!twl6040_codec);
|
||||
|
||||
codec = twl6040_codec;
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create pcms\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, twl6040_snd_controls,
|
||||
ARRAY_SIZE(twl6040_snd_controls));
|
||||
twl6040_add_widgets(codec);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register card\n");
|
||||
goto card_err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
card_err:
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int twl6040_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_twl6040 = {
|
||||
.probe = twl6040_probe,
|
||||
.remove = twl6040_remove,
|
||||
.suspend = twl6040_suspend,
|
||||
.resume = twl6040_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_twl6040);
|
||||
|
||||
static int __devinit twl6040_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec_data *twl_codec = pdev->dev.platform_data;
|
||||
struct snd_soc_codec *codec;
|
||||
struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
|
||||
struct twl6040_data *priv;
|
||||
int audpwron, naudint;
|
||||
int ret = 0;
|
||||
|
|
@ -1092,6 +1022,7 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
|
|||
priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
|
||||
if (twl_codec) {
|
||||
audpwron = twl_codec->audpwron_gpio;
|
||||
|
|
@ -1104,29 +1035,6 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
|
|||
priv->audpwron = audpwron;
|
||||
priv->naudint = naudint;
|
||||
|
||||
codec = &priv->codec;
|
||||
codec->dev = &pdev->dev;
|
||||
twl6040_dai.dev = &pdev->dev;
|
||||
|
||||
codec->name = "twl6040";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = twl6040_read_reg_cache;
|
||||
codec->write = twl6040_write;
|
||||
codec->set_bias_level = twl6040_set_bias_level;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
codec->dai = &twl6040_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(twl6040_reg);
|
||||
codec->reg_cache = kmemdup(twl6040_reg, sizeof(twl6040_reg),
|
||||
GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cache_err;
|
||||
}
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
init_completion(&priv->ready);
|
||||
|
||||
if (gpio_is_valid(audpwron)) {
|
||||
|
|
@ -1169,23 +1077,12 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto irq_err;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
twl6040_codec = codec;
|
||||
|
||||
ret = snd_soc_register_dai(&twl6040_dai);
|
||||
if (ret)
|
||||
goto dai_err;
|
||||
snd_soc_add_controls(codec, twl6040_snd_controls,
|
||||
ARRAY_SIZE(twl6040_snd_controls));
|
||||
twl6040_add_widgets(codec);
|
||||
|
||||
return 0;
|
||||
|
||||
dai_err:
|
||||
snd_soc_unregister_codec(codec);
|
||||
twl6040_codec = NULL;
|
||||
reg_err:
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
irq_err:
|
||||
if (naudint)
|
||||
free_irq(naudint, codec);
|
||||
|
|
@ -1193,36 +1090,57 @@ gpio2_err:
|
|||
if (gpio_is_valid(audpwron))
|
||||
gpio_free(audpwron);
|
||||
gpio1_err:
|
||||
kfree(codec->reg_cache);
|
||||
cache_err:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit twl6040_codec_remove(struct platform_device *pdev)
|
||||
static int twl6040_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(twl6040_codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int audpwron = priv->audpwron;
|
||||
int naudint = priv->naudint;
|
||||
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
if (gpio_is_valid(audpwron))
|
||||
gpio_free(audpwron);
|
||||
|
||||
if (naudint)
|
||||
free_irq(naudint, twl6040_codec);
|
||||
free_irq(naudint, codec);
|
||||
|
||||
snd_soc_unregister_dai(&twl6040_dai);
|
||||
snd_soc_unregister_codec(twl6040_codec);
|
||||
kfree(priv);
|
||||
|
||||
kfree(twl6040_codec);
|
||||
twl6040_codec = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
|
||||
.probe = twl6040_probe,
|
||||
.remove = twl6040_remove,
|
||||
.suspend = twl6040_suspend,
|
||||
.resume = twl6040_resume,
|
||||
.read = twl6040_read_reg_cache,
|
||||
.write = twl6040_write,
|
||||
.set_bias_level = twl6040_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(twl6040_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = twl6040_reg,
|
||||
};
|
||||
|
||||
static int __devinit twl6040_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_twl6040, &twl6040_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit twl6040_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl6040_codec_driver = {
|
||||
.driver = {
|
||||
.name = "twl6040_codec",
|
||||
.name = "twl6040-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = twl6040_codec_probe,
|
||||
|
|
|
|||
|
|
@ -135,7 +135,4 @@
|
|||
#define TWL6040_HPPLL_ID 1
|
||||
#define TWL6040_LPPLL_ID 2
|
||||
|
||||
extern struct snd_soc_dai twl6040_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_twl6040;
|
||||
|
||||
#endif /* End of __TWL6040_H__ */
|
||||
|
|
|
|||
|
|
@ -161,8 +161,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec =rtd->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_pcm_runtime *master_runtime;
|
||||
|
||||
|
|
@ -194,8 +193,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (uda134x->master_substream == substream)
|
||||
|
|
@ -209,8 +207,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
u8 hw_params;
|
||||
|
||||
|
|
@ -364,7 +361,7 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
|
|||
pd->power(1);
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
|
||||
codec->write(codec, i, *cache++);
|
||||
codec->driver->write(codec, i, *cache++);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
|
|
@ -465,8 +462,8 @@ static struct snd_soc_dai_ops uda134x_dai_ops = {
|
|||
.set_fmt = uda134x_set_dai_fmt,
|
||||
};
|
||||
|
||||
struct snd_soc_dai uda134x_dai = {
|
||||
.name = "UDA134X",
|
||||
static struct snd_soc_dai_driver uda134x_dai = {
|
||||
.name = "uda134x-hifi",
|
||||
/* playback capabilities */
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
|
|
@ -486,27 +483,21 @@ struct snd_soc_dai uda134x_dai = {
|
|||
/* pcm operations */
|
||||
.ops = &uda134x_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL(uda134x_dai);
|
||||
|
||||
|
||||
static int uda134x_soc_probe(struct platform_device *pdev)
|
||||
static int uda134x_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct uda134x_priv *uda134x;
|
||||
void *codec_setup_data = socdev->codec_data;
|
||||
int ret = -ENOMEM;
|
||||
struct uda134x_platform_data *pd;
|
||||
struct uda134x_platform_data *pd = dev_get_drvdata(codec->card->dev);
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "UDA134X SoC Audio Codec\n");
|
||||
|
||||
if (!codec_setup_data) {
|
||||
if (!pd) {
|
||||
printk(KERN_ERR "UDA134X SoC codec: "
|
||||
"missing L3 bitbang function\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pd = codec_setup_data;
|
||||
switch (pd->model) {
|
||||
case UDA134X_UDA1340:
|
||||
case UDA134X_UDA1341:
|
||||
|
|
@ -520,58 +511,22 @@ static int uda134x_soc_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (socdev->card->codec == NULL)
|
||||
return ret;
|
||||
|
||||
codec = socdev->card->codec;
|
||||
|
||||
uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
|
||||
if (uda134x == NULL)
|
||||
goto priv_err;
|
||||
return -ENOMEM;
|
||||
snd_soc_codec_set_drvdata(codec, uda134x);
|
||||
|
||||
codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
|
||||
GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL)
|
||||
goto reg_err;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
codec->reg_cache_size = sizeof(uda134x_reg);
|
||||
codec->reg_cache_step = 1;
|
||||
|
||||
codec->name = "UDA134X";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &uda134x_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->read = uda134x_read_reg_cache;
|
||||
codec->write = uda134x_write;
|
||||
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->control_data = codec_setup_data;
|
||||
codec->control_data = pd;
|
||||
|
||||
if (pd->power)
|
||||
pd->power(1);
|
||||
|
||||
uda134x_reset(codec);
|
||||
|
||||
if (pd->is_powered_on_standby) {
|
||||
codec->set_bias_level = NULL;
|
||||
if (pd->is_powered_on_standby)
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
|
||||
} else {
|
||||
codec->set_bias_level = uda134x_set_bias_level;
|
||||
else
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
}
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "UDA134X: failed to register pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
switch (pd->model) {
|
||||
case UDA134X_UDA1340:
|
||||
|
|
@ -590,61 +545,42 @@ static int uda134x_soc_probe(struct platform_device *pdev)
|
|||
default:
|
||||
printk(KERN_ERR "%s unknown codec type: %d",
|
||||
__func__, pd->model);
|
||||
return -EINVAL;
|
||||
kfree(uda134x);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "UDA134X: failed to register controls\n");
|
||||
goto pcm_err;
|
||||
kfree(uda134x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
pcm_err:
|
||||
kfree(codec->reg_cache);
|
||||
reg_err:
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
priv_err:
|
||||
kfree(codec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int uda134x_soc_remove(struct platform_device *pdev)
|
||||
static int uda134x_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec->reg_cache);
|
||||
kfree(codec);
|
||||
|
||||
kfree(uda134x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int uda134x_soc_suspend(struct platform_device *pdev,
|
||||
static int uda134x_soc_suspend(struct snd_soc_codec *codec,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uda134x_soc_resume(struct platform_device *pdev)
|
||||
static int uda134x_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
|
||||
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
|
||||
return 0;
|
||||
|
|
@ -654,25 +590,53 @@ static int uda134x_soc_resume(struct platform_device *pdev)
|
|||
#define uda134x_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_uda134x = {
|
||||
static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
|
||||
.probe = uda134x_soc_probe,
|
||||
.remove = uda134x_soc_remove,
|
||||
.suspend = uda134x_soc_suspend,
|
||||
.resume = uda134x_soc_resume,
|
||||
.reg_cache_size = sizeof(uda134x_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_step = 1,
|
||||
.read = uda134x_read_reg_cache,
|
||||
.write = uda134x_write,
|
||||
#ifdef POWER_OFF_ON_STANDBY
|
||||
.set_bias_level = uda134x_set_bias_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
|
||||
|
||||
static int __init uda134x_init(void)
|
||||
static int __devinit uda134x_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_dai(&uda134x_dai);
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_uda134x, &uda134x_dai, 1);
|
||||
}
|
||||
module_init(uda134x_init);
|
||||
|
||||
static void __exit uda134x_exit(void)
|
||||
static int __devexit uda134x_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&uda134x_dai);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
module_exit(uda134x_exit);
|
||||
|
||||
static struct platform_driver uda134x_codec_driver = {
|
||||
.driver = {
|
||||
.name = "uda134x-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = uda134x_codec_probe,
|
||||
.remove = __devexit_p(uda134x_codec_remove),
|
||||
};
|
||||
|
||||
static int __init uda134x_codec_init(void)
|
||||
{
|
||||
return platform_driver_register(&uda134x_codec_driver);
|
||||
}
|
||||
module_init(uda134x_codec_init);
|
||||
|
||||
static void __exit uda134x_codec_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&uda134x_codec_driver);
|
||||
}
|
||||
module_exit(uda134x_codec_exit);
|
||||
|
||||
MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
|
||||
MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -31,7 +31,4 @@
|
|||
#define STATUS0_DAIFMT_MASK (~(7<<1))
|
||||
#define STATUS0_SYSCLK_MASK (~(3<<4))
|
||||
|
||||
extern struct snd_soc_dai uda134x_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_uda134x;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,14 +33,13 @@
|
|||
|
||||
#include "uda1380.h"
|
||||
|
||||
static struct snd_soc_codec *uda1380_codec;
|
||||
|
||||
/* codec private data */
|
||||
struct uda1380_priv {
|
||||
struct snd_soc_codec codec;
|
||||
struct snd_soc_codec *codec;
|
||||
u16 reg_cache[UDA1380_CACHEREGNUM];
|
||||
unsigned int dac_clk;
|
||||
struct work_struct work;
|
||||
void *control_data;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -131,10 +130,51 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0)
|
||||
static void uda1380_sync_cache(struct snd_soc_codec *codec)
|
||||
{
|
||||
int reg;
|
||||
u8 data[3];
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (reg = 0; reg < UDA1380_MVOL; reg++) {
|
||||
data[0] = reg;
|
||||
data[1] = (cache[reg] & 0xff00) >> 8;
|
||||
data[2] = cache[reg] & 0x00ff;
|
||||
if (codec->hw_write(codec->control_data, data, 3) != 3)
|
||||
dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
|
||||
__func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int uda1380_reset(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_reset)) {
|
||||
gpio_set_value(pdata->gpio_reset, 1);
|
||||
mdelay(1);
|
||||
gpio_set_value(pdata->gpio_reset, 0);
|
||||
} else {
|
||||
u8 data[3];
|
||||
|
||||
data[0] = UDA1380_RESET;
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
|
||||
if (codec->hw_write(codec->control_data, data, 3) != 3) {
|
||||
dev_err(codec->dev, "%s: failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uda1380_flush_work(struct work_struct *work)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
|
||||
struct snd_soc_codec *uda1380_codec = uda1380->codec;
|
||||
int bit, reg;
|
||||
|
||||
for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
|
||||
|
|
@ -145,6 +185,7 @@ static void uda1380_flush_work(struct work_struct *work)
|
|||
uda1380_read_reg_cache(uda1380_codec, reg));
|
||||
clear_bit(bit, &uda1380_cache_dirty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* declarations of ALSA reg_elem_REAL controls */
|
||||
|
|
@ -474,8 +515,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
|
||||
|
||||
|
|
@ -501,8 +541,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
|
||||
|
||||
/* set WSPLL power and divider if running from this clock */
|
||||
|
|
@ -540,8 +579,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
|
||||
|
||||
/* shut down WSPLL power if running from this clock */
|
||||
|
|
@ -562,18 +600,41 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
|
|||
enum snd_soc_bias_level level)
|
||||
{
|
||||
int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
|
||||
int reg;
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
|
||||
if (codec->bias_level == level)
|
||||
return 0;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/* ADC, DAC on */
|
||||
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
if (gpio_is_valid(pdata->gpio_power)) {
|
||||
gpio_set_value(pdata->gpio_power, 1);
|
||||
mdelay(1);
|
||||
uda1380_reset(codec);
|
||||
}
|
||||
|
||||
uda1380_sync_cache(codec);
|
||||
}
|
||||
uda1380_write(codec, UDA1380_PM, 0x0);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
if (!gpio_is_valid(pdata->gpio_power))
|
||||
break;
|
||||
|
||||
gpio_set_value(pdata->gpio_power, 0);
|
||||
|
||||
/* Mark mixer regs cache dirty to sync them with
|
||||
* codec regs on power on.
|
||||
*/
|
||||
for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
|
||||
set_bit(reg - 0x10, &uda1380_cache_dirty);
|
||||
}
|
||||
codec->bias_level = level;
|
||||
return 0;
|
||||
|
|
@ -604,9 +665,9 @@ static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
|
|||
.set_fmt = uda1380_set_dai_fmt_capture,
|
||||
};
|
||||
|
||||
struct snd_soc_dai uda1380_dai[] = {
|
||||
static struct snd_soc_dai_driver uda1380_dai[] = {
|
||||
{
|
||||
.name = "UDA1380",
|
||||
.name = "uda1380-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -622,7 +683,7 @@ struct snd_soc_dai uda1380_dai[] = {
|
|||
.ops = &uda1380_dai_ops,
|
||||
},
|
||||
{ /* playback only - dual interface */
|
||||
.name = "UDA1380",
|
||||
.name = "uda1380-hifi-playback",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -633,7 +694,7 @@ struct snd_soc_dai uda1380_dai[] = {
|
|||
.ops = &uda1380_dai_ops_playback,
|
||||
},
|
||||
{ /* capture only - dual interface*/
|
||||
.name = "UDA1380",
|
||||
.name = "uda1380-hifi-capture",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
|
|
@ -644,67 +705,69 @@ struct snd_soc_dai uda1380_dai[] = {
|
|||
.ops = &uda1380_dai_ops_capture,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(uda1380_dai);
|
||||
|
||||
static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uda1380_resume(struct platform_device *pdev)
|
||||
static int uda1380_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int i;
|
||||
u8 data[2];
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
|
||||
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
|
||||
data[1] = cache[i] & 0x00ff;
|
||||
codec->hw_write(codec->control_data, data, 2);
|
||||
}
|
||||
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uda1380_probe(struct platform_device *pdev)
|
||||
static int uda1380_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct uda1380_platform_data *pdata;
|
||||
int ret = 0;
|
||||
struct uda1380_platform_data *pdata =codec->dev->platform_data;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (uda1380_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
uda1380->codec = codec;
|
||||
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
codec->control_data = uda1380->control_data;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_reset)) {
|
||||
ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
|
||||
if (ret)
|
||||
goto err_out;
|
||||
ret = gpio_direction_output(pdata->gpio_reset, 0);
|
||||
if (ret)
|
||||
goto err_gpio_reset_conf;
|
||||
}
|
||||
|
||||
socdev->card->codec = uda1380_codec;
|
||||
codec = uda1380_codec;
|
||||
pdata = codec->dev->platform_data;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
if (gpio_is_valid(pdata->gpio_power)) {
|
||||
ret = gpio_request(pdata->gpio_power, "uda1380 power");
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
ret = gpio_direction_output(pdata->gpio_power, 0);
|
||||
if (ret)
|
||||
goto err_gpio_power_conf;
|
||||
} else {
|
||||
ret = uda1380_reset(codec);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to issue reset\n");
|
||||
goto err_reset;
|
||||
}
|
||||
}
|
||||
|
||||
INIT_WORK(&uda1380->work, uda1380_flush_work);
|
||||
|
||||
/* power on device */
|
||||
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
/* set clock input */
|
||||
switch (pdata->dac_clk) {
|
||||
case UDA1380_DAC_CLK_SYSCLK:
|
||||
uda1380_write(codec, UDA1380_CLK, 0);
|
||||
uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
|
||||
break;
|
||||
case UDA1380_DAC_CLK_WSPLL:
|
||||
uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
|
||||
uda1380_write_reg_cache(codec, UDA1380_CLK,
|
||||
R00_DAC_CLK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -712,167 +775,73 @@ static int uda1380_probe(struct platform_device *pdev)
|
|||
ARRAY_SIZE(uda1380_snd_controls));
|
||||
uda1380_add_widgets(codec);
|
||||
|
||||
return ret;
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int uda1380_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec->control_data)
|
||||
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_uda1380 = {
|
||||
.probe = uda1380_probe,
|
||||
.remove = uda1380_remove,
|
||||
.suspend = uda1380_suspend,
|
||||
.resume = uda1380_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
|
||||
|
||||
static int uda1380_register(struct uda1380_priv *uda1380)
|
||||
{
|
||||
int ret, i;
|
||||
struct snd_soc_codec *codec = &uda1380->codec;
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
|
||||
if (uda1380_codec) {
|
||||
dev_err(codec->dev, "Another UDA1380 is registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
|
||||
return -EINVAL;
|
||||
|
||||
ret = gpio_request(pdata->gpio_power, "uda1380 power");
|
||||
if (ret)
|
||||
goto err_out;
|
||||
ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
|
||||
gpio_direction_output(pdata->gpio_power, 1);
|
||||
|
||||
/* we may need to have the clock running here - pH5 */
|
||||
gpio_direction_output(pdata->gpio_reset, 1);
|
||||
udelay(5);
|
||||
gpio_set_value(pdata->gpio_reset, 0);
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, uda1380);
|
||||
codec->name = "UDA1380";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = uda1380_read_reg_cache;
|
||||
codec->write = uda1380_write;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = uda1380_set_bias_level;
|
||||
codec->dai = uda1380_dai;
|
||||
codec->num_dai = ARRAY_SIZE(uda1380_dai);
|
||||
codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
|
||||
codec->reg_cache = &uda1380->reg_cache;
|
||||
codec->reg_cache_step = 1;
|
||||
|
||||
memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
|
||||
|
||||
ret = uda1380_reset(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to issue reset\n");
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
INIT_WORK(&uda1380->work, uda1380_flush_work);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
|
||||
uda1380_dai[i].dev = codec->dev;
|
||||
|
||||
uda1380_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
|
||||
goto err_dai;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_dai:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err_reset:
|
||||
gpio_set_value(pdata->gpio_power, 0);
|
||||
gpio_free(pdata->gpio_reset);
|
||||
err_gpio_power_conf:
|
||||
if (gpio_is_valid(pdata->gpio_power))
|
||||
gpio_free(pdata->gpio_power);
|
||||
|
||||
err_gpio_reset_conf:
|
||||
err_gpio:
|
||||
gpio_free(pdata->gpio_power);
|
||||
if (gpio_is_valid(pdata->gpio_reset))
|
||||
gpio_free(pdata->gpio_reset);
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uda1380_unregister(struct uda1380_priv *uda1380)
|
||||
/* power down chip */
|
||||
static int uda1380_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = &uda1380->codec;
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
struct uda1380_platform_data *pdata =codec->dev->platform_data;
|
||||
|
||||
snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
|
||||
snd_soc_unregister_codec(&uda1380->codec);
|
||||
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
gpio_set_value(pdata->gpio_power, 0);
|
||||
gpio_free(pdata->gpio_reset);
|
||||
gpio_free(pdata->gpio_power);
|
||||
|
||||
kfree(uda1380);
|
||||
uda1380_codec = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
|
||||
.probe = uda1380_probe,
|
||||
.remove = uda1380_remove,
|
||||
.suspend = uda1380_suspend,
|
||||
.resume = uda1380_resume,
|
||||
.read = uda1380_read_reg_cache,
|
||||
.write = uda1380_write,
|
||||
.set_bias_level = uda1380_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(uda1380_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = uda1380_reg,
|
||||
.reg_cache_step = 1,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct uda1380_priv *uda1380;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
|
||||
if (uda1380 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &uda1380->codec;
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
|
||||
i2c_set_clientdata(i2c, uda1380);
|
||||
codec->control_data = i2c;
|
||||
uda1380->control_data = i2c;
|
||||
|
||||
codec->dev = &i2c->dev;
|
||||
|
||||
ret = uda1380_register(uda1380);
|
||||
if (ret != 0)
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
|
||||
if (ret < 0)
|
||||
kfree(uda1380);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
|
||||
uda1380_unregister(uda1380);
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
kfree(i2c_get_clientdata(i2c));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -884,7 +853,7 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
|
|||
|
||||
static struct i2c_driver uda1380_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "UDA1380 I2C Codec",
|
||||
.name = "uda1380-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = uda1380_i2c_probe,
|
||||
|
|
|
|||
|
|
@ -76,7 +76,4 @@
|
|||
#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */
|
||||
#define UDA1380_DAI_CAPTURE 2 /* capture DAI */
|
||||
|
||||
extern struct snd_soc_dai uda1380_dai[3];
|
||||
extern struct snd_soc_codec_device soc_codec_dev_uda1380;
|
||||
|
||||
#endif /* _UDA1380_H */
|
||||
|
|
|
|||
528
sound/soc/codecs/wl1273.c
Normal file
528
sound/soc/codecs/wl1273.c
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
/*
|
||||
* ALSA SoC WL1273 codec driver
|
||||
*
|
||||
* Author: Matti Aaltonen, <matti.j.aaltonen@nokia.com>
|
||||
*
|
||||
* Copyright: (C) 2010 Nokia Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mfd/wl1273-core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc-dai.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "wl1273.h"
|
||||
|
||||
enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
|
||||
|
||||
/* codec private data */
|
||||
struct wl1273_priv {
|
||||
enum wl1273_mode mode;
|
||||
struct wl1273_core *core;
|
||||
unsigned int channels;
|
||||
};
|
||||
|
||||
static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
|
||||
int rate, int width)
|
||||
{
|
||||
struct device *dev = &core->i2c_dev->dev;
|
||||
int r = 0;
|
||||
u16 mode;
|
||||
|
||||
dev_dbg(dev, "rate: %d\n", rate);
|
||||
dev_dbg(dev, "width: %d\n", width);
|
||||
|
||||
mutex_lock(&core->lock);
|
||||
|
||||
mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
|
||||
|
||||
switch (rate) {
|
||||
case 48000:
|
||||
mode |= WL1273_IS2_RATE_48K;
|
||||
break;
|
||||
case 44100:
|
||||
mode |= WL1273_IS2_RATE_44_1K;
|
||||
break;
|
||||
case 32000:
|
||||
mode |= WL1273_IS2_RATE_32K;
|
||||
break;
|
||||
case 22050:
|
||||
mode |= WL1273_IS2_RATE_22_05K;
|
||||
break;
|
||||
case 16000:
|
||||
mode |= WL1273_IS2_RATE_16K;
|
||||
break;
|
||||
case 12000:
|
||||
mode |= WL1273_IS2_RATE_12K;
|
||||
break;
|
||||
case 11025:
|
||||
mode |= WL1273_IS2_RATE_11_025;
|
||||
break;
|
||||
case 8000:
|
||||
mode |= WL1273_IS2_RATE_8K;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Sampling rate: %d not supported\n", rate);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (width) {
|
||||
case 16:
|
||||
mode |= WL1273_IS2_WIDTH_32;
|
||||
break;
|
||||
case 20:
|
||||
mode |= WL1273_IS2_WIDTH_40;
|
||||
break;
|
||||
case 24:
|
||||
mode |= WL1273_IS2_WIDTH_48;
|
||||
break;
|
||||
case 25:
|
||||
mode |= WL1273_IS2_WIDTH_50;
|
||||
break;
|
||||
case 30:
|
||||
mode |= WL1273_IS2_WIDTH_60;
|
||||
break;
|
||||
case 32:
|
||||
mode |= WL1273_IS2_WIDTH_64;
|
||||
break;
|
||||
case 40:
|
||||
mode |= WL1273_IS2_WIDTH_80;
|
||||
break;
|
||||
case 48:
|
||||
mode |= WL1273_IS2_WIDTH_96;
|
||||
break;
|
||||
case 64:
|
||||
mode |= WL1273_IS2_WIDTH_128;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Data width: %d not supported\n", width);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n", WL1273_I2S_DEF_MODE);
|
||||
dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
|
||||
dev_dbg(dev, "mode: 0x%04x\n", mode);
|
||||
|
||||
if (core->i2s_mode != mode) {
|
||||
r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
core->i2s_mode = mode;
|
||||
r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
|
||||
WL1273_AUDIO_ENABLE_I2S);
|
||||
if (r)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&core->lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
|
||||
int channel_number)
|
||||
{
|
||||
struct i2c_client *client = core->i2c_dev;
|
||||
struct device *dev = &client->dev;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
mutex_lock(&core->lock);
|
||||
|
||||
if (core->channel_number == channel_number)
|
||||
goto out;
|
||||
|
||||
if (channel_number == 1 && core->mode == WL1273_MODE_RX)
|
||||
r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
|
||||
WL1273_RX_MONO);
|
||||
else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
|
||||
r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
|
||||
WL1273_TX_MONO);
|
||||
else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
|
||||
r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
|
||||
WL1273_RX_STEREO);
|
||||
else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
|
||||
r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
|
||||
WL1273_TX_STEREO);
|
||||
else
|
||||
r = -EINVAL;
|
||||
out:
|
||||
mutex_unlock(&core->lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = wl1273->mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
|
||||
|
||||
static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (wl1273->mode == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
||||
/* Do not allow changes while stream is running */
|
||||
if (codec->active)
|
||||
return -EPERM;
|
||||
|
||||
if (ucontrol->value.integer.value[0] < 0 ||
|
||||
ucontrol->value.integer.value[0] >= ARRAY_SIZE(wl1273_audio_route))
|
||||
return -EINVAL;
|
||||
|
||||
wl1273->mode = ucontrol->value.integer.value[0];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct soc_enum wl1273_enum =
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
|
||||
|
||||
static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(codec->dev, "%s: enter.\n", __func__);
|
||||
|
||||
ucontrol->value.integer.value[0] = wl1273->core->audio_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
int val, r = 0;
|
||||
|
||||
dev_dbg(codec->dev, "%s: enter.\n", __func__);
|
||||
|
||||
val = ucontrol->value.integer.value[0];
|
||||
if (wl1273->core->audio_mode == val)
|
||||
return 0;
|
||||
|
||||
r = wl1273_fm_set_audio(wl1273->core, val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *wl1273_audio_strings[] = { "Digital", "Analog" };
|
||||
|
||||
static const struct soc_enum wl1273_audio_enum =
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
|
||||
wl1273_audio_strings);
|
||||
|
||||
static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(codec->dev, "%s: enter.\n", __func__);
|
||||
|
||||
ucontrol->value.integer.value[0] = wl1273->core->volume;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
int r;
|
||||
|
||||
dev_dbg(codec->dev, "%s: enter.\n", __func__);
|
||||
|
||||
r = wl1273_fm_set_volume(wl1273->core,
|
||||
ucontrol->value.integer.value[0]);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new wl1273_controls[] = {
|
||||
SOC_ENUM_EXT("Codec Mode", wl1273_enum,
|
||||
snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
|
||||
SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
|
||||
snd_wl1273_fm_audio_get, snd_wl1273_fm_audio_put),
|
||||
SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
|
||||
snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
|
||||
};
|
||||
|
||||
static int wl1273_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (wl1273->mode) {
|
||||
case WL1273_MODE_BT:
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
8000, 8000);
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, 1, 1);
|
||||
break;
|
||||
case WL1273_MODE_FM_RX:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
pr_err("Cannot play in RX mode.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case WL1273_MODE_FM_TX:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
pr_err("Cannot capture in TX mode.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1273_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
|
||||
struct wl1273_core *core = wl1273->core;
|
||||
unsigned int rate, width, r;
|
||||
|
||||
if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
|
||||
pr_err("Only SNDRV_PCM_FORMAT_S16_LE supported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rate = params_rate(params);
|
||||
width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
|
||||
|
||||
if (wl1273->mode == WL1273_MODE_BT) {
|
||||
if (rate != 8000) {
|
||||
pr_err("Rate %d not supported.\n", params_rate(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params_channels(params) != 1) {
|
||||
pr_err("Only mono supported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wl1273->mode == WL1273_MODE_FM_TX &&
|
||||
substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
pr_err("Only playback supported with TX.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wl1273->mode == WL1273_MODE_FM_RX &&
|
||||
substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
pr_err("Only capture supported with RX.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wl1273->mode != WL1273_MODE_FM_RX &&
|
||||
wl1273->mode != WL1273_MODE_FM_TX) {
|
||||
pr_err("Unexpected mode: %d.\n", wl1273->mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
wl1273->channels = params_channels(params);
|
||||
r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops wl1273_dai_ops = {
|
||||
.startup = wl1273_startup,
|
||||
.hw_params = wl1273_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver wl1273_dai = {
|
||||
.name = "wl1273-fm",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE},
|
||||
.ops = &wl1273_dai_ops,
|
||||
};
|
||||
|
||||
/* Audio interface format for the soc_card driver */
|
||||
int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
|
||||
{
|
||||
struct wl1273_priv *wl1273;
|
||||
|
||||
if (codec == NULL || fmt == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (wl1273->mode) {
|
||||
case WL1273_MODE_FM_RX:
|
||||
case WL1273_MODE_FM_TX:
|
||||
*fmt = SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM;
|
||||
|
||||
break;
|
||||
case WL1273_MODE_BT:
|
||||
*fmt = SND_SOC_DAIFMT_DSP_A |
|
||||
SND_SOC_DAIFMT_IB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1273_get_format);
|
||||
|
||||
static int wl1273_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wl1273_core **core = codec->dev->platform_data;
|
||||
struct wl1273_priv *wl1273;
|
||||
int r;
|
||||
|
||||
dev_dbg(codec->dev, "%s.\n", __func__);
|
||||
|
||||
if (!core) {
|
||||
dev_err(codec->dev, "Platform data is missing.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
|
||||
if (wl1273 == NULL) {
|
||||
dev_err(codec->dev, "Cannot allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wl1273->mode = WL1273_MODE_BT;
|
||||
wl1273->core = *core;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, wl1273);
|
||||
mutex_init(&codec->mutex);
|
||||
|
||||
r = snd_soc_add_controls(codec, wl1273_controls,
|
||||
ARRAY_SIZE(wl1273_controls));
|
||||
if (r)
|
||||
kfree(wl1273);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wl1273_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(codec->dev, "%s\n", __func__);
|
||||
kfree(wl1273);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
|
||||
.probe = wl1273_probe,
|
||||
.remove = wl1273_remove,
|
||||
};
|
||||
|
||||
static int __devinit wl1273_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273,
|
||||
&wl1273_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit wl1273_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:wl1273-codec");
|
||||
|
||||
static struct platform_driver wl1273_platform_driver = {
|
||||
.driver = {
|
||||
.name = "wl1273-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wl1273_platform_probe,
|
||||
.remove = __devexit_p(wl1273_platform_remove),
|
||||
};
|
||||
|
||||
static int __init wl1273_init(void)
|
||||
{
|
||||
return platform_driver_register(&wl1273_platform_driver);
|
||||
}
|
||||
module_init(wl1273_init);
|
||||
|
||||
static void __exit wl1273_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wl1273_platform_driver);
|
||||
}
|
||||
module_exit(wl1273_exit);
|
||||
|
||||
MODULE_AUTHOR("Matti Aaltonen <[email protected]>");
|
||||
MODULE_DESCRIPTION("ASoC WL1273 codec driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
101
sound/soc/codecs/wl1273.h
Normal file
101
sound/soc/codecs/wl1273.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* sound/soc/codec/wl1273.h
|
||||
*
|
||||
* ALSA SoC WL1273 codec driver
|
||||
*
|
||||
* Copyright (C) Nokia Corporation
|
||||
* Author: Matti Aaltonen <matti.j.aaltonen@nokia.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.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL1273_CODEC_H__
|
||||
#define __WL1273_CODEC_H__
|
||||
|
||||
/* I2S protocol, left channel first, data width 16 bits */
|
||||
#define WL1273_PCM_DEF_MODE 0x00
|
||||
|
||||
/* Rx */
|
||||
#define WL1273_AUDIO_ENABLE_I2S (1 << 0)
|
||||
#define WL1273_AUDIO_ENABLE_ANALOG (1 << 1)
|
||||
|
||||
/* Tx */
|
||||
#define WL1273_AUDIO_IO_SET_ANALOG 0
|
||||
#define WL1273_AUDIO_IO_SET_I2S 1
|
||||
|
||||
#define WL1273_POWER_SET_OFF 0
|
||||
#define WL1273_POWER_SET_FM (1 << 0)
|
||||
#define WL1273_POWER_SET_RDS (1 << 1)
|
||||
#define WL1273_POWER_SET_RETENTION (1 << 4)
|
||||
|
||||
#define WL1273_PUPD_SET_OFF 0x00
|
||||
#define WL1273_PUPD_SET_ON 0x01
|
||||
#define WL1273_PUPD_SET_RETENTION 0x10
|
||||
|
||||
/* I2S mode */
|
||||
#define WL1273_IS2_WIDTH_32 0x0
|
||||
#define WL1273_IS2_WIDTH_40 0x1
|
||||
#define WL1273_IS2_WIDTH_22_23 0x2
|
||||
#define WL1273_IS2_WIDTH_23_22 0x3
|
||||
#define WL1273_IS2_WIDTH_48 0x4
|
||||
#define WL1273_IS2_WIDTH_50 0x5
|
||||
#define WL1273_IS2_WIDTH_60 0x6
|
||||
#define WL1273_IS2_WIDTH_64 0x7
|
||||
#define WL1273_IS2_WIDTH_80 0x8
|
||||
#define WL1273_IS2_WIDTH_96 0x9
|
||||
#define WL1273_IS2_WIDTH_128 0xa
|
||||
#define WL1273_IS2_WIDTH 0xf
|
||||
|
||||
#define WL1273_IS2_FORMAT_STD (0x0 << 4)
|
||||
#define WL1273_IS2_FORMAT_LEFT (0x1 << 4)
|
||||
#define WL1273_IS2_FORMAT_RIGHT (0x2 << 4)
|
||||
#define WL1273_IS2_FORMAT_USER (0x3 << 4)
|
||||
|
||||
#define WL1273_IS2_MASTER (0x0 << 6)
|
||||
#define WL1273_IS2_SLAVEW (0x1 << 6)
|
||||
|
||||
#define WL1273_IS2_TRI_AFTER_SENDING (0x0 << 7)
|
||||
#define WL1273_IS2_TRI_ALWAYS_ACTIVE (0x1 << 7)
|
||||
|
||||
#define WL1273_IS2_SDOWS_RR (0x0 << 8)
|
||||
#define WL1273_IS2_SDOWS_RF (0x1 << 8)
|
||||
#define WL1273_IS2_SDOWS_FR (0x2 << 8)
|
||||
#define WL1273_IS2_SDOWS_FF (0x3 << 8)
|
||||
|
||||
#define WL1273_IS2_TRI_OPT (0x0 << 10)
|
||||
#define WL1273_IS2_TRI_ALWAYS (0x1 << 10)
|
||||
|
||||
#define WL1273_IS2_RATE_48K (0x0 << 12)
|
||||
#define WL1273_IS2_RATE_44_1K (0x1 << 12)
|
||||
#define WL1273_IS2_RATE_32K (0x2 << 12)
|
||||
#define WL1273_IS2_RATE_22_05K (0x4 << 12)
|
||||
#define WL1273_IS2_RATE_16K (0x5 << 12)
|
||||
#define WL1273_IS2_RATE_12K (0x8 << 12)
|
||||
#define WL1273_IS2_RATE_11_025 (0x9 << 12)
|
||||
#define WL1273_IS2_RATE_8K (0xa << 12)
|
||||
#define WL1273_IS2_RATE (0xf << 12)
|
||||
|
||||
#define WL1273_I2S_DEF_MODE (WL1273_IS2_WIDTH_32 | \
|
||||
WL1273_IS2_FORMAT_STD | \
|
||||
WL1273_IS2_MASTER | \
|
||||
WL1273_IS2_TRI_AFTER_SENDING | \
|
||||
WL1273_IS2_SDOWS_RR | \
|
||||
WL1273_IS2_TRI_OPT | \
|
||||
WL1273_IS2_RATE_48K)
|
||||
|
||||
int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
|
||||
|
||||
#endif /* End of __WL1273_CODEC_H__ */
|
||||
|
|
@ -16,9 +16,6 @@ struct wm2000_setup_data {
|
|||
|
||||
extern int wm2000_add_controls(struct snd_soc_codec *codec);
|
||||
|
||||
extern struct snd_soc_dai wm2000_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_wm2000;
|
||||
|
||||
#define WM2000_REG_SYS_START 0x8000
|
||||
#define WM2000_REG_SPEECH_CLARITY 0x8fef
|
||||
#define WM2000_REG_SYS_WATCHDOG 0x8ff6
|
||||
|
|
|
|||
|
|
@ -1321,20 +1321,14 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8350_resume(struct platform_device *pdev)
|
||||
static int wm8350_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1489,24 +1483,74 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
|
||||
|
||||
static struct snd_soc_codec *wm8350_codec;
|
||||
#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
|
||||
|
||||
static int wm8350_probe(struct platform_device *pdev)
|
||||
#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
static struct snd_soc_dai_ops wm8350_dai_ops = {
|
||||
.hw_params = wm8350_pcm_hw_params,
|
||||
.digital_mute = wm8350_mute,
|
||||
.trigger = wm8350_pcm_trigger,
|
||||
.set_fmt = wm8350_set_dai_fmt,
|
||||
.set_sysclk = wm8350_set_dai_sysclk,
|
||||
.set_pll = wm8350_set_fll,
|
||||
.set_clkdiv = wm8350_set_clkdiv,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver wm8350_dai = {
|
||||
.name = "wm8350-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = WM8350_RATES,
|
||||
.formats = WM8350_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = WM8350_RATES,
|
||||
.formats = WM8350_FORMATS,
|
||||
},
|
||||
.ops = &wm8350_dai_ops,
|
||||
};
|
||||
|
||||
static int wm8350_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
struct wm8350 *wm8350;
|
||||
struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
|
||||
struct wm8350_data *priv;
|
||||
int ret;
|
||||
struct wm8350_output *out1;
|
||||
struct wm8350_output *out2;
|
||||
int ret, i;
|
||||
|
||||
BUG_ON(!wm8350_codec);
|
||||
if (wm8350->codec.platform_data == NULL) {
|
||||
dev_err(codec->dev, "No audio platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
socdev->card->codec = wm8350_codec;
|
||||
codec = socdev->card->codec;
|
||||
wm8350 = codec->control_data;
|
||||
priv = snd_soc_codec_get_drvdata(codec);
|
||||
priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
|
||||
priv->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
|
||||
priv->supplies);
|
||||
if (ret != 0)
|
||||
goto err_priv;
|
||||
|
||||
wm8350->codec.codec = codec;
|
||||
codec->control_data = wm8350;
|
||||
|
||||
/* Put the codec into reset if it wasn't already */
|
||||
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
||||
|
||||
INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
|
||||
|
||||
/* Enable the codec */
|
||||
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
||||
|
|
@ -1557,11 +1601,6 @@ static int wm8350_probe(struct platform_device *pdev)
|
|||
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
|
||||
wm8350_mic_handler, 0, "Microphone detect", priv);
|
||||
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create pcms\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, wm8350_snd_controls,
|
||||
ARRAY_SIZE(wm8350_snd_controls));
|
||||
|
|
@ -1570,14 +1609,16 @@ static int wm8350_probe(struct platform_device *pdev)
|
|||
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
|
||||
err_priv:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8350_remove(struct platform_device *pdev)
|
||||
static int wm8350_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
|
||||
int ret;
|
||||
|
||||
wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
|
||||
|
|
@ -1607,134 +1648,30 @@ static int wm8350_remove(struct platform_device *pdev)
|
|||
|
||||
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
kfree(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
|
||||
|
||||
#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
static struct snd_soc_dai_ops wm8350_dai_ops = {
|
||||
.hw_params = wm8350_pcm_hw_params,
|
||||
.digital_mute = wm8350_mute,
|
||||
.trigger = wm8350_pcm_trigger,
|
||||
.set_fmt = wm8350_set_dai_fmt,
|
||||
.set_sysclk = wm8350_set_dai_sysclk,
|
||||
.set_pll = wm8350_set_fll,
|
||||
.set_clkdiv = wm8350_set_clkdiv,
|
||||
};
|
||||
|
||||
struct snd_soc_dai wm8350_dai = {
|
||||
.name = "WM8350",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = WM8350_RATES,
|
||||
.formats = WM8350_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = WM8350_RATES,
|
||||
.formats = WM8350_FORMATS,
|
||||
},
|
||||
.ops = &wm8350_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm8350_dai);
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8350 = {
|
||||
.probe = wm8350_probe,
|
||||
.remove = wm8350_remove,
|
||||
static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
|
||||
.probe = wm8350_codec_probe,
|
||||
.remove = wm8350_codec_remove,
|
||||
.suspend = wm8350_suspend,
|
||||
.resume = wm8350_resume,
|
||||
.read = wm8350_codec_read,
|
||||
.write = wm8350_codec_write,
|
||||
.set_bias_level = wm8350_set_bias_level,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
|
||||
|
||||
static __devinit int wm8350_codec_probe(struct platform_device *pdev)
|
||||
static int __devinit wm8350_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
|
||||
struct wm8350_data *priv;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret, i;
|
||||
|
||||
if (wm8350->codec.platform_data == NULL) {
|
||||
dev_err(&pdev->dev, "No audio platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
|
||||
priv->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
|
||||
priv->supplies);
|
||||
if (ret != 0)
|
||||
goto err_priv;
|
||||
|
||||
codec = &priv->codec;
|
||||
wm8350->codec.codec = codec;
|
||||
|
||||
wm8350_dai.dev = &pdev->dev;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
codec->dev = &pdev->dev;
|
||||
codec->name = "WM8350";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = wm8350_codec_read;
|
||||
codec->write = wm8350_codec_write;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = wm8350_set_bias_level;
|
||||
codec->dai = &wm8350_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = WM8350_MAX_REGISTER;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
codec->control_data = wm8350;
|
||||
|
||||
/* Put the codec into reset if it wasn't already */
|
||||
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
||||
|
||||
INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0)
|
||||
goto err_supply;
|
||||
|
||||
wm8350_codec = codec;
|
||||
|
||||
ret = snd_soc_register_dai(&wm8350_dai);
|
||||
if (ret != 0)
|
||||
goto err_codec;
|
||||
return 0;
|
||||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err_supply:
|
||||
regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
err_priv:
|
||||
kfree(priv);
|
||||
wm8350_codec = NULL;
|
||||
return ret;
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
|
||||
&wm8350_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit wm8350_codec_remove(struct platform_device *pdev)
|
||||
static int __devexit wm8350_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = wm8350->codec.codec;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_soc_unregister_dai(&wm8350_dai);
|
||||
snd_soc_unregister_codec(codec);
|
||||
regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
kfree(priv);
|
||||
wm8350_codec = NULL;
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1743,8 +1680,8 @@ static struct platform_driver wm8350_codec_driver = {
|
|||
.name = "wm8350-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8350_codec_probe,
|
||||
.remove = __devexit_p(wm8350_codec_remove),
|
||||
.probe = wm8350_probe,
|
||||
.remove = __devexit_p(wm8350_remove),
|
||||
};
|
||||
|
||||
static __init int wm8350_init(void)
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@
|
|||
#include <sound/soc.h>
|
||||
#include <linux/mfd/wm8350/audio.h>
|
||||
|
||||
extern struct snd_soc_dai wm8350_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_wm8350;
|
||||
|
||||
enum wm8350_jack {
|
||||
WM8350_JDL = 1,
|
||||
WM8350_JDR = 2,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ static struct regulator_bulk_data power[] = {
|
|||
|
||||
/* codec private data */
|
||||
struct wm8400_priv {
|
||||
struct snd_soc_codec codec;
|
||||
struct snd_soc_codec *codec;
|
||||
struct wm8400 *wm8400;
|
||||
u16 fake_register;
|
||||
unsigned int sysclk;
|
||||
|
|
@ -1163,8 +1163,7 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
|
||||
|
||||
audio1 &= ~WM8400_AIF_WL_MASK;
|
||||
|
|
@ -1332,10 +1331,9 @@ static struct snd_soc_dai_ops wm8400_dai_ops = {
|
|||
* 1. ADC/DAC on Primary Interface
|
||||
* 2. ADC on Primary Interface/DAC on secondary
|
||||
*/
|
||||
struct snd_soc_dai wm8400_dai = {
|
||||
static struct snd_soc_dai_driver wm8400_dai = {
|
||||
/* ADC/DAC on primary */
|
||||
.name = "WM8400 ADC/DAC Primary",
|
||||
.id = 1,
|
||||
.name = "wm8400-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
|
@ -1352,147 +1350,53 @@ struct snd_soc_dai wm8400_dai = {
|
|||
},
|
||||
.ops = &wm8400_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm8400_dai);
|
||||
|
||||
static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8400_resume(struct platform_device *pdev)
|
||||
static int wm8400_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec *wm8400_codec;
|
||||
|
||||
static int wm8400_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
if (!wm8400_codec) {
|
||||
dev_err(&pdev->dev, "wm8400 not yet discovered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
codec = wm8400_codec;
|
||||
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
wm8400_add_controls(codec);
|
||||
wm8400_add_widgets(codec);
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int wm8400_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8400 = {
|
||||
.probe = wm8400_probe,
|
||||
.remove = wm8400_remove,
|
||||
.suspend = wm8400_suspend,
|
||||
.resume = wm8400_resume,
|
||||
};
|
||||
|
||||
static void wm8400_probe_deferred(struct work_struct *work)
|
||||
{
|
||||
struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
|
||||
work);
|
||||
struct snd_soc_codec *codec = &priv->codec;
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
|
||||
/* charge output caps */
|
||||
wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* We're done, tell the subsystem. */
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(priv->wm8400->dev,
|
||||
"Failed to register codec: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&wm8400_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(priv->wm8400->dev,
|
||||
"Failed to register DAI: %d\n", ret);
|
||||
goto err_codec;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err:
|
||||
wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
}
|
||||
|
||||
static int wm8400_codec_probe(struct platform_device *dev)
|
||||
static int wm8400_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
|
||||
struct wm8400_priv *priv;
|
||||
int ret;
|
||||
u16 reg;
|
||||
struct snd_soc_codec *codec;
|
||||
|
||||
priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &priv->codec;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
codec->control_data = dev_get_drvdata(&dev->dev);
|
||||
priv->wm8400 = dev_get_drvdata(&dev->dev);
|
||||
codec->control_data = priv->wm8400 = wm8400;
|
||||
priv->codec = codec;
|
||||
|
||||
ret = regulator_bulk_get(priv->wm8400->dev,
|
||||
ret = regulator_bulk_get(wm8400->dev,
|
||||
ARRAY_SIZE(power), &power[0]);
|
||||
if (ret != 0) {
|
||||
dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
|
||||
dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
codec->dev = &dev->dev;
|
||||
wm8400_dai.dev = &dev->dev;
|
||||
|
||||
codec->name = "WM8400";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = wm8400_read;
|
||||
codec->write = wm8400_write;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = wm8400_set_bias_level;
|
||||
codec->dai = &wm8400_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = WM8400_REGISTER_COUNT;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
INIT_WORK(&priv->work, wm8400_probe_deferred);
|
||||
|
||||
wm8400_codec_reset(codec);
|
||||
|
|
@ -1511,65 +1415,78 @@ static int wm8400_codec_probe(struct platform_device *dev)
|
|||
wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
|
||||
wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
|
||||
|
||||
wm8400_codec = codec;
|
||||
|
||||
if (!schedule_work(&priv->work)) {
|
||||
ret = -EINVAL;
|
||||
goto err_regulator;
|
||||
}
|
||||
|
||||
wm8400_add_controls(codec);
|
||||
wm8400_add_widgets(codec);
|
||||
return 0;
|
||||
|
||||
err_regulator:
|
||||
wm8400_codec = NULL;
|
||||
regulator_bulk_free(ARRAY_SIZE(power), power);
|
||||
err:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit wm8400_codec_remove(struct platform_device *dev)
|
||||
static int wm8400_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec);
|
||||
struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg;
|
||||
|
||||
snd_soc_unregister_dai(&wm8400_dai);
|
||||
snd_soc_unregister_codec(wm8400_codec);
|
||||
|
||||
reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
|
||||
wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
|
||||
reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
|
||||
wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
|
||||
reg & (~WM8400_CODEC_ENA));
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(power), power);
|
||||
kfree(priv);
|
||||
|
||||
wm8400_codec = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
|
||||
.probe = wm8400_codec_probe,
|
||||
.remove = wm8400_codec_remove,
|
||||
.suspend = wm8400_suspend,
|
||||
.resume = wm8400_resume,
|
||||
.read = wm8400_read,
|
||||
.write = wm8400_write,
|
||||
.set_bias_level = wm8400_set_bias_level,
|
||||
};
|
||||
|
||||
static int __devinit wm8400_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
|
||||
&wm8400_dai, 1);
|
||||
}
|
||||
|
||||
static int __devexit wm8400_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver wm8400_codec_driver = {
|
||||
.driver = {
|
||||
.name = "wm8400-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8400_codec_probe,
|
||||
.remove = __exit_p(wm8400_codec_remove),
|
||||
.name = "wm8400-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8400_probe,
|
||||
.remove = __devexit_p(wm8400_remove),
|
||||
};
|
||||
|
||||
static int __init wm8400_codec_init(void)
|
||||
static __init int wm8400_init(void)
|
||||
{
|
||||
return platform_driver_register(&wm8400_codec_driver);
|
||||
}
|
||||
module_init(wm8400_codec_init);
|
||||
module_init(wm8400_init);
|
||||
|
||||
static void __exit wm8400_codec_exit(void)
|
||||
static __exit void wm8400_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wm8400_codec_driver);
|
||||
}
|
||||
module_exit(wm8400_codec_exit);
|
||||
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
|
||||
module_exit(wm8400_exit);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC WM8400 driver");
|
||||
MODULE_AUTHOR("Mark Brown");
|
||||
|
|
|
|||
|
|
@ -56,7 +56,4 @@
|
|||
#define WM8400_BCLK_DIV_44 (0xE << 1)
|
||||
#define WM8400_BCLK_DIV_48 (0xF << 1)
|
||||
|
||||
extern struct snd_soc_dai wm8400_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_wm8400;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,10 +29,6 @@
|
|||
|
||||
#include "wm8510.h"
|
||||
|
||||
#define WM8510_VERSION "0.6"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8510;
|
||||
|
||||
/*
|
||||
* wm8510 register cache
|
||||
* We can't read the WM8510 register space when we are
|
||||
|
|
@ -61,6 +57,11 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
|
|||
|
||||
#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0)
|
||||
|
||||
/* codec private data */
|
||||
struct wm8510_priv {
|
||||
enum snd_soc_control_type control_type;
|
||||
};
|
||||
|
||||
static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
|
||||
static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
|
||||
static const char *wm8510_alc[] = { "ALC", "Limiter" };
|
||||
|
|
@ -403,8 +404,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
|
||||
u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
|
||||
|
||||
|
|
@ -514,8 +514,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = {
|
|||
.set_pll = wm8510_set_dai_pll,
|
||||
};
|
||||
|
||||
struct snd_soc_dai wm8510_dai = {
|
||||
.name = "WM8510 HiFi",
|
||||
static struct snd_soc_dai_driver wm8510_dai = {
|
||||
.name = "wm8510-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
|
@ -531,21 +531,15 @@ struct snd_soc_dai wm8510_dai = {
|
|||
.ops = &wm8510_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm8510_dai);
|
||||
|
||||
static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8510_resume(struct platform_device *pdev)
|
||||
static int wm8510_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int i;
|
||||
u8 data[2];
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
|
@ -561,86 +555,109 @@ static int wm8510_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the WM8510 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int wm8510_init(struct snd_soc_device *socdev,
|
||||
enum snd_soc_control_type control)
|
||||
static int wm8510_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int ret = 0;
|
||||
struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
codec->name = "WM8510";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->set_bias_level = wm8510_set_bias_level;
|
||||
codec->dai = &wm8510_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
|
||||
codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
|
||||
|
||||
if (codec->reg_cache == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8510->control_type);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wm8510_reset(codec);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "wm8510: failed to create pcms\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* power on device */
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
snd_soc_add_controls(codec, wm8510_snd_controls,
|
||||
ARRAY_SIZE(wm8510_snd_controls));
|
||||
wm8510_add_widgets(codec);
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
kfree(codec->reg_cache);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_device *wm8510_socdev;
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
/*
|
||||
* WM8510 2 wire address is 0x1a
|
||||
*/
|
||||
|
||||
static int wm8510_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
/* power down chip */
|
||||
static int wm8510_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_device *socdev = wm8510_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
kfree(wm8510);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
|
||||
.probe = wm8510_probe,
|
||||
.remove = wm8510_remove,
|
||||
.suspend = wm8510_suspend,
|
||||
.resume = wm8510_resume,
|
||||
.set_bias_level = wm8510_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(wm8510_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default =wm8510_reg,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8510_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct wm8510_priv *wm8510;
|
||||
int ret;
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
codec->control_data = i2c;
|
||||
wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
|
||||
if (wm8510 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = wm8510_init(socdev, SND_SOC_I2C);
|
||||
wm8510->control_type = SND_SOC_SPI;
|
||||
spi_set_drvdata(spi, wm8510);
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_wm8510, &wm8510_dai, 1);
|
||||
if (ret < 0)
|
||||
pr_err("failed to initialise WM8510\n");
|
||||
|
||||
kfree(wm8510);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8510_i2c_remove(struct i2c_client *client)
|
||||
static int __devexit wm8510_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_codec *codec = i2c_get_clientdata(client);
|
||||
kfree(codec->reg_cache);
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver wm8510_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8510",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8510_spi_probe,
|
||||
.remove = __devexit_p(wm8510_spi_remove),
|
||||
};
|
||||
#endif /* CONFIG_SPI_MASTER */
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm8510_priv *wm8510;
|
||||
int ret;
|
||||
|
||||
wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
|
||||
if (wm8510 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, wm8510);
|
||||
wm8510->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_wm8510, &wm8510_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(wm8510);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int wm8510_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -652,165 +669,44 @@ MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
|
|||
|
||||
static struct i2c_driver wm8510_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "WM8510 I2C Codec",
|
||||
.name = "wm8510-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8510_i2c_probe,
|
||||
.remove = wm8510_i2c_remove,
|
||||
.remove = __devexit_p(wm8510_i2c_remove),
|
||||
.id_table = wm8510_i2c_id,
|
||||
};
|
||||
|
||||
static int wm8510_add_i2c_device(struct platform_device *pdev,
|
||||
const struct wm8510_setup_data *setup)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&wm8510_i2c_driver);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "can't add i2c driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = setup->i2c_address;
|
||||
strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
|
||||
|
||||
adapter = i2c_get_adapter(setup->i2c_bus);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "can't get i2c adapter %d\n",
|
||||
setup->i2c_bus);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
client = i2c_new_device(adapter, &info);
|
||||
i2c_put_adapter(adapter);
|
||||
if (!client) {
|
||||
dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
|
||||
(unsigned int)info.addr);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_driver:
|
||||
i2c_del_driver(&wm8510_i2c_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8510_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_device *socdev = wm8510_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int ret;
|
||||
|
||||
codec->control_data = spi;
|
||||
|
||||
ret = wm8510_init(socdev, SND_SOC_SPI);
|
||||
if (ret < 0)
|
||||
dev_err(&spi->dev, "failed to initialise WM8510\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wm8510_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver wm8510_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8510",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8510_spi_probe,
|
||||
.remove = __devexit_p(wm8510_spi_remove),
|
||||
};
|
||||
#endif /* CONFIG_SPI_MASTER */
|
||||
|
||||
static int wm8510_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct wm8510_setup_data *setup;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
|
||||
|
||||
setup = socdev->codec_data;
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
wm8510_socdev = socdev;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
if (setup->i2c_address) {
|
||||
ret = wm8510_add_i2c_device(pdev, setup);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
if (setup->spi) {
|
||||
ret = spi_register_driver(&wm8510_spi_driver);
|
||||
if (ret != 0)
|
||||
printk(KERN_ERR "can't add spi driver");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
kfree(codec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int wm8510_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec->control_data)
|
||||
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&wm8510_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8510_spi_driver);
|
||||
#endif
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8510 = {
|
||||
.probe = wm8510_probe,
|
||||
.remove = wm8510_remove,
|
||||
.suspend = wm8510_suspend,
|
||||
.resume = wm8510_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
|
||||
|
||||
static int __init wm8510_modinit(void)
|
||||
{
|
||||
return snd_soc_register_dai(&wm8510_dai);
|
||||
int ret = 0;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&wm8510_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&wm8510_spi_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(wm8510_modinit);
|
||||
|
||||
static void __exit wm8510_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&wm8510_dai);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&wm8510_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8510_spi_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(wm8510_exit);
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue