diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/Makefile | 1 | ||||
-rw-r--r-- | sound/soc/codecs/ab3550.c | 426 | ||||
-rw-r--r-- | sound/soc/codecs/ab3550.h | 3 | ||||
-rw-r--r-- | sound/soc/codecs/av8100_audio.c | 218 | ||||
-rw-r--r-- | sound/soc/codecs/av8100_audio.h | 7 | ||||
-rw-r--r-- | sound/soc/codecs/cg29xx.c | 558 | ||||
-rw-r--r-- | sound/soc/codecs/cg29xx.h | 5 |
7 files changed, 582 insertions, 636 deletions
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 99bbb804537..363acbb047b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -92,6 +92,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-wm2000-objs := wm2000.o snd-soc-wm9090-objs := wm9090.o +obj-$(CONFIG_SND_SOC_AB3550) += snd-soc-ab3550.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB3550) += snd-soc-ab3550.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o diff --git a/sound/soc/codecs/ab3550.c b/sound/soc/codecs/ab3550.c index e0a4c6d7f06..1b5abd2c4e2 100644 --- a/sound/soc/codecs/ab3550.c +++ b/sound/soc/codecs/ab3550.c @@ -2,7 +2,8 @@ * Copyright (C) ST-Ericsson SA 2010 * * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>, - * Roger Nilsson <roger.xr.nilsson@stericsson.com> + * Roger Nilsson <roger.xr.nilsson@stericsson.com>, + * Ola Lilja <ola.o.lilja@stericsson.com> * for ST-Ericsson. * * License terms: @@ -36,8 +37,11 @@ #define I2C_BANK 0 +/* codec private data */ +struct ab3550_codec_dai_data { +}; + static struct device *ab3550_dev; -static struct snd_soc_codec *ab3550_codec; static u8 virtual_regs[] = { 0, 0 @@ -620,9 +624,6 @@ enum enum_link { LINK = 1 }; -static unsigned int ab3550_read_reg(struct snd_soc_codec *codec, - unsigned int reg); - static enum enum_power get_widget_power_status(enum enum_widget widget) { u8 val; @@ -861,105 +862,6 @@ static enum enum_widget adder_sink_translate(u8 reg) } } -/** - This function is only called by the SOC framework to - set registers associated to the mixer controls. -*/ -static int ab3550_write_reg(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - if (reg < MIC_BIAS1 || reg > INTERFACE_SWAP) - return -EINVAL; - switch (reg) { - u8 diff, oldval; - case ANALOG_LOOP_PGA1: - case ANALOG_LOOP_PGA2: { - enum enum_widget apga = reg == ANALOG_LOOP_PGA1 ? - widget_apga1 : widget_apga2; - - oldval = read_reg(reg); - diff = value ^ oldval; - - /* The APGA is to be turned on/off. - The power bit and the other bits in the - same register won't be changed at the same time - since they belong to different controls. - */ - if (diff & (1 << APGAx_PWR_SHIFT)) { - power_widget_locked(value >> APGAx_PWR_SHIFT & 1, - apga); - } else if (diff & APGAx_MUX_MASK) { - enum enum_widget old_source = - apga_source_translate(oldval); - enum enum_widget new_source = - apga_source_translate(value); - update_widgets_link(UNLINK, old_source, apga, - reg, APGAx_MUX_MASK, 0); - update_widgets_link(LINK, new_source, apga, - reg, APGAx_MUX_MASK, value); - } else { - set_reg(reg, value); - } - break; - } - - case APGA1_ADDER: - case APGA2_ADDER: { - int i; - enum enum_widget apga; - enum enum_widget apga_dst[] = { - widget_auxo2, widget_auxo1, widget_ear, widget_spkr, - widget_line2, widget_line1 - }; - - apga = adder_sink_translate(reg); - oldval = read_reg(reg); - diff = value ^ oldval; - for (i = 0; diff; i++) { - if (!(diff & 1 << i)) - continue; - diff ^= 1 << i; - update_widgets_link(value >> i & 1, apga, apga_dst[i], - reg, 1 << i, value); - } - break; - } - - case EAR_ADDER: - case AUXO1_ADDER: - case AUXO2_ADDER: - case SPKR_ADDER: - case LINE1_ADDER: - case LINE2_ADDER: { - int i; - enum enum_widget widgets[] = { - widget_dac1, widget_dac2, widget_dac3, - }; - oldval = read_reg(reg); - diff = value ^ oldval; - for (i = 0; diff; i++) { - if (!(diff & 1 << i)) - continue; - diff ^= 1 << i; - update_widgets_link(value >> i & 1, widgets[i], - adder_sink_translate(reg), - reg, 1 << i, value); - } - break; - } - - default: - set_reg(reg, value); - } - return 0; -} - -static unsigned int ab3550_read_reg(struct snd_soc_codec *codec, - unsigned int reg) -{ - return read_reg(reg); -} - static int ab3550_add_widgets(struct snd_soc_codec *codec) { snd_soc_dapm_new_controls(codec, ab3550_dapm_widgets, @@ -1011,7 +913,7 @@ static int ab3550_add_controls(struct snd_soc_codec *codec) pr_debug("%s: %s called.\n", __FILE__, __func__); for (i = 0; i < n; i++) { - err = snd_ctl_add(codec->card, snd_ctl_new1( + err = snd_ctl_add(codec->card->snd_card, snd_ctl_new1( &ab3550_snd_controls[i], codec)); if (err < 0) { pr_err("%s failed to add control No.%d of %d.\n", @@ -1052,7 +954,7 @@ static int ab3550_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - !dai->capture.active : !dai->playback.active) { + !dai->capture_active : !dai->playback_active) { mask_set_reg(reg, I2Sx_SR_MASK, val << I2Sx_SR_SHIFT); if ((read_reg(reg) & I2Sx_MODE_MASK) == 0) { @@ -1067,7 +969,7 @@ static int ab3550_pcm_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - dai->playback.active : dai->capture.active) { + dai->playback_active : dai->capture_active) { dev_err(ab3550_dev, "%s: A %s stream is already active.\n", __func__, @@ -1097,21 +999,20 @@ static int ab3550_pcm_prepare(struct snd_pcm_substream *substream, } static void ab3550_pcm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai* dai) + struct snd_soc_dai *dai) { u8 iface = dai->id == 0 ? INTERFACE0 : INTERFACE1; dev_info(ab3550_dev, "%s called.\n", __func__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) power_for_playback(POWER_OFF, dai->id); - } else { + else power_for_capture(POWER_OFF, dai->id); - } - if (!dai->playback.active && !dai->capture.active && + if (!dai->playback_active && !dai->capture_active && (read_reg(iface) & I2Sx_MODE_MASK) == 0) mask_set_reg(iface, MASTER_GENx_PWR_MASK, 0); } -static int ab3550_set_dai_sysclk(struct snd_soc_dai* dai, int clk_id, +static int ab3550_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { return 0; @@ -1138,7 +1039,7 @@ static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) "0x%x\n", fmt); return -EINVAL; } - if (codec_dai->playback.active && codec_dai->capture.active) { + if (codec_dai->playback_active && codec_dai->capture_active) { if ((read_reg(iface) & I2Sx_MODE_MASK) == val) return 0; else { @@ -1152,19 +1053,19 @@ static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } -struct snd_soc_dai ab3550_codec_dai[] = { +struct snd_soc_dai_driver ab3550_dai_drv[] = { { - .name = "ab3550_0", + .name = "ab3550-codec-dai.0", .id = 0, .playback = { - .stream_name = "ab3550_0", + .stream_name = "AB3550.0 Playback", .channels_min = 2, .channels_max = 2, .rates = AB3550_SUPPORTED_RATE, .formats = AB3550_SUPPORTED_FMT, }, .capture = { - .stream_name = "ab3550_0", + .stream_name = "AB3550.0 Capture", .channels_min = 2, .channels_max = 2, .rates = AB3550_SUPPORTED_RATE, @@ -1181,20 +1082,19 @@ struct snd_soc_dai ab3550_codec_dai[] = { } }, .symmetric_rates = 1, - .private_data = NULL }, { - .name = "ab3550_1", + .name = "ab3550-codec-dai.1", .id = 1, .playback = { - .stream_name = "ab3550_1", + .stream_name = "AB3550.1 Playback", .channels_min = 2, .channels_max = 2, .rates = AB3550_SUPPORTED_RATE, .formats = AB3550_SUPPORTED_FMT, }, .capture = { - .stream_name = "ab3550_1", + .stream_name = "AB3550.0 Capture", .channels_min = 2, .channels_max = 2, .rates = AB3550_SUPPORTED_RATE, @@ -1211,61 +1111,45 @@ struct snd_soc_dai ab3550_codec_dai[] = { } }, .symmetric_rates = 1, - .private_data = NULL } }; -EXPORT_SYMBOL_GPL(ab3550_codec_dai); +EXPORT_SYMBOL_GPL(ab3550_dai_drv); -static int ab3550_codec_probe(struct platform_device *pdev) +static int ab3550_codec_probe(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); int ret; - dev_info(&pdev->dev, "%s called. pdev = %p.\n", __func__, pdev); - if (!ab3550_codec) { - dev_err(&pdev->dev, "%s: Codec device not registered.\n", - __func__); - return -EAGAIN; - } - socdev->card->codec = ab3550_codec; - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&pdev->dev, "%s: Failed to create a new card " - "and new PCMs. error %d\n", __func__, ret); - goto err; - } + pr_info("%s: Enter.\n", __func__); + /* Add controls */ - if (ab3550_add_controls(ab3550_codec) < 0) - goto err; - ab3550_add_widgets(ab3550_codec); - return 0; + if (ab3550_add_controls(codec) < 0) + return ret; -err: - snd_soc_free_pcms(socdev); - return ret; + /* Add widgets */ + ab3550_add_widgets(codec); + + return 0; } -static int ab3550_codec_remove(struct platform_device *pdev) +static int ab3550_codec_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); + snd_soc_dapm_free(codec); + return 0; } #ifdef CONFIG_PM -static int ab3550_codec_suspend(struct platform_device *pdev, - pm_message_t state) +static int ab3550_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) { - dev_dbg(ab3550_dev, "%s : pdev=%p.\n", __func__, pdev); mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0); + return 0; } -static int ab3550_codec_resume(struct platform_device *pdev) +static int ab3550_codec_resume(struct snd_soc_codec *codec) { - dev_dbg(ab3550_dev, "%s : pdev=%p.\n", __func__, pdev); mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0xff); + return 0; } #else @@ -1273,14 +1157,114 @@ static int ab3550_codec_resume(struct platform_device *pdev) #define ab3550_codec_suspend NULL #endif -struct snd_soc_codec_device soc_codec_dev_ab3550 = { +/* + * This function is only called by the SOC framework to + * set registers associated to the mixer controls. + */ +static int ab3550_codec_write_reg(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + if (reg < MIC_BIAS1 || reg > INTERFACE_SWAP) + return -EINVAL; + switch (reg) { + u8 diff, oldval; + case ANALOG_LOOP_PGA1: + case ANALOG_LOOP_PGA2: { + enum enum_widget apga = reg == ANALOG_LOOP_PGA1 ? + widget_apga1 : widget_apga2; + + oldval = read_reg(reg); + diff = value ^ oldval; + + /* The APGA is to be turned on/off. + * The power bit and the other bits in the + * same register won't be changed at the same time + * since they belong to different controls. + */ + if (diff & (1 << APGAx_PWR_SHIFT)) { + power_widget_locked(value >> APGAx_PWR_SHIFT & 1, + apga); + } else if (diff & APGAx_MUX_MASK) { + enum enum_widget old_source = + apga_source_translate(oldval); + enum enum_widget new_source = + apga_source_translate(value); + update_widgets_link(UNLINK, old_source, apga, + reg, APGAx_MUX_MASK, 0); + update_widgets_link(LINK, new_source, apga, + reg, APGAx_MUX_MASK, value); + } else { + set_reg(reg, value); + } + break; + } + + case APGA1_ADDER: + case APGA2_ADDER: { + int i; + enum enum_widget apga; + enum enum_widget apga_dst[] = { + widget_auxo2, widget_auxo1, widget_ear, widget_spkr, + widget_line2, widget_line1 + }; + + apga = adder_sink_translate(reg); + oldval = read_reg(reg); + diff = value ^ oldval; + for (i = 0; diff; i++) { + if (!(diff & 1 << i)) + continue; + diff ^= 1 << i; + update_widgets_link(value >> i & 1, apga, apga_dst[i], + reg, 1 << i, value); + } + break; + } + + case EAR_ADDER: + case AUXO1_ADDER: + case AUXO2_ADDER: + case SPKR_ADDER: + case LINE1_ADDER: + case LINE2_ADDER: { + int i; + enum enum_widget widgets[] = { + widget_dac1, widget_dac2, widget_dac3, + }; + oldval = read_reg(reg); + diff = value ^ oldval; + for (i = 0; diff; i++) { + if (!(diff & 1 << i)) + continue; + diff ^= 1 << i; + update_widgets_link(value >> i & 1, widgets[i], + adder_sink_translate(reg), + reg, 1 << i, value); + } + break; + } + + default: + set_reg(reg, value); + } + return 0; +} + +static unsigned int ab3550_codec_read_reg(struct snd_soc_codec *codec, + unsigned int reg) +{ + return read_reg(reg); +} + +static struct snd_soc_codec_driver ab3550_codec_drv = { .probe = ab3550_codec_probe, .remove = ab3550_codec_remove, .suspend = ab3550_codec_suspend, - .resume = ab3550_codec_resume + .resume = ab3550_codec_resume, + .read = ab3550_codec_read_reg, + .write = ab3550_codec_write_reg, }; - -EXPORT_SYMBOL_GPL(soc_codec_dev_ab3550); +EXPORT_SYMBOL_GPL(ab3550_codec_drv); static inline void init_playback_route(void) { @@ -1334,13 +1318,34 @@ static inline void init_capture_gain(void) mask_set_reg(TX_DIGITAL_PGA1, TXDPGAx_MASK, 0x0f << TXDPGAx_SHIFT); } -static int __init ab3550_platform_probe(struct platform_device *pdev) +static __devinit int ab3550_codec_drv_probe(struct platform_device *pdev) { + struct ab3550_codec_dai_data *codec_drvdata; int ret = 0; - int i; u8 reg; - pr_debug("%s invoked with pdev = %p.\n", __func__, pdev); + pr_debug("%s: Enter.\n", __func__); + + pr_info("%s: Init codec private data.\n", __func__); + codec_drvdata = kzalloc(sizeof(struct ab3550_codec_dai_data), GFP_KERNEL); + if (codec_drvdata == NULL) + return -ENOMEM; + + /* TODO: Add private data to codec_drvdata */ + + platform_set_drvdata(pdev, codec_drvdata); + + pr_info("%s: Register codec.\n", __func__); + ret = snd_soc_register_codec(&pdev->dev, &ab3550_codec_drv, &ab3550_dai_drv[0], 2); + if (ret < 0) { + pr_debug("%s: Error: Failed to register codec (ret = %d).\n", + __func__, + ret); + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + return ret; + } + ab3550_dev = &pdev->dev; /* Initialize the codec registers */ for (reg = AB3550_FIRST_REG; reg <= AB3550_LAST_REG; reg++) @@ -1354,102 +1359,69 @@ static int __init ab3550_platform_probe(struct platform_device *pdev) init_capture_gain(); memset(&pm_stack, 0, sizeof(pm_stack)); - ab3550_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (ab3550_codec == NULL) - return -ENOMEM; - ab3550_codec->name = "AB3550"; - ab3550_codec->owner = THIS_MODULE; - ab3550_codec->dai = ab3550_codec_dai; - ab3550_codec->num_dai = 2; - ab3550_codec->read = ab3550_read_reg; - ab3550_codec->write = ab3550_write_reg; - ab3550_codec->reg_cache_size = 0; - ab3550_codec->reg_cache = NULL; - INIT_LIST_HEAD(&ab3550_codec->dapm_widgets); - INIT_LIST_HEAD(&ab3550_codec->dapm_paths); - mutex_init(&ab3550_codec->mutex); - ret = snd_soc_register_codec(ab3550_codec); - if (ret) { - dev_err(ab3550_dev, "%s: Failed to register codec: %d.\n", - __func__, ret); - kfree(ab3550_codec); - } - - for (i = 0; !ret && i < ARRAY_SIZE(ab3550_codec_dai); i++) - ret = snd_soc_register_dai(ab3550_codec_dai + i); - if (ret && i == 1) { - snd_soc_unregister_codec(ab3550_codec); - kfree(ab3550_codec); - } - - return ret; + return 0; } -static int ab3550_platform_remove(struct platform_device *pdev) +static int __devexit ab3550_codec_drv_remove(struct platform_device *pdev) { - int i; - - pr_debug("%s called.\n", __func__); mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0); - for (i = 0; i < ARRAY_SIZE(ab3550_codec_dai); i++) - snd_soc_unregister_dai(ab3550_codec_dai + i); - snd_soc_unregister_codec(ab3550_codec); - kfree(ab3550_codec); + ab3550_dev = NULL; + + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + return 0; } -static int ab3550_platform_suspend(struct platform_device *pdev, +static int ab3550_codec_drv_suspend(struct platform_device *pdev, pm_message_t state) { return 0; } -static int ab3550_platform_resume(struct platform_device *pdev) +static int ab3550_codec_drv_resume(struct platform_device *pdev) { return 0; } -static struct platform_driver ab3550_platform_driver = { - .driver = { - .name = "ab3550-codec", - .owner = THIS_MODULE, +static struct platform_driver ab3550_codec_platform_drv = { + .driver = { + .name = "ab3550-codec", + .owner = THIS_MODULE, }, - .probe = ab3550_platform_probe, - .remove = ab3550_platform_remove, - .suspend = ab3550_platform_suspend, - .resume = ab3550_platform_resume, + .probe = ab3550_codec_drv_probe, + .remove = __devexit_p(ab3550_codec_drv_remove), + .suspend = ab3550_codec_drv_suspend, + .resume = ab3550_codec_drv_resume, }; -static int __devinit ab3550_init(void) +static int __devinit ab3550_codec_platform_drv_init(void) { - int ret1; + int ret; - pr_debug("%s called.\n", __func__); + pr_debug("%s: Enter.\n", __func__); ab3550_dev = NULL; - ab3550_codec = NULL; - /* Register codec platform driver. */ - ret1 = platform_driver_register(&ab3550_platform_driver); - if (ret1 < 0) { - pr_debug("%s: Error %d: Failed to register codec platform " - "driver.\n", __func__, ret1); - } - return ret1; + + ret = platform_driver_register(&ab3550_codec_platform_drv); + if (ret != 0) + pr_err("Failed to register AB3550 platform driver (%d)!\n", ret); + + return ret; } -static void __devexit ab3550_exit(void) +static void __exit ab3550_codec_platform_drv_exit(void) { - pr_debug("u8500_ab3550_init: Enter.\n"); + pr_debug("%s: Enter.\n", __func__); - /* Register codec platform driver. */ - pr_debug("%s: Un-register codec platform driver.\n", __func__); - platform_driver_unregister(&ab3550_platform_driver); + platform_driver_unregister(&ab3550_codec_platform_drv); } -module_init(ab3550_init); -module_exit(ab3550_exit); + +module_init(ab3550_codec_platform_drv_init); +module_exit(ab3550_codec_platform_drv_exit); MODULE_DESCRIPTION("AB3550 Codec driver"); MODULE_AUTHOR("Xie Xiaolei <xie.xiaolei@stericsson.com>"); diff --git a/sound/soc/codecs/ab3550.h b/sound/soc/codecs/ab3550.h index f553fdce96b..fe9c77b1a62 100644 --- a/sound/soc/codecs/ab3550.h +++ b/sound/soc/codecs/ab3550.h @@ -13,9 +13,6 @@ #ifndef AB3550_CODEC_REGISTERS_H #define AB3550_CODEC_REGISTERS_H -extern struct snd_soc_dai ab3550_codec_dai[2]; -extern struct snd_soc_codec_device soc_codec_dev_ab3550; - #define AB3550_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) diff --git a/sound/soc/codecs/av8100_audio.c b/sound/soc/codecs/av8100_audio.c index d85a8ca24e5..6fa6261c9fd 100644 --- a/sound/soc/codecs/av8100_audio.c +++ b/sound/soc/codecs/av8100_audio.c @@ -1,7 +1,7 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Ola Lilja (ola.o.lilja@stericsson.com) + * Author: Ola Lilja <ola.o.lilja@stericsson.com> * for ST-Ericsson. * * License terms: @@ -29,7 +29,7 @@ #include "av8100_audio.h" /* codec private data */ -struct av8100_codec_private_data { +struct av8100_codec_dai_data { struct hdmi_audio_settings as; }; @@ -178,43 +178,51 @@ static int av8100_codec_send_audio_infoframe(struct hdmi_audio_settings *as) return 0; } -int av8100_codec_change_hdmi_audio_settings(struct snd_pcm_substream *substream, +static struct av8100_codec_dai_data *get_dai_data_codec(struct snd_soc_codec *codec, + int dai_id) +{ + struct av8100_codec_dai_data *dai_data = snd_soc_codec_get_drvdata(codec); + return &dai_data[dai_id]; +} + +static struct av8100_codec_dai_data *get_dai_data(struct snd_soc_dai *codec_dai) +{ + return get_dai_data_codec(codec_dai->codec, codec_dai->id); +} + +int av8100_codec_change_hdmi_audio_settings(struct snd_soc_dai *codec_dai, struct hdmi_audio_settings *as) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->card->codec; - struct av8100_codec_private_data *av8100_codec_priv = codec->private_data; + struct av8100_codec_dai_data *dai_data = get_dai_data(codec_dai); pr_debug("%s: Enter.\n", __func__); - av8100_codec_priv->as.audio_coding_type = as->audio_coding_type; - av8100_codec_priv->as.audio_channel_count = as->audio_channel_count; - av8100_codec_priv->as.sampling_frequency = as->sampling_frequency; - av8100_codec_priv->as.sample_size = as->sample_size; - av8100_codec_priv->as.channel_allocation = as->channel_allocation; - av8100_codec_priv->as.level_shift_value = as->level_shift_value; - av8100_codec_priv->as.downmix_inhibit = as->downmix_inhibit; + dai_data->as.audio_coding_type = as->audio_coding_type; + dai_data->as.audio_channel_count = as->audio_channel_count; + dai_data->as.sampling_frequency = as->sampling_frequency; + dai_data->as.sample_size = as->sample_size; + dai_data->as.channel_allocation = as->channel_allocation; + dai_data->as.level_shift_value = as->level_shift_value; + dai_data->as.downmix_inhibit = as->downmix_inhibit; return 0; } static int av8100_codec_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, - struct snd_soc_dai *dai) + struct snd_soc_dai *codec_dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->card->codec; - struct av8100_codec_private_data *av8100_codec_priv = codec->private_data; + struct av8100_codec_dai_data *dai_data = get_dai_data(codec_dai); pr_debug("%s: Enter.\n", __func__); - av8100_codec_send_audio_infoframe(&av8100_codec_priv->as); + av8100_codec_send_audio_infoframe(&dai_data->as); return 0; } static int av8100_codec_pcm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *codec_dai) { int ret; @@ -234,7 +242,7 @@ static int av8100_codec_pcm_startup(struct snd_pcm_substream *substream, } static void av8100_codec_pcm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *codec_dai) { pr_debug("%s: Enter.\n", __func__); } @@ -301,11 +309,10 @@ static int av8100_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -struct snd_soc_dai av8100_codec_dai[] = { - { - .name = "av8100_0", +struct snd_soc_dai_driver av8100_dai_drv = { + .name = "av8100-codec-dai", .playback = { - .stream_name = "av8100_0", + .stream_name = "AV8100 Playback", .channels_min = 1, .channels_max = 8, .rates = AV8100_SUPPORTED_RATE, @@ -321,145 +328,124 @@ struct snd_soc_dai av8100_codec_dai[] = { .set_fmt = av8100_codec_set_dai_fmt, } }, - } }; -EXPORT_SYMBOL_GPL(av8100_codec_dai); +EXPORT_SYMBOL_GPL(av8100_dai_drv); -static unsigned int av8100_codec_read(struct snd_soc_codec *codec, - unsigned int ctl) +static int av8100_codec_probe(struct snd_soc_codec *codec) { - pr_debug("%s: Enter.\n", __func__); + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); return 0; } -static int av8100_codec_write(struct snd_soc_codec *codec, - unsigned int ctl, - unsigned int value) +static int av8100_codec_remove(struct snd_soc_codec *codec) { - pr_debug("%s: Enter.\n", __func__); + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); return 0; } -static int av8100_codec_probe(struct platform_device *pdev) +static int av8100_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; - struct av8100_codec_private_data *av8100_codec_priv; - int ret; + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); - pr_info("%s: Enter (pdev = %p).\n", __func__, pdev); + return 0; +} - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - codec->name = "AV8100"; - codec->owner = THIS_MODULE; - codec->dai = &av8100_codec_dai[0]; - codec->num_dai = 1; - codec->read = av8100_codec_read; - codec->write = av8100_codec_write; - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); +static int av8100_codec_resume(struct snd_soc_codec *codec) +{ + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + + return 0; +} + +struct snd_soc_codec_driver av8100_codec_drv = { + .probe = av8100_codec_probe, + .remove = av8100_codec_remove, + .suspend = av8100_codec_suspend, + .resume = av8100_codec_resume +}; + +static __devinit int av8100_codec_drv_probe(struct platform_device *pdev) +{ + struct av8100_codec_dai_data *dai_data; + int ret; + + pr_debug("%s: Enter.\n", __func__); pr_info("%s: Init codec private data..\n", __func__); - av8100_codec_priv = kzalloc(sizeof(struct av8100_codec_private_data), GFP_KERNEL); - if (av8100_codec_priv == NULL) + dai_data = kzalloc(sizeof(struct av8100_codec_dai_data), GFP_KERNEL); + if (dai_data == NULL) return -ENOMEM; /* Setup hdmi_audio_settings default values */ - av8100_codec_priv->as.audio_coding_type = AV8100_CODEC_CT_IEC60958_PCM; - av8100_codec_priv->as.audio_channel_count = AV8100_CODEC_CC_2CH; - av8100_codec_priv->as.sampling_frequency = AV8100_CODEC_SF_48KHZ; - av8100_codec_priv->as.sample_size = AV8100_CODEC_SS_16BIT; - av8100_codec_priv->as.channel_allocation = AV8100_CODEC_CA_FL_FR; - av8100_codec_priv->as.level_shift_value = AV8100_CODEC_LSV_0DB; - av8100_codec_priv->as.downmix_inhibit = false; - - codec->private_data = &av8100_codec_priv; - mutex_init(&codec->mutex); - socdev->card->codec = codec; - - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + dai_data[0].as.audio_coding_type = AV8100_CODEC_CT_IEC60958_PCM; + dai_data[0].as.audio_channel_count = AV8100_CODEC_CC_2CH; + dai_data[0].as.sampling_frequency = AV8100_CODEC_SF_48KHZ; + dai_data[0].as.sample_size = AV8100_CODEC_SS_16BIT; + dai_data[0].as.channel_allocation = AV8100_CODEC_CA_FL_FR; + dai_data[0].as.level_shift_value = AV8100_CODEC_LSV_0DB; + dai_data[0].as.downmix_inhibit = false; + + platform_set_drvdata(pdev, dai_data); + + pr_info("%s: Register codec.\n", __func__); + ret = snd_soc_register_codec(&pdev->dev, &av8100_codec_drv, &av8100_dai_drv, 1); if (ret < 0) { - pr_err("%s: Error: to create new PCMs. error %d\n", + pr_debug("%s: Error: Failed to register codec (ret = %d).\n", __func__, ret); - goto err; + return ret; } return 0; - -err: - kfree(codec); - return ret; -} - -static int av8100_codec_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - pr_debug("%s: Enter (pdev = %p).\n", __func__, pdev); - - if (!codec) - return 0; - - snd_soc_free_pcms(socdev); - kfree(socdev->card->codec); - - return 0; -} - -static int av8100_codec_suspend(struct platform_device *pdev, - pm_message_t state) -{ - pr_debug("%s: Enter (pdev = %p).\n", __func__, pdev); - - return 0; } -static int av8100_codec_resume(struct platform_device *pdev) +static int __devexit av8100_codec_drv_remove(struct platform_device *pdev) { - pr_debug("%s: Enter (pdev = %p).\n", __func__, pdev); - + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); return 0; } -struct snd_soc_codec_device soc_codec_dev_av8100 = { - .probe = av8100_codec_probe, - .remove = av8100_codec_remove, - .suspend = av8100_codec_suspend, - .resume = av8100_codec_resume +static const struct platform_device_id av8100_codec_platform_id[] = { + { "av8100-codec", 0 }, + { } +}; +MODULE_DEVICE_TABLE(platform, av8100_codec_platform_id); + +static struct platform_driver av8100_codec_platform_drv = { + .driver = { + .name = "av8100-codec", + .owner = THIS_MODULE, + }, + .probe = av8100_codec_drv_probe, + .remove = __devexit_p(av8100_codec_drv_remove), + .id_table = av8100_codec_platform_id, }; -EXPORT_SYMBOL_GPL(soc_codec_dev_av8100); -static int __devinit av8100_codec_init(void) +static int __devinit av8100_codec_platform_drv_init(void) { int ret; pr_debug("%s: Enter.\n", __func__); - pr_info("%s: Register codec-dai.\n", __func__); - ret = snd_soc_register_dai(&av8100_codec_dai[0]); - if (ret < 0) { - pr_debug("%s: Error: Failed to register codec-dai (ret = %d).\n", - __func__, - ret); + ret = platform_driver_register(&av8100_codec_platform_drv); + if (ret != 0) { + pr_err("Failed to register AV8100 platform driver (%d)!\n", ret); } return ret; } -static void av8100_codec_exit(void) +static void __exit av8100_codec_platform_drv_exit(void) { pr_debug("%s: Enter.\n", __func__); - snd_soc_unregister_dai(&av8100_codec_dai[0]); + platform_driver_unregister(&av8100_codec_platform_drv); } -module_init(av8100_codec_init); -module_exit(av8100_codec_exit); +module_init(av8100_codec_platform_drv_init); +module_exit(av8100_codec_platform_drv_exit); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/codecs/av8100_audio.h b/sound/soc/codecs/av8100_audio.h index bcd2f26ddc8..4c269c14106 100644 --- a/sound/soc/codecs/av8100_audio.h +++ b/sound/soc/codecs/av8100_audio.h @@ -1,7 +1,7 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Ola Lilja ola.o.lilja@stericsson.com, + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * for ST-Ericsson. * * License terms: @@ -151,10 +151,7 @@ struct hdmi_audio_settings { bool downmix_inhibit; }; -extern struct snd_soc_dai av8100_codec_dai[]; -extern struct snd_soc_codec_device soc_codec_dev_av8100; - -int av8100_codec_change_hdmi_audio_settings(struct snd_pcm_substream *substream, +int av8100_codec_change_hdmi_audio_settings(struct snd_soc_dai *dai, struct hdmi_audio_settings *as); #endif /* AV8100_CODEC_H */ diff --git a/sound/soc/codecs/cg29xx.c b/sound/soc/codecs/cg29xx.c index a138f2c211a..bbd3adcfe5b 100644 --- a/sound/soc/codecs/cg29xx.c +++ b/sound/soc/codecs/cg29xx.c @@ -1,7 +1,8 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Roger Nilsson roger.xr.nilsson@stericsson.com + * Author: Roger Nilsson <roger.xr.nilsson@stericsson.com>, + * Ola Lilja <ola.o.lilja@stericsson.com> * for ST-Ericsson. * * License terms: @@ -78,108 +79,59 @@ static struct cg29xx_codec codec_private = { .session = 0, }; -static struct snd_soc_codec *cg29xx_codec; - -static struct cg29xx_dai - cg29xx_dai_private[CG29XX_NBR_OF_DAI] = { - { - .tx_active = 0, - .rx_active = 0, - .input_select = 0, - .output_select = 0, - .config = { - .port = PORT_0_I2S, - .conf.i2s.mode = DAI_MODE_SLAVE, - .conf.i2s.half_period = HALF_PER_DUR_16, - .conf.i2s.channel_sel = CHANNEL_SELECTION_BOTH, - .conf.i2s.sample_rate = SAMPLE_RATE_48, - .conf.i2s.word_width = WORD_WIDTH_32 - } - }, - { - .tx_active = 0, - .rx_active = 0, - .input_select = 0, - .output_select = 0, - .config = { - .port = PORT_1_I2S_PCM, - .conf.i2s_pcm.mode = DAI_MODE_SLAVE, - .conf.i2s_pcm.slot_0_dir = DAI_DIR_B_RX_A_TX, - .conf.i2s_pcm.slot_1_dir = DAI_DIR_B_TX_A_RX, - .conf.i2s_pcm.slot_2_dir = DAI_DIR_B_RX_A_TX, - .conf.i2s_pcm.slot_3_dir = DAI_DIR_B_RX_A_TX, - .conf.i2s_pcm.slot_0_used = true, - .conf.i2s_pcm.slot_1_used = false, - .conf.i2s_pcm.slot_2_used = false, - .conf.i2s_pcm.slot_3_used = false, - .conf.i2s_pcm.slot_0_start = 0, - .conf.i2s_pcm.slot_1_start = 16, - .conf.i2s_pcm.slot_2_start = 32, - .conf.i2s_pcm.slot_3_start = 48, - .conf.i2s_pcm.protocol = PORT_PROTOCOL_PCM, - .conf.i2s_pcm.ratio = STREAM_RATIO_FM48_VOICE16, - .conf.i2s_pcm.duration = SYNC_DURATION_32, - .conf.i2s_pcm.clk = BIT_CLK_512, - .conf.i2s_pcm.sample_rate = SAMPLE_RATE_16, - } - }, -}; - -static struct snd_soc_dai_ops cg29xx_dai_ops = { +static struct snd_soc_dai_ops cg29xx_dai_drv_dai_ops = { .startup = cg29xx_dai_startup, .prepare = cg29xx_dai_prepare, .hw_params = cg29xx_dai_hw_params, - .shutdown = cg29xx_dai_shutdown, + .shutdown = cg29xx_dai_shutdown, .set_sysclk = cg29xx_set_dai_sysclk, .set_fmt = cg29xx_set_dai_fmt, .set_tdm_slot = cg29xx_set_tdm_slot }; -struct snd_soc_dai cg29xx_codec_dai[] = { +struct snd_soc_dai_driver cg29xx_dai_drv[] = { { - .name = "cg29xx_0", - .id = 0, - .playback = { - .stream_name = "cg29xx_0_pb", - .channels_min = 2, - .channels_max = 2, - .rates = CG29XX_SUPPORTED_RATE, - .formats = CG29XX_SUPPORTED_FMT, - }, - .capture = { - .stream_name = "cg29xx_0_cap", - .channels_min = 2, - .channels_max = 2, - .rates = CG29XX_SUPPORTED_RATE, - .formats = CG29XX_SUPPORTED_FMT, - }, - .ops = &cg29xx_dai_ops, - .symmetric_rates = 1, - .private_data = &cg29xx_dai_private[0] + .name = "cg29xx-codec-dai.0", + .id = 0, + .playback = { + .stream_name = "CG29xx.0 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE, + .formats = CG29XX_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "CG29xx.0 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE, + .formats = CG29XX_SUPPORTED_FMT, + }, + .ops = &cg29xx_dai_drv_dai_ops, + .symmetric_rates = 1, }, { - .name = "cg29xx_1", - .id = 1, - .playback = { - .stream_name = "cg29xx_1_pb", - .channels_min = 1, - .channels_max = 2, - .rates = CG29XX_SUPPORTED_RATE_PCM, - .formats = CG29XX_SUPPORTED_FMT, - }, - .capture = { - .stream_name = "cg29xx_1_cap", - .channels_min = 1, - .channels_max = 2, - .rates = CG29XX_SUPPORTED_RATE_PCM, - .formats = CG29XX_SUPPORTED_FMT, - }, - .ops = &cg29xx_dai_ops, - .symmetric_rates = 1, - .private_data = &cg29xx_dai_private[1] + .name = "cg29xx-codec-dai.1", + .id = 1, + .playback = { + .stream_name = "CG29xx.1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE_PCM, + .formats = CG29XX_SUPPORTED_FMT, + }, + .capture = { + .stream_name = "CG29xx.1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CG29XX_SUPPORTED_RATE_PCM, + .formats = CG29XX_SUPPORTED_FMT, + }, + .ops = &cg29xx_dai_drv_dai_ops, + .symmetric_rates = 1, } }; -EXPORT_SYMBOL_GPL(cg29xx_codec_dai); +EXPORT_SYMBOL_GPL(cg29xx_dai_drv); static const char *enum_ifs_input_select[] = { "BT_SCO", "FM_RX" @@ -220,20 +172,30 @@ static struct snd_kcontrol_new cg29xx_snd_controls[] = { SOC_ENUM("If1 Output Select", if1_output_select), }; -static int cg29xx_set_dai_sysclk( - struct snd_soc_dai *codec_dai, - int clk_id, - unsigned int freq, int dir) + +static struct cg29xx_codec_dai_data *get_dai_data_codec(struct snd_soc_codec *codec, + int dai_id) +{ + struct cg29xx_codec_dai_data *codec_drvdata = snd_soc_codec_get_drvdata(codec); + return &codec_drvdata[dai_id]; +} + +static struct cg29xx_codec_dai_data *get_dai_data(struct snd_soc_dai *codec_dai) +{ + return get_dai_data_codec(codec_dai->codec, codec_dai->id); +} + +static int cg29xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, + unsigned int freq, int dir) { return 0; } -static int cg29xx_set_dai_fmt( - struct snd_soc_dai *codec_dai, - unsigned int fmt) +static int cg29xx_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) { - struct cg29xx_dai *private = - codec_dai->private_data; + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); unsigned int prot; unsigned int msel; @@ -242,20 +204,20 @@ static int cg29xx_set_dai_fmt( switch (prot) { case SND_SOC_DAIFMT_I2S: - if (private->config.port != PORT_0_I2S) { + if (dai_data->config.port != PORT_0_I2S) { pr_err("cg29xx_dai: unsupported DAI format 0x%x\n", fmt); return -EINVAL; } if (msel == SND_SOC_DAIFMT_CBM_CFM) - private->config.conf.i2s.mode = DAI_MODE_MASTER; + dai_data->config.conf.i2s.mode = DAI_MODE_MASTER; else - private->config.conf.i2s.mode = DAI_MODE_SLAVE; + dai_data->config.conf.i2s.mode = DAI_MODE_SLAVE; break; case SND_SOC_DAIFMT_DSP_A: - if (private->config.port != PORT_1_I2S_PCM || + if (dai_data->config.port != PORT_1_I2S_PCM || msel == SND_SOC_DAIFMT_CBM_CFM) { pr_err("cg29xx_dai: unsupported DAI format 0x%x\n", fmt); @@ -270,57 +232,54 @@ static int cg29xx_set_dai_fmt( return 0; } -static int cg29xx_set_tdm_slot( - struct snd_soc_dai *dai, - unsigned int tx_mask, - unsigned int rx_mask, - int slots, - int slot_width) +static int cg29xx_set_tdm_slot(struct snd_soc_dai *codec_dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) { - struct cg29xx_dai *private = - dai->private_data; + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); - if (private->config.port != PORT_1_I2S_PCM) + if (dai_data->config.port != PORT_1_I2S_PCM) return -EINVAL; - private->config.conf.i2s_pcm.slot_0_used = + dai_data->config.conf.i2s_pcm.slot_0_used = (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT0_SHIFT) ? true : false; - private->config.conf.i2s_pcm.slot_1_used = + dai_data->config.conf.i2s_pcm.slot_1_used = (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT1_SHIFT) ? true : false; - private->config.conf.i2s_pcm.slot_2_used = + dai_data->config.conf.i2s_pcm.slot_2_used = (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT2_SHIFT) ? true : false; - private->config.conf.i2s_pcm.slot_3_used = + dai_data->config.conf.i2s_pcm.slot_3_used = (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT3_SHIFT) ? true : false; - private->config.conf.i2s_pcm.slot_0_start = 0; - private->config.conf.i2s_pcm.slot_1_start = slot_width; - private->config.conf.i2s_pcm.slot_2_start = 2 * slot_width; - private->config.conf.i2s_pcm.slot_3_start = 3 * slot_width; + dai_data->config.conf.i2s_pcm.slot_0_start = 0; + dai_data->config.conf.i2s_pcm.slot_1_start = slot_width; + dai_data->config.conf.i2s_pcm.slot_2_start = 2 * slot_width; + dai_data->config.conf.i2s_pcm.slot_3_start = 3 * slot_width; return 0; } -static int cg29xx_configure_endp( - struct cg29xx_dai *dai, - enum cg2900_audio_endpoint_id endpid) +static int cg29xx_configure_endp(struct cg29xx_codec_dai_data *dai_data, + enum cg2900_audio_endpoint_id endpid) { struct cg2900_endpoint_config config; int err; enum cg2900_dai_sample_rate dai_sr; enum cg2900_endpoint_sample_rate endp_sr; - switch (dai->config.port) { + switch (dai_data->config.port) { default: case PORT_0_I2S: - dai_sr = dai->config.conf.i2s.sample_rate; + dai_sr = dai_data->config.conf.i2s.sample_rate; break; case PORT_1_I2S_PCM: - dai_sr = dai->config.conf.i2s_pcm.sample_rate; + dai_sr = dai_data->config.conf.i2s_pcm.sample_rate; break; } @@ -359,17 +318,16 @@ static int cg29xx_configure_endp( return err; } -static int cg29xx_stop_if( - struct cg29xx_dai *dai, - enum cg29xx_dai_direction direction) +static int cg29xx_stop_if(struct cg29xx_codec_dai_data *dai_data, + enum cg29xx_dai_direction direction) { int err = 0; unsigned int *stream; if (direction == CG29XX_DAI_DIRECTION_TX) - stream = &dai->tx_active; + stream = &dai_data->tx_active; else - stream = &dai->rx_active; + stream = &dai_data->rx_active; if (*stream) { err = cg2900_audio_stop_stream( @@ -380,29 +338,28 @@ static int cg29xx_stop_if( } else { pr_err("asoc cg29xx - %s - Failed to stop stream on interface %d.\n", __func__, - dai->config.port); + dai_data->config.port); } } return err; } -static int cg29xx_start_if( - struct cg29xx_dai *dai, - enum cg29xx_dai_direction direction) +static int cg29xx_start_if(struct cg29xx_codec_dai_data *dai_data, + enum cg29xx_dai_direction direction) { enum cg2900_audio_endpoint_id if_endpid; enum cg2900_audio_endpoint_id endpid; unsigned int *stream; int err; - if (dai->config.port == PORT_0_I2S) + if (dai_data->config.port == PORT_0_I2S) if_endpid = ENDPOINT_PORT_0_I2S; else if_endpid = ENDPOINT_PORT_1_I2S_PCM; if (direction == CG29XX_DAI_DIRECTION_RX) { - switch (dai->output_select) { + switch (dai_data->output_select) { default: case 0: endpid = ENDPOINT_BT_SCO_INOUT; @@ -410,9 +367,9 @@ static int cg29xx_start_if( case 1: endpid = ENDPOINT_FM_TX; } - stream = &dai->rx_active; + stream = &dai_data->rx_active; } else { - switch (dai->input_select) { + switch (dai_data->input_select) { default: case 0: endpid = ENDPOINT_BT_SCO_INOUT; @@ -421,7 +378,7 @@ static int cg29xx_start_if( endpid = ENDPOINT_FM_RX; } - stream = &dai->tx_active; + stream = &dai_data->tx_active; } if (*stream) { @@ -436,7 +393,7 @@ static int cg29xx_start_if( if_endpid, endpid); - err = cg29xx_configure_endp(dai, endpid); + err = cg29xx_configure_endp(dai_data, endpid); if (err) { pr_err("asoc cg29xx - %s - Configure endpoint id: %d failed.\n", @@ -446,8 +403,7 @@ static int cg29xx_start_if( return err; } - err = cg2900_audio_start_stream( - codec_private.session, + err = cg2900_audio_start_stream(codec_private.session, if_endpid, endpid, stream); @@ -455,9 +411,8 @@ static int cg29xx_start_if( return err; } -static int cg29xx_dai_startup( - struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int cg29xx_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { int err = 0; @@ -467,10 +422,10 @@ static int cg29xx_dai_startup( return err; } -static int cg29xx_dai_prepare( - struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int cg29xx_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) { + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); int err = 0; enum cg29xx_dai_direction direction; @@ -479,15 +434,15 @@ static int cg29xx_dai_prepare( else direction = CG29XX_DAI_DIRECTION_TX; - err = cg29xx_start_if(dai->private_data, direction); + err = cg29xx_start_if(dai_data, direction); return err; } -static void cg29xx_dai_shutdown( - struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void cg29xx_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) { + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); enum cg29xx_dai_direction direction; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -495,15 +450,14 @@ static void cg29xx_dai_shutdown( else direction = CG29XX_DAI_DIRECTION_TX; - (void) cg29xx_stop_if(dai->private_data, direction); + (void) cg29xx_stop_if(dai_data, direction); } -static int cg29xx_dai_hw_params( - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params, - struct snd_soc_dai *dai) +static int cg29xx_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *codec_dai) { - struct cg29xx_dai *private = dai->private_data; + struct cg29xx_codec_dai_data *dai_data = get_dai_data(codec_dai); enum cg2900_dai_fs_duration duration = SYNC_DURATION_32; enum cg2900_dai_bit_clk bclk = BIT_CLK_512; int sr; @@ -512,7 +466,7 @@ static int cg29xx_dai_hw_params( pr_debug("cg29xx asoc - %s called. Port: %d.\n", __func__, - private->config.port); + dai_data->config.port); switch (params_rate(hw_params)) { case 8000: @@ -537,47 +491,50 @@ static int cg29xx_dai_hw_params( return -EINVAL; } - if (private->config.port == PORT_0_I2S) { - private->config.conf.i2s.sample_rate = sr; + if (dai_data->config.port == PORT_0_I2S) { + dai_data->config.conf.i2s.sample_rate = sr; } else { - private->config.conf.i2s_pcm.sample_rate = sr; - private->config.conf.i2s_pcm.duration = duration; - private->config.conf.i2s_pcm.clk = bclk; - private->config.conf.i2s_pcm.ratio = ratio; + dai_data->config.conf.i2s_pcm.sample_rate = sr; + dai_data->config.conf.i2s_pcm.duration = duration; + dai_data->config.conf.i2s_pcm.clk = bclk; + dai_data->config.conf.i2s_pcm.ratio = ratio; } - if (!(private->tx_active | private->rx_active)) { + if (!(dai_data->tx_active | dai_data->rx_active)) { err = cg2900_audio_set_dai_config( codec_private.session, - &private->config); + &dai_data->config); pr_debug("asoc cg29xx: cg2900_audio_set_dai_config" "on port %d completed with result: %d.\n", - private->config.port, + dai_data->config.port, err); } return err; } -static unsigned int cg29xx_codec_read( - struct snd_soc_codec *codec, - unsigned int reg) +static unsigned int cg29xx_codec_read(struct snd_soc_codec *codec, + unsigned int reg) { + struct cg29xx_codec_dai_data *dai_data; switch (reg) { - case INTERFACE0_INPUT_SELECT: - return cg29xx_dai_private[0].input_select; + dai_data = get_dai_data_codec(codec, 0); + return dai_data->input_select; case INTERFACE1_INPUT_SELECT: - return cg29xx_dai_private[1].input_select; + dai_data = get_dai_data_codec(codec, 1); + return dai_data->input_select; case INTERFACE0_OUTPUT_SELECT: - return cg29xx_dai_private[0].output_select; + dai_data = get_dai_data_codec(codec, 0); + return dai_data->output_select; case INTERFACE1_OUTPUT_SELECT: - return cg29xx_dai_private[1].output_select; + dai_data = get_dai_data_codec(codec, 1); + return dai_data->output_select; default: return 0; @@ -586,59 +543,57 @@ static unsigned int cg29xx_codec_read( return 0; } -static int cg29xx_codec_write( - struct snd_soc_codec *codec, - unsigned int reg, - unsigned int value) +static int cg29xx_codec_write(struct snd_soc_codec *codec, + unsigned int reg, + unsigned int value) { - int old_value; - struct cg29xx_dai *dai; + struct cg29xx_codec_dai_data *dai_data; enum cg29xx_dai_direction direction; bool restart_if = false; + int old_value; switch (reg) { - case INTERFACE0_INPUT_SELECT: - dai = &cg29xx_dai_private[0]; + dai_data = get_dai_data_codec(codec, 0); direction = CG29XX_DAI_DIRECTION_TX; - old_value = dai->input_select; - dai->input_select = value; + old_value = dai_data->input_select; + dai_data->input_select = value; - if ((old_value ^ value) && dai->tx_active) + if ((old_value ^ value) && dai_data->tx_active) restart_if = true; break; case INTERFACE1_INPUT_SELECT: - dai = &cg29xx_dai_private[1]; + dai_data = get_dai_data_codec(codec, 1); direction = CG29XX_DAI_DIRECTION_TX; - old_value = dai->input_select; - dai->input_select = value; + old_value = dai_data->input_select; + dai_data->input_select = value; - if ((old_value ^ value) && dai->tx_active) + if ((old_value ^ value) && dai_data->tx_active) restart_if = true; break; case INTERFACE0_OUTPUT_SELECT: - dai = &cg29xx_dai_private[0]; + dai_data = get_dai_data_codec(codec, 0); direction = CG29XX_DAI_DIRECTION_RX; - old_value = dai->output_select; - dai->output_select = value; + old_value = dai_data->output_select; + dai_data->output_select = value; - if ((old_value ^ value) && dai->rx_active) + if ((old_value ^ value) && dai_data->rx_active) restart_if = true; break; case INTERFACE1_OUTPUT_SELECT: - dai = &cg29xx_dai_private[1]; + dai_data = get_dai_data_codec(codec, 1); direction = CG29XX_DAI_DIRECTION_RX; - old_value = dai->output_select; - dai->output_select = value; + old_value = dai_data->output_select; + dai_data->output_select = value; - if ((old_value ^ value) && dai->rx_active) + if ((old_value ^ value) && dai_data->rx_active) restart_if = true; break; @@ -647,132 +602,173 @@ static int cg29xx_codec_write( } if (restart_if) { - (void) cg29xx_stop_if(dai, direction); - (void) cg29xx_start_if(dai, direction); + (void) cg29xx_stop_if(dai_data, direction); + (void) cg29xx_start_if(dai_data, direction); } return 0; } -static int cg29xx_soc_probe(struct platform_device *pdev) +static int cg29xx_codec_probe(struct snd_soc_codec *codec) { - int err; - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - socdev->card->codec = cg29xx_codec; - - err = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (err < 0) { - pr_err("cg29xx asoc - snd_soc_new_pcms failed with error: %d\n", - err); - goto err1; - } + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); snd_soc_add_controls( - cg29xx_codec, + codec, cg29xx_snd_controls, ARRAY_SIZE(cg29xx_snd_controls)); return 0; - - snd_soc_free_pcms(socdev); -err1: - return err; } -static int cg29xx_soc_remove(struct platform_device *pdev) +static int cg29xx_codec_remove(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_soc_free_pcms(socdev); + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); return 0; } -static int cg29xx_soc_suspend(struct platform_device *pdev, - pm_message_t state) +static int cg29xx_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) { + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + return 0; } -static int cg29xx_soc_resume(struct platform_device *pdev) +static int cg29xx_codec_resume(struct snd_soc_codec *codec) { + pr_debug("%s: Enter (codec->name = %s).\n", __func__, codec->name); + return 0; } -struct snd_soc_codec_device soc_codec_dev_cg29xx = { - .probe = cg29xx_soc_probe, - .remove = cg29xx_soc_remove, - .suspend = cg29xx_soc_suspend, - .resume = cg29xx_soc_resume +struct snd_soc_codec_driver cg29xx_codec_drv = { + .probe = cg29xx_codec_probe, + .remove = cg29xx_codec_remove, + .suspend = cg29xx_codec_suspend, + .resume = cg29xx_codec_resume, + .read = cg29xx_codec_read, + .write = cg29xx_codec_write, }; -EXPORT_SYMBOL_GPL(soc_codec_dev_cg29xx); -static int __init cg29xx_init(void) +static __devinit int cg29xx_codec_drv_probe(struct platform_device *pdev) { - int err; - int i; + int ret; + struct cg29xx_codec_dai_data *dai_data; - cg29xx_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + pr_debug("%s: Enter.\n", __func__); - if (!cg29xx_codec) + pr_info("%s: Init codec private data..\n", __func__); + dai_data = kzalloc(CG29XX_NBR_OF_DAI * sizeof(struct cg29xx_codec_dai_data), + GFP_KERNEL); + if (dai_data == NULL) return -ENOMEM; - cg29xx_codec->name = "CG29XX"; - cg29xx_codec->owner = THIS_MODULE; - cg29xx_codec->dai = cg29xx_codec_dai; - cg29xx_codec->num_dai = CG29XX_NBR_OF_DAI; - cg29xx_codec->read = cg29xx_codec_read; - cg29xx_codec->write = cg29xx_codec_write; - INIT_LIST_HEAD(&cg29xx_codec->dapm_widgets); - INIT_LIST_HEAD(&cg29xx_codec->dapm_paths); - mutex_init(&cg29xx_codec->mutex); - - err = snd_soc_register_codec(cg29xx_codec); + dai_data[0].tx_active = 0; + dai_data[0].rx_active = 0; + dai_data[0].input_select = 0; + dai_data[0].output_select = 0; + dai_data[0].config.port = PORT_0_I2S; + dai_data[0].config.conf.i2s.mode = DAI_MODE_SLAVE; + dai_data[0].config.conf.i2s.half_period = HALF_PER_DUR_16; + dai_data[0].config.conf.i2s.channel_sel = CHANNEL_SELECTION_BOTH; + dai_data[0].config.conf.i2s.sample_rate = SAMPLE_RATE_48; + dai_data[0].config.conf.i2s.word_width = WORD_WIDTH_32; + dai_data[1].tx_active = 0; + dai_data[1].rx_active = 0; + dai_data[1].input_select = 0; + dai_data[1].output_select = 0; + dai_data[1].config.port = PORT_1_I2S_PCM; + dai_data[1].config.conf.i2s_pcm.mode = DAI_MODE_SLAVE; + dai_data[1].config.conf.i2s_pcm.slot_0_dir = DAI_DIR_B_RX_A_TX; + dai_data[1].config.conf.i2s_pcm.slot_1_dir = DAI_DIR_B_TX_A_RX; + dai_data[1].config.conf.i2s_pcm.slot_2_dir = DAI_DIR_B_RX_A_TX; + dai_data[1].config.conf.i2s_pcm.slot_3_dir = DAI_DIR_B_RX_A_TX; + dai_data[1].config.conf.i2s_pcm.slot_0_used = true; + dai_data[1].config.conf.i2s_pcm.slot_1_used = false; + dai_data[1].config.conf.i2s_pcm.slot_2_used = false; + dai_data[1].config.conf.i2s_pcm.slot_3_used = false; + dai_data[1].config.conf.i2s_pcm.slot_0_start = 0; + dai_data[1].config.conf.i2s_pcm.slot_1_start = 16; + dai_data[1].config.conf.i2s_pcm.slot_2_start = 32; + dai_data[1].config.conf.i2s_pcm.slot_3_start = 48; + dai_data[1].config.conf.i2s_pcm.protocol = PORT_PROTOCOL_PCM; + dai_data[1].config.conf.i2s_pcm.ratio = STREAM_RATIO_FM48_VOICE16; + dai_data[1].config.conf.i2s_pcm.duration = SYNC_DURATION_32; + dai_data[1].config.conf.i2s_pcm.clk = BIT_CLK_512; + dai_data[1].config.conf.i2s_pcm.sample_rate = SAMPLE_RATE_16; + + platform_set_drvdata(pdev, dai_data); + + pr_info("%s: Register codec.\n", __func__); + ret = snd_soc_register_codec(&pdev->dev, &cg29xx_codec_drv, &cg29xx_dai_drv[0], 2); + if (ret < 0) { + pr_debug("%s: Error: Failed to register codec (ret = %d).\n", + __func__, + ret); + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); + return ret; + } - if (err) { - pr_err( - "asoc cg29xx - snd_soc_register_codec" - " failed with error: %d.\n", - err); + return 0; +} - return err; - } +static int __devexit cg29xx_codec_drv_remove(struct platform_device *pdev) +{ + (void)cg2900_audio_close(&codec_private.session); - for (i = 0; i < CG29XX_NBR_OF_DAI; i++) { - mutex_init(&cg29xx_dai_private[i].mutex); + snd_soc_unregister_codec(&pdev->dev); + kfree(platform_get_drvdata(pdev)); - err = snd_soc_register_dai(&cg29xx_codec_dai[i]); + return 0; +} - if (err) { - pr_err( - "asoc cg29xx - snd_soc_register_dai" - " failed with error: %d.\n", - err); - return err; - } - } +static int cg29xx_codec_drv_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} - return err; +static int cg29xx_codec_drv_resume(struct platform_device *pdev) +{ + return 0; } -module_init(cg29xx_init); -static void __exit cg29xx_exit(void) +static struct platform_driver cg29xx_codec_platform_drv = { + .driver = { + .name = "cg29xx-codec", + .owner = THIS_MODULE, + }, + .probe = cg29xx_codec_drv_probe, + .remove = __devexit_p(cg29xx_codec_drv_remove), + .suspend = cg29xx_codec_drv_suspend, + .resume = cg29xx_codec_drv_resume, +}; + + +static int __devinit cg29xx_codec_platform_drv_init(void) { - int i; + int ret; - (void) cg2900_audio_close(&codec_private.session); + pr_debug("%s: Enter.\n", __func__); - if (cg29xx_codec) { - snd_soc_unregister_codec(cg29xx_codec); - kfree(cg29xx_codec); - cg29xx_codec = NULL; - } + ret = platform_driver_register(&cg29xx_codec_platform_drv); + if (ret != 0) + pr_err("Failed to register CG29xx platform driver (%d)!\n", ret); + + return ret; +} + +static void __exit cg29xx_codec_platform_drv_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); - for (i = 0; i < CG29XX_NBR_OF_DAI; i++) - snd_soc_unregister_dai(&cg29xx_codec_dai[i]); + platform_driver_unregister(&cg29xx_codec_platform_drv); } -module_exit(cg29xx_exit); -MODULE_DESCRIPTION("CG29xx codec driver"); -MODULE_LICENSE("GPL v2"); + +module_init(cg29xx_codec_platform_drv_init); +module_exit(cg29xx_codec_platform_drv_exit); + +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/codecs/cg29xx.h b/sound/soc/codecs/cg29xx.h index e7ced7f9e24..5e73bc4b65a 100644 --- a/sound/soc/codecs/cg29xx.h +++ b/sound/soc/codecs/cg29xx.h @@ -15,10 +15,7 @@ #include <linux/mfd/cg2900_audio.h> -extern struct snd_soc_dai cg29xx_codec_dai[]; -extern struct snd_soc_codec_device soc_codec_dev_cg29xx; - -struct cg29xx_dai { +struct cg29xx_codec_dai_data { struct mutex mutex; unsigned int rx_active; unsigned int tx_active; |