diff options
author | Ola Lilja <ola.o.lilja@stericsson.com> | 2010-11-25 18:02:05 +0100 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@stericsson.com> | 2011-09-19 15:14:42 +0200 |
commit | fe1e8e8b6b8637eda7fb33dc9b98a4d3ec9d7f37 (patch) | |
tree | 6891167a081639c7f2d429fa5dae54edc478bb49 | |
parent | 0185e37f689cecb899655c4c39bc4797993e0bf7 (diff) |
Ux500 ASoC: Multi-component support.
The Ux500 driver is now rewritten to for multi-component support.
This includes the Ux500 platform driver, the AV8100 codec-driver,
the CG29xx codec-driver and the AB3550 codec-driver. There is now
one common machine-driver for all codecs, and all three codecs can
be activated indepentantly.
Change-Id: I4c942b040306a1d6033ee4d80f9368917cb9b4d3
Signed-off-by: Ola Lilja <ola.o.lilja@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/9767
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/10280
-rw-r--r-- | sound/soc/Kconfig | 2 | ||||
-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 | ||||
-rw-r--r-- | sound/soc/ux500/Kconfig | 35 | ||||
-rw-r--r-- | sound/soc/ux500/Makefile | 30 | ||||
-rw-r--r-- | sound/soc/ux500/u8500.c | 199 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_ab3550.c | 205 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_ab3550.h | 19 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_av8100.c | 127 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_av8100.h | 19 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_cg29xx.c | 161 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_cg29xx.h | 19 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_dai.c | 526 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_dai.h | 8 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_pcm.c | 101 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_pcm.h | 4 |
21 files changed, 1260 insertions, 1413 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index a2d1f2c52a9..adcbc43276d 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -11,7 +11,7 @@ menuconfig SND_SOC If you want ASoC support, you should say Y here and also to the specific driver for your SoC platform below. - + ASoC provides power efficient ALSA support for embedded battery powered SoC based systems like PDA's, Phones and Personal Media Players. 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; diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig index 52944f6fa64..2b1327240fe 100644 --- a/sound/soc/ux500/Kconfig +++ b/sound/soc/ux500/Kconfig @@ -2,45 +2,40 @@ # Ux500 SoC audio configuration # -config SND_SOC_UX500 +menuconfig SND_SOC_UX500 bool "SoC Audio support for Ux500 platform" depends on SND_SOC && STM_I2S && STM_MSP_I2S default n help - Say Y if you want to add support for the codecs attached to - the I2S of the Ux500. You will also need - to select the audio codec to be supported in the driver. - -choice - prompt "Codec to be used in Ux500 ASoC driver" - depends on SND_SOC_UX500 - default SND_SOC_CG29XX + Say Y if you want to add support for the Ux500 platform. config SND_SOC_UX500_AB3550 - bool "AB3550" - depends on AB3550_CORE + bool "Codec - AB3550" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && AB3550_CORE select SND_SOC_AB3550 + default n help - Say Y if you want to use AB3550 codec (Petronella MSA). + Say Y if you want to include AB3550 codec (Petronella MSA). config SND_SOC_UX500_CG29XX - bool "CG29xx" + bool "Codec - CG29xx" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && MFD_CG2900_AUDIO select SND_SOC_CG29XX + default n help - Say Y if you want to use CG29xx codec (Combo chip). + Say Y if you want to include CG29xx codec (Combo chip). config SND_SOC_UX500_AV8100 - bool "AV8100" - depends on AV8100 + bool "Codec - AV8100" + depends on SND_SOC_UX500 && (UX500_SOC_DB8500 || UX500_SOC_DB5500) && AV8100 select SND_SOC_AV8100 + default n help - Say Y if you want to use AV8100 codec (HDMI chip). - -endchoice + Say Y if you want to include AV8100 codec (HDMI chip). config SND_SOC_UX500_DEBUG bool "Activate Ux500 platform debug-mode (pr_debug)" - depends on SND_SOC && STM_I2S && STM_MSP_I2S + depends on SND_SOC_UX500 default n help Say Y if you want to add debug level prints for Ux500 code-files. diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile index 3a9091efd35..e7917509681 100644 --- a/sound/soc/ux500/Makefile +++ b/sound/soc/ux500/Makefile @@ -6,12 +6,28 @@ CFLAGS_ux500_msp_dai.o := -DDEBUG CFLAGS_ux500_av8100.o := -DDEBUG endif -snd-soc-ux500-objs := ux500_pcm.o ux500_msp_dai.o -snd-soc-ux500-ab3550-objs := ux500_ab3550.o -snd-soc-ux500-cg29xx-objs := ux500_cg29xx.o +ifdef CONFIG_SND_SOC_UX500_AB3550 +snd-soc-ux500-av8100-objs := ux500_ab3550.o +obj-$(CONFIG_SND_SOC_UX500_AB3550) += ux500_ab3550.o +endif + +ifdef CONFIG_SND_SOC_UX500_AV8100 snd-soc-ux500-av8100-objs := ux500_av8100.o +obj-$(CONFIG_SND_SOC_UX500_AV8100) += ux500_av8100.o +endif + +ifdef CONFIG_SND_SOC_UX500_CG29XX +snd-soc-ux500-av8100-objs := ux500_cg29xx.o +obj-$(CONFIG_SND_SOC_UX500_CG29XX) += ux500_cg29xx.o +endif + +#ifdef UX500_SOC_DB8500 +snd-soc-u8500-objs := u8500.o +obj-y += ux500_pcm.o ux500_msp_dai.o snd-soc-u8500.o +#endif + +ifdef UX500_SOC_DB5500 +snd-soc-u8500-objs := u5500.o +obj-$(UX500_SOC_DB5500) += ux500_pcm.o ux500_msp_dai.o snd-soc-u5500.o +endif -obj-$(CONFIG_SND_SOC_UX500) += snd-soc-ux500.o -obj-$(CONFIG_SND_SOC_UX500_AB3550) += snd-soc-ux500-ab3550.o -obj-$(CONFIG_SND_SOC_UX500_CG29XX) += snd-soc-ux500-cg29xx.o -obj-$(CONFIG_SND_SOC_UX500_AV8100) += snd-soc-ux500-av8100.o diff --git a/sound/soc/ux500/u8500.c b/sound/soc/ux500/u8500.c new file mode 100644 index 00000000000..54fb9a1584e --- /dev/null +++ b/sound/soc/ux500/u8500.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja (ola.o.lilja@stericsson.com) + * for ST-Ericsson. + * + * License terms: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/io.h> +#include <sound/soc.h> + +#include "ux500_pcm.h" +#include "ux500_msp_dai.h" + +#include <linux/spi/spi.h> +#include <sound/initval.h> + +#ifdef CONFIG_SND_SOC_UX500_AB3550 +#include "ux500_ab3550.h" +#endif + +#ifdef CONFIG_SND_SOC_UX500_AV8100 +#include "ux500_av8100.h" +#endif + +#ifdef CONFIG_SND_SOC_UX500_CG29XX +#include "ux500_cg29xx.h" +#endif + + +static struct platform_device *u8500_platform_dev; + +/* Create dummy devices for platform drivers */ + +static struct platform_device ux500_pcm = { + .name = "ux500-pcm", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; + +#ifdef CONFIG_SND_SOC_UX500_AV8100 +static struct platform_device av8100_codec = { + .name = "av8100-codec", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; +#endif + +#ifdef CONFIG_SND_SOC_UX500_CG29XX +static struct platform_device cg29xx_codec = { + .name = "cg29xx-codec", + .id = 0, + .dev = { + .platform_data = NULL, + }, +}; +#endif + +/* Define the whole U8500 soundcard, linking platform to the codec-drivers */ +struct snd_soc_dai_link u8500_dai_links[] = { + #ifdef CONFIG_SND_SOC_UX500_AV8100 + { + .name = "hdmi", + .stream_name = "hdmi", + .cpu_dai_name = "i2s.2", + .codec_dai_name = "av8100-codec-dai", + .platform_name = "ux500-pcm.0", + .codec_name = "av8100-codec.0", + .init = NULL, + .ops = ux500_av8100_ops, + }, + #endif + #ifdef CONFIG_SND_SOC_UX500_AB3550 + { + .name = "ab3550_0", + .stream_name = "ab3550_0", + .cpu_dai_name = "i2s.0", + .codec_dai_name = "ab3550-codec-dai.0", + .platform_name = "ux500-pcm.0", + .codec_name = "ab3550-codec.11", + .init = NULL, + .ops = ux500_ab3550_ops, + }, + { + .name = "ab3550_1", + .stream_name = "ab3550_1", + .cpu_dai_name = "i2s.1", + .codec_dai_name = "ab3550-codec-dai.1", + .platform_name = "ux500-pcm.0", + .codec_name = "ab3550-codec.11", + .init = NULL, + .ops = ux500_ab3550_ops, + }, + #endif + #ifdef CONFIG_SND_SOC_UX500_CG29XX + { + .name = "cg29xx_0", + .stream_name = "cg29xx_0", + .cpu_dai_name = "i2s.0", + .codec_dai_name = "cg29xx-codec-dai.1", + .platform_name = "ux500-pcm.0", + .codec_name = "cg29xx-codec.0", + .init = NULL, + .ops = ux500_cg29xx_ops, + }, + #endif +}; + +static struct snd_soc_card u8500_drvdata = { + .name = "U8500-card", + .probe = NULL, + .dai_link = u8500_dai_links, + .num_links = ARRAY_SIZE(u8500_dai_links), +}; + +static int __init u8500_soc_init(void) +{ + int ret = 0; + + pr_debug("%s: Enter.\n", __func__); + + #ifdef CONFIG_SND_SOC_UX500_AV8100 + pr_debug("%s: Register device to generate a probe for AV8100 codec.\n", + __func__); + platform_device_register(&av8100_codec); + #endif + + #ifdef CONFIG_SND_SOC_UX500_CG29XX + pr_debug("%s: Register device to generate a probe for CG29xx codec.\n", + __func__); + platform_device_register(&cg29xx_codec); + #endif + + pr_debug("%s: Register device to generate a probe for Ux500-pcm platform.\n", + __func__); + platform_device_register(&ux500_pcm); + + pr_debug("%s: Allocate platform device 'soc-audio'.\n", + __func__); + u8500_platform_dev = platform_device_alloc("soc-audio", -1); + if (!u8500_platform_dev) + return -ENOMEM; + + pr_debug("%s: Card %s: num_links = %d\n", + __func__, + u8500_drvdata.name, + u8500_drvdata.num_links); + pr_debug("%s: Card %s: DAI-link 0: name = %s\n", + __func__, + u8500_drvdata.name, + u8500_drvdata.dai_link[0].name); + pr_debug("%s: Card %s: DAI-link 0: stream_name = %s\n", + __func__, + u8500_drvdata.name, + u8500_drvdata.dai_link[0].stream_name); + + pr_debug("%s: Card %s: Set platform drvdata.\n", + __func__, + u8500_drvdata.name); + platform_set_drvdata(u8500_platform_dev, &u8500_drvdata); + u8500_drvdata.dev = &u8500_platform_dev->dev; + + pr_debug("%s: Card %s: Add platform device.\n", + __func__, + u8500_drvdata.name); + ret = platform_device_add(u8500_platform_dev); + if (ret) { + pr_err("%s: Error: Failed to add platform device (%s).\n", + __func__, + u8500_drvdata.name); + platform_device_put(u8500_platform_dev); + } + + return ret; +} + +static void __exit u8500_soc_exit(void) +{ + pr_debug("%s: Enter.\n", __func__); + + pr_debug("%s: Unregister platform device (%s).\n", + __func__, + u8500_drvdata.name); + platform_device_unregister(u8500_platform_dev); +} + +module_init(u8500_soc_init); +module_exit(u8500_soc_exit); + +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/ux500/ux500_ab3550.c b/sound/soc/ux500/ux500_ab3550.c index 103e8b2cfb5..7e144c0e4d2 100644 --- a/sound/soc/ux500/ux500_ab3550.c +++ b/sound/soc/ux500/ux500_ab3550.c @@ -12,196 +12,65 @@ * by the Free Software Foundation. */ -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/io.h> #include <sound/soc.h> - -#include "ux500_pcm.h" -#include "ux500_msp_dai.h" -#include "mach/hardware.h" #include "../codecs/ab3550.h" -static struct platform_device *ux500_ab3550_platform_device; - -#define AB3550_DAI_FMT_I2S_M (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM) -#define AB3550_DAI_FMT_I2S_S (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS) -#define AB3550_DAI_FMT AB3550_DAI_FMT_I2S_S - static int ux500_ab3550_startup(struct snd_pcm_substream *substream) { - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Enter\n", - __func__); + pr_debug("%s: Enter.\n", __func__); + return 0; } static void ux500_ab3550_shutdown(struct snd_pcm_substream *substream) { - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Enter\n", - __func__); + pr_debug("%s: Enter.\n", __func__); } -static int ux500_ab3550_hw_params( - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int ux500_ab3550_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; - int ifid, ret = 0; - - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Enter\n", - __func__); - - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: substream->pcm->name = %s\n" - "substream->pcm->id = %s.\n" - "substream->name = %s.\n" - "substream->number = %d.\n", - __func__, - substream->pcm->name, - substream->pcm->id, - substream->name, - substream->number); - - for (ifid = 0; ifid < ARRAY_SIZE(ab3550_codec_dai); ifid++) { - if (strcmp(codec_dai->name, ab3550_codec_dai[ifid].name) == 0) - break; - } - - if (codec_dai->ops->set_fmt) { - ret = snd_soc_dai_set_fmt(codec_dai, AB3550_DAI_FMT); - if (ret < 0) { - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: snd_soc_dai_set_fmt failed with %d.\n", - __func__, - ret); - return ret; - } - - ret = snd_soc_dai_set_fmt(cpu_dai, AB3550_DAI_FMT); - - if (ret < 0) { - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: snd_soc_dai_set_fmt" - " failed with %d.\n", __func__, ret); - return ret; - } - } - - return ret; -} - -static struct snd_soc_ops ux500_ab3550_ops = { - .startup = ux500_ab3550_startup, - .shutdown = ux500_ab3550_shutdown, - .hw_params = ux500_ab3550_hw_params, -}; - -struct snd_soc_dai_link ux500_ab3550_dai_links[] = { - { - .name = "ab3550_0", - .stream_name = "ab3550_0", - .cpu_dai = &ux500_msp_dai[0], - .codec_dai = &ab3550_codec_dai[0], - .init = NULL, - .ops = &ux500_ab3550_ops, - }, - { - .name = "ab3550_1", - .stream_name = "ab3550_1", - .cpu_dai = &ux500_msp_dai[1], - .codec_dai = &ab3550_codec_dai[1], - .init = NULL, - .ops = &ux500_ab3550_ops, - }, -}; - -static struct snd_soc_card ux500_ab3550 = { - .name = "ab3550", - .probe = NULL, - .dai_link = ux500_ab3550_dai_links, - .num_links = ARRAY_SIZE(ux500_ab3550_dai_links), - .platform = &ux500_soc_platform, -}; - -struct snd_soc_device ux500_ab3550_drvdata = { - .card = &ux500_ab3550, - .codec_dev = &soc_codec_dev_ab3550, -}; - -static int __init mop500_ab3550_soc_init(void) -{ - int i; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - pr_debug("%s: Enter\n", - __func__); - pr_debug("%s: Card name: %s\n", - __func__, - ux500_ab3550_drvdata.card->name); - - for (i = 0; i < ARRAY_SIZE(ux500_ab3550_dai_links); i++) { - pr_debug("%s: DAI-link %d, name: %s\n", + int channels = params_channels(params); + + pr_debug("%s: Enter.\n", __func__); + pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); + pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + pr_debug("%s: substream->name = %s.\n", __func__, substream->name); + pr_debug("%s: substream->number = %d.\n", __func__, substream->number); + pr_debug("%s: channels = %d.\n", __func__, channels); + pr_debug("%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); + + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_debug("%s: snd_soc_dai_set_fmt failed with %d.\n", __func__, - i, - ux500_ab3550_drvdata.card->dai_link[i].name); - pr_debug("%s: DAI-link %d, stream_name: %s\n", - __func__, - i, - ux500_ab3550_drvdata.card->dai_link[i].stream_name); + ret); + return ret; } - pr_debug("%s: Allocate platform device (%s)\n", - __func__, - ux500_ab3550_drvdata.card->name); - ux500_ab3550_platform_device = platform_device_alloc("soc-audio", -1); - if (!ux500_ab3550_platform_device) - return -ENOMEM; - - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Set platform drvdata (%s)\n", - __func__, - ux500_ab3550_drvdata.card->name); - platform_set_drvdata( - ux500_ab3550_platform_device, - &ux500_ab3550_drvdata); - - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Add platform device (%s)\n", - __func__, - ux500_ab3550_drvdata.card->name); - ux500_ab3550_drvdata.dev = &ux500_ab3550_platform_device->dev; - - ret = platform_device_add(ux500_ab3550_platform_device); - if (ret) { - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Error: Failed to add platform device (%s)\n", + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + pr_debug("%s: snd_soc_dai_set_fmt failed with %d.\n", __func__, - ux500_ab3550_drvdata.card->name); - platform_device_put(ux500_ab3550_platform_device); + ret); + return ret; } return ret; } -module_init(mop500_ab3550_soc_init); -static void __exit mop500_ab3550_soc_exit(void) -{ - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Enter.\n", - __func__); - - dev_dbg(&ux500_ab3550_platform_device->dev, - "%s: Un-register platform device (%s)\n", - __func__, - ux500_ab3550_drvdata.card->name); - platform_device_unregister(ux500_ab3550_platform_device); -} -module_exit(mop500_ab3550_soc_exit); - -MODULE_LICENSE("GPL"); +struct snd_soc_ops ux500_ab3550_ops[] = { + { + .startup = ux500_ab3550_startup, + .shutdown = ux500_ab3550_shutdown, + .hw_params = ux500_ab3550_hw_params, + } +}; diff --git a/sound/soc/ux500/ux500_ab3550.h b/sound/soc/ux500/ux500_ab3550.h new file mode 100644 index 00000000000..53ea3902d36 --- /dev/null +++ b/sound/soc/ux500/ux500_ab3550.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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 UX500_AB3550_H +#define UX500_AB3550_H + +extern struct snd_soc_ops ux500_ab3550_ops[]; + +#endif diff --git a/sound/soc/ux500/ux500_av8100.c b/sound/soc/ux500/ux500_av8100.c index 5317670c3b4..25e6a0deb0c 100644 --- a/sound/soc/ux500/ux500_av8100.c +++ b/sound/soc/ux500/ux500_av8100.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: @@ -11,42 +11,31 @@ * by the Free Software Foundation. */ -#include <linux/io.h> #include <sound/soc.h> - -#include "ux500_pcm.h" -#include "ux500_msp_dai.h" - -#include <linux/spi/spi.h> -#include <sound/initval.h> - #include "../codecs/av8100_audio.h" - -static struct platform_device *ux500_av8100_platform_device; +#include "ux500_av8100.h" static int ux500_av8100_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + 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 channels = params_channels(params); unsigned int tx_mask, fmt; enum hdmi_channel_allocation hdmi_ca; enum hdmi_audio_channel_count hdmi_cc; struct hdmi_audio_settings as; + int ret; - int channels = params_channels(params); - int ret = 0; - - pr_debug("%s: Enter (TDM-mode, channels = %d, name = %s, number = %d).\n", - __func__, - channels, - substream->name, - substream->number); - + pr_debug("%s: Enter.\n", __func__); pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + pr_debug("%s: substream->name = %s.\n", __func__, substream->name); + pr_debug("%s: substream->number = %d.\n", __func__, substream->number); + pr_debug("%s: channels = %d.\n", __func__, channels); + pr_debug("%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); switch (channels) { case 1: @@ -100,7 +89,7 @@ static int ux500_av8100_hw_params(struct snd_pcm_substream *substream, as.channel_allocation = hdmi_ca; as.level_shift_value = AV8100_CODEC_LSV_0DB; as.downmix_inhibit = false; - ret = av8100_codec_change_hdmi_audio_settings(substream, &as); + ret = av8100_codec_change_hdmi_audio_settings(codec_dai, &as); if (ret < 0) { pr_err("%s: Unable to change HDMI audio-settings for codec-DAI " "(av8100_codec_change_hdmi_audio_settings returned %d)!\n", @@ -155,93 +144,9 @@ static int ux500_av8100_hw_params(struct snd_pcm_substream *substream, return ret; } - - -struct snd_soc_dai_link ux500_av8100_dai_links[] = { +struct snd_soc_ops ux500_av8100_ops[] = { { - .name = "hdmi", - .stream_name = "hdmi", - .cpu_dai = &ux500_msp_dai[2], - .codec_dai = &av8100_codec_dai[0], - .init = NULL, - .ops = (struct snd_soc_ops[]) { - { - .hw_params = ux500_av8100_hw_params, - } + .hw_params = ux500_av8100_hw_params, } - }, }; -static struct snd_soc_card ux500_av8100 = { - .name = "hdmi", - .probe = NULL, - .dai_link = ux500_av8100_dai_links, - .num_links = ARRAY_SIZE(ux500_av8100_dai_links), - .platform = &ux500_soc_platform, -}; - -struct snd_soc_device ux500_av8100_drvdata = { - .card = &ux500_av8100, - .codec_dev = &soc_codec_dev_av8100, -}; - -static int __init ux500_av8100_soc_init(void) -{ - int ret = 0; - - pr_debug("%s: Enter.\n", __func__); - - pr_info("%s: Card name: %s\n", - __func__, - ux500_av8100_drvdata.card->name); - - pr_debug("%s: DAI-link 0, name: %s\n", - __func__, - ux500_av8100_drvdata.card->dai_link[0].name); - pr_debug("%s: DAI-link 0, stream_name: %s\n", - __func__, - ux500_av8100_drvdata.card->dai_link[0].stream_name); - - pr_debug("%s: Allocate platform device (%s).\n", - __func__, - ux500_av8100_drvdata.card->name); - ux500_av8100_platform_device = platform_device_alloc("soc-audio", -1); - if (!ux500_av8100_platform_device) - return -ENOMEM; - - pr_debug("%s: Set platform drvdata (%s).\n", - __func__, - ux500_av8100_drvdata.card->name); - platform_set_drvdata( - ux500_av8100_platform_device, - &ux500_av8100_drvdata); - ux500_av8100_drvdata.dev = &ux500_av8100_platform_device->dev; - - pr_debug("%s: Add platform device (%s).\n", - __func__, - ux500_av8100_drvdata.card->name); - ret = platform_device_add(ux500_av8100_platform_device); - if (ret) { - pr_err("%s: Error: Failed to add platform device (%s).\n", - __func__, - ux500_av8100_drvdata.card->name); - platform_device_put(ux500_av8100_platform_device); - } - - return ret; -} - -static void __exit ux500_av8100_soc_exit(void) -{ - pr_debug("%s: Enter.\n", __func__); - - pr_debug("%s: Unregister platform device (%s).\n", - __func__, - ux500_av8100_drvdata.card->name); - platform_device_unregister(ux500_av8100_platform_device); -} - -module_init(ux500_av8100_soc_init); -module_exit(ux500_av8100_soc_exit); - -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/ux500/ux500_av8100.h b/sound/soc/ux500/ux500_av8100.h new file mode 100644 index 00000000000..b107b2e1be7 --- /dev/null +++ b/sound/soc/ux500/ux500_av8100.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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 UX500_AV8100_H +#define UX500_AV8100_H + +extern struct snd_soc_ops ux500_av8100_ops[]; + +#endif diff --git a/sound/soc/ux500/ux500_cg29xx.c b/sound/soc/ux500/ux500_cg29xx.c index 0c74bbe4550..6cc77820a62 100644 --- a/sound/soc/ux500/ux500_cg29xx.c +++ b/sound/soc/ux500/ux500_cg29xx.c @@ -1,7 +1,8 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Roger Nilsson roger.xr.nilsson@stericsson.com + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. * * License terms: @@ -11,93 +12,75 @@ * by the Free Software Foundation. */ -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/io.h> #include <sound/soc.h> - -#include "ux500_pcm.h" -#include "ux500_msp_dai.h" #include "../codecs/cg29xx.h" #define UX500_CG29XX_DAI_SLOT_WIDTH 16 #define UX500_CG29XX_DAI_SLOTS 2 #define UX500_CG29XX_DAI_ACTIVE_SLOTS 0x01 -static struct platform_device *ux500_cg29xx_platform_device; - -static int ux500_cg29xx_hw_params( - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +int ux500_cg29xx_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; + int channels = params_channels(params); int err; - pr_debug("%s: substream->pcm->name = %s.\n" - "substream->pcm->id = %s.\n" - "substream->name = %s.\n" - "substream->number = %d.\n", - __func__, - substream->pcm->name, - substream->pcm->id, - substream->name, - substream->number); + pr_debug("%s: Enter.\n", __func__); + pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name); + pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id); + pr_debug("%s: substream->name = %s.\n", __func__, substream->name); + pr_debug("%s: substream->number = %d.\n", __func__, substream->number); + pr_debug("%s: channels = %d.\n", __func__, channels); + pr_debug("%s: DAI-index (Codec): %d\n", __func__, codec_dai->id); + pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id); - err = snd_soc_dai_set_fmt( - codec_dai, - SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS); + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS); if (err) { - pr_err("%s: snd_soc_dai_set_fmt(codec)" - " failed with %d.\n", - __func__, + pr_err("%s: snd_soc_dai_set_fmt(codec) failed with %d.\n", + __func__, err); goto out_err; } - err = snd_soc_dai_set_tdm_slot( - codec_dai, - 1 << CG29XX_DAI_SLOT0_SHIFT, - 1 << CG29XX_DAI_SLOT0_SHIFT, - UX500_CG29XX_DAI_SLOTS, - UX500_CG29XX_DAI_SLOT_WIDTH); + err = snd_soc_dai_set_tdm_slot(codec_dai, + 1 << CG29XX_DAI_SLOT0_SHIFT, + 1 << CG29XX_DAI_SLOT0_SHIFT, + UX500_CG29XX_DAI_SLOTS, + UX500_CG29XX_DAI_SLOT_WIDTH); if (err) { - pr_err("%s: cg29xx_set_tdm_slot(codec)" - " failed with %d.\n", + pr_err("%s: cg29xx_set_tdm_slot(codec_dai) failed with %d.\n", __func__, err); goto out_err; } - err = snd_soc_dai_set_fmt( - cpu_dai, - SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS | - SND_SOC_DAIFMT_NB_NF); + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_NB_NF); if (err) { - pr_err("%s: snd_soc_dai_set_fmt(dai)" - " failed with %d.\n", - __func__, + pr_err("%s: snd_soc_dai_set_fmt(cpu_dai) failed with %d.\n", + __func__, err); goto out_err; } err = snd_soc_dai_set_tdm_slot(cpu_dai, - UX500_CG29XX_DAI_ACTIVE_SLOTS, - UX500_CG29XX_DAI_ACTIVE_SLOTS, - UX500_CG29XX_DAI_SLOTS, - UX500_CG29XX_DAI_SLOT_WIDTH); + UX500_CG29XX_DAI_ACTIVE_SLOTS, + UX500_CG29XX_DAI_ACTIVE_SLOTS, + UX500_CG29XX_DAI_SLOTS, + UX500_CG29XX_DAI_SLOT_WIDTH); if (err) { - pr_err("%s: cg29xx_set_tdm_slot(dai)" - " failed with %d.\n", - __func__, - err); + pr_err("%s: cg29xx_set_tdm_slot(cpu_dai) failed with %d.\n", + __func__, + err); goto out_err; } @@ -105,73 +88,9 @@ out_err: return err; } -static struct snd_soc_ops ux500_cg29xx_ops = { - .hw_params = ux500_cg29xx_hw_params, -}; - -struct snd_soc_dai_link ux500_cg29xx_dai_links[] = { +struct snd_soc_ops ux500_cg29xx_ops[] = { { - .name = "cg29xx_0", - .stream_name = "cg29xx_0", - .cpu_dai = &ux500_msp_dai[0], - .codec_dai = &cg29xx_codec_dai[1], - .init = NULL, - .ops = &ux500_cg29xx_ops, - }, -}; - -static struct snd_soc_card ux500_cg29xx = { - .name = "cg29xx", - .probe = NULL, - .dai_link = ux500_cg29xx_dai_links, - .num_links = ARRAY_SIZE(ux500_cg29xx_dai_links), - .platform = &ux500_soc_platform, -}; - -struct snd_soc_device ux500_cg29xx_drvdata = { - .card = &ux500_cg29xx, - .codec_dev = &soc_codec_dev_cg29xx, -}; - -static int __init ux500_cg29xx_soc_init(void) -{ - int err; - int i; - - for (i = 0; i < ARRAY_SIZE(ux500_cg29xx_dai_links); i++) { - pr_debug("%s: DAI-link %d, name: %s\n", - __func__, - i, - ux500_cg29xx_drvdata.card->dai_link[i].name); - } - - ux500_cg29xx_platform_device = - platform_device_alloc("soc-audio", -1); - if (!ux500_cg29xx_platform_device) - return -ENOMEM; - - platform_set_drvdata( - ux500_cg29xx_platform_device, - &ux500_cg29xx_drvdata); - - ux500_cg29xx_drvdata.dev = &ux500_cg29xx_platform_device->dev; - - err = platform_device_add(ux500_cg29xx_platform_device); - if (err) { - pr_err("%s: Error: Failed to add platform device (%s).\n", - __func__, - ux500_cg29xx_drvdata.card->name); - platform_device_put(ux500_cg29xx_platform_device); + .hw_params = ux500_cg29xx_hw_params, } +}; - return err; -} -module_init(ux500_cg29xx_soc_init); - -static void __exit ux500_cg29xx_soc_exit(void) -{ - platform_device_unregister(ux500_cg29xx_platform_device); -} -module_exit(ux500_cg29xx_soc_exit); - -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/ux500/ux500_cg29xx.h b/sound/soc/ux500/ux500_cg29xx.h new file mode 100644 index 00000000000..49a8c3e0478 --- /dev/null +++ b/sound/soc/ux500/ux500_cg29xx.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ola Lilja <ola.o.lilja@stericsson.com> + * for ST-Ericsson. + * + * License terms: + * + * 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 UX500_CG29XX_H +#define UX500_CG29XX_H + +extern struct snd_soc_ops ux500_cg29xx_ops[]; + +#endif diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 432f5646b67..6a4574c0931 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -1,8 +1,8 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Ola Lilja (ola.o.lilja@stericsson.com), - * Roger Nilsson (roger.xr.nilsson@stericsson.com) + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. * * License terms: @@ -11,6 +11,7 @@ * it under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. */ + #include <linux/slab.h> #include <asm/dma.h> #include <linux/bitops.h> @@ -23,7 +24,7 @@ #include "ux500_msp_dai.h" #include "ux500_pcm.h" -static struct ux500_msp_dai_private ux500_msp_dai_private[UX500_NBR_OF_DAI] = { +static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = { { .i2s = NULL, .fmt = 0, @@ -31,6 +32,8 @@ static struct ux500_msp_dai_private ux500_msp_dai_private[UX500_NBR_OF_DAI] = { .tx_mask = 0x01, .rx_mask = 0x01, .slot_width = 16, + .playback_active = false, + .capture_active = false, }, { .i2s = NULL, @@ -39,6 +42,8 @@ static struct ux500_msp_dai_private ux500_msp_dai_private[UX500_NBR_OF_DAI] = { .tx_mask = 0x01, .rx_mask = 0x01, .slot_width = 16, + .playback_active = false, + .capture_active = false, }, { .i2s = NULL, @@ -47,73 +52,22 @@ static struct ux500_msp_dai_private ux500_msp_dai_private[UX500_NBR_OF_DAI] = { .tx_mask = 0x01, .rx_mask = 0x01, .slot_width = 16, + .playback_active = false, + .capture_active = false, }, }; -static int ux500_msp_dai_i2s_probe(struct i2s_device *i2s) -{ - pr_info("%s: Enter (chip_select = %d, i2s = %d).\n", - __func__, - (int)i2s->chip_select, (int)(i2s)); - - ux500_msp_dai_private[i2s->chip_select].i2s = i2s; - - try_module_get(i2s->controller->dev.parent->driver->owner); - i2s_set_drvdata( - i2s, - (void *)&ux500_msp_dai_private[i2s->chip_select]); - - return 0; -} - -static int ux500_msp_dai_i2s_remove(struct i2s_device *i2s) -{ - struct ux500_msp_dai_private *ux500_msp_dai_private = - i2s_get_drvdata(i2s); - - pr_debug("%s: Enter (chip_select = %d).\n", - __func__, - (int)i2s->chip_select); - - ux500_msp_dai_private->i2s = NULL; - i2s_set_drvdata(i2s, NULL); - - pr_debug("%s: Calling module_put.\n", - __func__); - module_put(i2s->controller->dev.parent->driver->owner); - - return 0; -} - -static const struct i2s_device_id dev_id_table[] = { - { "i2s_device.0", 0, 0 }, - { "i2s_device.1", 0, 0 }, - { "i2s_device.2", 0, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2s, dev_id_table); - -static struct i2s_driver i2sdrv_i2s = { - .driver = { - .name = "ux500_asoc_i2s", - .owner = THIS_MODULE, - }, - .probe = ux500_msp_dai_i2s_probe, - .remove = __devexit_p(ux500_msp_dai_i2s_remove), - .id_table = dev_id_table, -}; - bool ux500_msp_dai_i2s_get_underrun_status(int dai_idx) { - struct ux500_msp_dai_private *dai_private = &ux500_msp_dai_private[dai_idx]; - int status = i2s_hw_status(dai_private->i2s->controller); + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; + int status = i2s_hw_status(drvdata->i2s->controller); return (bool)(status & TRANSMIT_UNDERRUN_ERR_INT); } dma_addr_t ux500_msp_dai_i2s_get_pointer(int dai_idx, int stream_id) { - struct ux500_msp_dai_private *dai_private = &ux500_msp_dai_private[dai_idx]; - return i2s_get_pointer(dai_private->i2s->controller, + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; + return i2s_get_pointer(drvdata->i2s->controller, (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? I2S_DIRECTION_TX : I2S_DIRECTION_RX); @@ -125,7 +79,7 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, int dai_idx, int stream_id) { - struct ux500_msp_dai_private *dai_private = &ux500_msp_dai_private[dai_idx]; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; struct i2s_message message; struct i2s_device *i2s_dev; int i; @@ -138,7 +92,7 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, sg_len, sg_size); - if (!ux500_msp_dai[dai_idx].playback.active) { + if (!drvdata->playback_active) { pr_err("%s: The I2S controller is not available." "MSP index:%d\n", __func__, @@ -146,7 +100,7 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, return ret; } - i2s_dev = dai_private->i2s; + i2s_dev = drvdata->i2s; sg = kzalloc(sizeof(struct scatterlist) * sg_len, GFP_ATOMIC); sg_init_table(sg, sg_len); @@ -174,161 +128,70 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, return ret; } -int ux500_msp_dai_i2s_send_data(void *data, - size_t bytes, - int dai_idx) +static const char *stream_str(struct snd_pcm_substream *substream) { - struct ux500_msp_dai_private *dai_private = - &ux500_msp_dai_private[dai_idx]; - struct i2s_message message; - struct i2s_device *i2s_dev; - int ret = 0; - - pr_debug("%s: Enter. (MSP-index: %d, bytes = %d).\n", - __func__, - dai_idx, - (int)bytes); - - i2s_dev = dai_private->i2s; - - if (!ux500_msp_dai[dai_idx].playback.active) { - pr_err("%s: The I2S controller is not available." - "MSP index:%d\n", - __func__, - dai_idx); - return ret; - } - - message.i2s_transfer_mode = I2S_TRANSFER_MODE_SINGLE_DMA; - message.i2s_direction = I2S_DIRECTION_TX; - message.txbytes = bytes; - message.txdata = data; - - ret = i2s_transfer(i2s_dev->controller, &message); - if (ret < 0) { - pr_err("%s: Error: i2s_transfer failed. MSP index: %d\n", - __func__, - dai_idx); - } - - return ret; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; } -int ux500_msp_dai_i2s_receive_data(void *data, - size_t bytes, - int dai_idx) +static int ux500_msp_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { - struct ux500_msp_dai_private *dai_private = - &ux500_msp_dai_private[dai_idx]; - struct i2s_message message; - struct i2s_device *i2s_dev; - int ret = 0; - - pr_debug("%s: Enter. (MSP-index: %d, Bytes: %d).\n", - __func__, - dai_idx, - (int)bytes); + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + bool mode_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - i2s_dev = dai_private->i2s; + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); - if (!ux500_msp_dai[dai_idx].capture.active) { - pr_err("%s: MSP controller is not available. (MSP-index: %d)\n", + if ((mode_playback && drvdata->playback_active) || + (!mode_playback && drvdata->capture_active)) { + pr_err("%s: Error: MSP %d (%s): Stream already active.\n", __func__, - dai_idx); - return ret; + dai->id, + stream_str(substream)); + return -EBUSY; } - message.i2s_transfer_mode = I2S_TRANSFER_MODE_SINGLE_DMA; - message.i2s_direction = I2S_DIRECTION_RX; - message.rxbytes = bytes; - message.rxdata = data; - message.dma_flag = 1; - - ret = i2s_transfer(i2s_dev->controller, &message); - if (ret < 0) { - pr_err("%s: i2s_transfer failed (%d)! (MSP-index: %d)\n", - __func__, - ret, - dai_idx); - } + if (mode_playback) + drvdata->playback_active = true; + else + drvdata->capture_active = true; - return ret; + return 0; } static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *msp_dai) + struct snd_soc_dai *dai) { - struct ux500_msp_dai_private *dai_private = msp_dai->private_data; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; + bool mode_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - pr_info("%s: Enter (stream = %s).\n", - __func__, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "SNDRV_PCM_STREAM_PLAYBACK" : "SNDRV_PCM_STREAM_CAPTURE"); - if (dai_private == NULL) - return; - - pr_debug("%s: chip_select = %d.\n", - __func__, - (int)dai_private->i2s->chip_select); - - if (i2s_cleanup(dai_private->i2s->controller, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DISABLE_TRANSMIT : DISABLE_RECEIVE)) { - - pr_err("%s: Error closing i2s for %s.\n", - __func__, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "playback" : "capture"); - } - return; -} + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); -static int ux500_msp_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *msp_dai) -{ - struct ux500_msp_dai_private *dai_private = - &ux500_msp_dai_private[msp_dai->id]; - - pr_info("%s: MSP Index: %d.\n", - __func__, - msp_dai->id); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - msp_dai->playback.active : msp_dai->capture.active) { - pr_err("%s: A %s stream is already active.\n", - __func__, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "PLAYBACK" : "CAPTURE"); - return -EBUSY; - } + if (drvdata == NULL) + return; - msp_dai->private_data = dai_private; + if (mode_playback) + drvdata->playback_active = false; + else + drvdata->capture_active = false; - if (dai_private->i2s == NULL) { - pr_err("%s: MSP index: %d" - "i2sdrv.i2s == NULL\n", - __func__, - msp_dai->id); - return -1; - } - - if (dai_private->i2s->controller == NULL) { - pr_err("%s: MSP index: %d" - "i2sdrv.i2s->controller == NULL.\n", - __func__, - msp_dai->id); - return -1; + if (i2s_cleanup(drvdata->i2s->controller, + mode_playback ? DISABLE_TRANSMIT : DISABLE_RECEIVE)) { + pr_err("%s: Error: MSP %d (%s): Unable to close i2s.\n", + __func__, + dai->id, + stream_str(substream)); } - return 0; + return; } -static void ux500_msp_dai_setup_multichannel( - struct ux500_msp_dai_private *private, - struct msp_config *msp_config) +static void ux500_msp_dai_setup_multichannel(struct ux500_platform_drvdata *private, + struct msp_config *msp_config) { - struct msp_multichannel_config *multi = - &msp_config->multichannel_config; + struct msp_multichannel_config *multi = &msp_config->multichannel_config; if (private->slots > 1) { msp_config->multichannel_configured = 1; @@ -356,10 +219,9 @@ static void ux500_msp_dai_setup_multichannel( } } -static void ux500_msp_dai_setup_frameper( - struct ux500_msp_dai_private *private, - unsigned int rate, - struct msp_protocol_desc *prot_desc) +static void ux500_msp_dai_setup_frameper(struct ux500_platform_drvdata *private, + unsigned int rate, + struct msp_protocol_desc *prot_desc) { switch (private->slots) { default: @@ -408,10 +270,9 @@ static void ux500_msp_dai_setup_frameper( prot_desc->total_clocks_for_one_frame); } -static void ux500_msp_dai_setup_framing_pcm( - struct ux500_msp_dai_private *private, - unsigned int rate, - struct msp_protocol_desc *prot_desc) +static void ux500_msp_dai_setup_framing_pcm(struct ux500_platform_drvdata *private, + unsigned int rate, + struct msp_protocol_desc *prot_desc) { u32 frame_length = MSP_FRAME_LENGTH_1; prot_desc->frame_width = 0; @@ -448,9 +309,8 @@ static void ux500_msp_dai_setup_framing_pcm( ux500_msp_dai_setup_frameper(private, rate, prot_desc); } -static void ux500_msp_dai_setup_clocking( - unsigned int fmt, - struct msp_config *msp_config) +static void ux500_msp_dai_setup_clocking(unsigned int fmt, + struct msp_config *msp_config) { switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -491,9 +351,8 @@ static void ux500_msp_dai_setup_clocking( } } -static void ux500_msp_dai_compile_prot_desc_pcm( - unsigned int fmt, - struct msp_protocol_desc *prot_desc) +static void ux500_msp_dai_compile_prot_desc_pcm(unsigned int fmt, + struct msp_protocol_desc *prot_desc) { prot_desc->rx_phase_mode = MSP_SINGLE_PHASE; prot_desc->tx_phase_mode = MSP_SINGLE_PHASE; @@ -525,8 +384,7 @@ static void ux500_msp_dai_compile_prot_desc_pcm( prot_desc->frame_sync_ignore = MSP_FRAME_SYNC_IGNORE; } -static void ux500_msp_dai_compile_prot_desc_i2s( - struct msp_protocol_desc *prot_desc) +static void ux500_msp_dai_compile_prot_desc_i2s(struct msp_protocol_desc *prot_desc) { prot_desc->rx_phase_mode = MSP_DUAL_PHASE; prot_desc->tx_phase_mode = MSP_DUAL_PHASE; @@ -560,11 +418,10 @@ static void ux500_msp_dai_compile_prot_desc_i2s( prot_desc->frame_sync_ignore = MSP_FRAME_SYNC_IGNORE; } -static void ux500_msp_dai_compile_msp_config( - struct snd_pcm_substream *substream, - struct ux500_msp_dai_private *private, - unsigned int rate, - struct msp_config *msp_config) +static void ux500_msp_dai_compile_msp_config(struct snd_pcm_substream *substream, + struct ux500_platform_drvdata *private, + unsigned int rate, + struct msp_config *msp_config) { struct msp_protocol_desc *prot_desc = &msp_config->protocol_desc; struct snd_pcm_runtime *runtime = substream->runtime; @@ -640,31 +497,24 @@ static void ux500_msp_dai_compile_msp_config( } static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *msp_dai) + struct snd_soc_dai *dai) { int ret = 0; - struct ux500_msp_dai_private *dai_private = msp_dai->private_data; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; struct snd_pcm_runtime *runtime = substream->runtime; struct msp_config msp_config; - pr_debug("%s: Enter (stream = %p - %s, chip_select = %d).\n", - __func__, - substream, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "SNDRV_PCM_STREAM_PLAYBACK" : "SNDRV_PCM_STREAM_CAPTURE", - (int)dai_private->i2s->chip_select); - - pr_debug("%s: Setting up dai with rate %u.\n", - __func__, - runtime->rate); + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); - ux500_msp_dai_compile_msp_config(substream, dai_private, - runtime->rate, &msp_config); + pr_debug("%s: Setup dai (Rate: %u).\n", __func__, runtime->rate); + ux500_msp_dai_compile_msp_config(substream, + drvdata, + runtime->rate, + &msp_config); - ret = i2s_setup(dai_private->i2s->controller, &msp_config); + ret = i2s_setup(drvdata->i2s->controller, &msp_config); if (ret < 0) { - pr_err("u8500_msp_dai_prepare: i2s_setup failed! " - "ret = %d\n", ret); + pr_err("%s: Error: i2s_setup failed (ret = %d)!\n", __func__, ret); goto cleanup; } @@ -674,24 +524,21 @@ cleanup: static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, - struct snd_soc_dai *msp_dai) + struct snd_soc_dai *dai) { unsigned int mask, slots_active; - struct ux500_msp_dai_private *private = msp_dai->private_data; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; - pr_debug("%s: Enter stream: %s, MSP index: %d.\n", + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "SNDRV_PCM_STREAM_PLAYBACK" : - "SNDRV_PCM_STREAM_CAPTURE", - (int)private->i2s->chip_select); + dai->id, + stream_str(substream)); - switch (private->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: if (params_channels(params) != 2) { - pr_err("%s: The I2S requires " - "that the channel count of the substream " - "is two. Substream channels: %d.\n", + pr_err("%s: Error: I2S requires channels = 2 " + "(channels = %d)!\n", __func__, params_channels(params)); return -EINVAL; @@ -701,22 +548,20 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, case SND_SOC_DAIFMT_DSP_A: mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - private->tx_mask : - private->rx_mask; + drvdata->tx_mask : + drvdata->rx_mask; slots_active = hweight32(mask); pr_debug("TDM slots active: %d", slots_active); if (params_channels(params) != slots_active) { - pr_err("%s: The PCM format requires " - "that the channel count of the substream " - "matches the number of active slots.\n" - "Number of active slots: %d\n" - "Substream channels: %d.\n", + pr_err("%s: Error: PCM TDM format requires channels " + "to match active slots " + "(channels = %d, active slots = %d)!\n", __func__, - slots_active, - params_channels(params)); + params_channels(params), + slots_active); return -EINVAL; } break; @@ -728,18 +573,14 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *msp_dai, +static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct ux500_msp_dai_private *dai_private = - msp_dai->private_data; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; - pr_debug("%s: MSP index: %d: Enter.\n", - __func__, - (int)dai_private->i2s->chip_select); + pr_debug("%s: MSP %d: Enter.\n", __func__, dai->id); - switch (fmt & - (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: @@ -749,9 +590,7 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *msp_dai, break; default: - pr_err("Unsupported DAI format (0x%x)!\n", - fmt); - return -EINVAL; + goto unsupported_format; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -760,40 +599,46 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *msp_dai, break; default: - pr_err("Unsupported DAI format (0x%x)!\n", - fmt); - return -EINVAL; + goto unsupported_format; } - dai_private->fmt = fmt; + drvdata->fmt = fmt; return 0; + +unsupported_format: + pr_err("%s: MSP %d: Error: Unsupported DAI format (0x%x)!\n", + __func__, + dai->id, + fmt); + return -EINVAL; } static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, - unsigned int rx_mask, - int slots, - int slot_width) + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) { - struct ux500_msp_dai_private *private = - dai->private_data; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; unsigned int cap; if (!(slots == 1 || slots == 2 || slots == 8 || slots == 16)) { - pr_err("%s - error: slots %d Supported values are 1/2/8/16.\n", + pr_err("%s: Error: Unsupported slots (%d)! " + "Supported values are 1/2/8/16.\n", __func__, slots); return -EINVAL; } - private->slots = slots; + drvdata->slots = slots; if (!(slot_width == 16)) { - pr_err("%s - error: slot_width %d Supported value is 16.\n", + pr_err("%s: Error: Unsupported slots_width (%d)!. " + "Supported value is 16.\n", __func__, slot_width); return -EINVAL; } - private->slot_width = slot_width; + drvdata->slot_width = slot_width; switch (slots) { default: @@ -811,28 +656,24 @@ static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai, break; } - private->tx_mask = tx_mask & cap; - private->rx_mask = rx_mask & cap; + drvdata->tx_mask = tx_mask & cap; + drvdata->rx_mask = rx_mask & cap; return 0; } static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *msp_dai) + struct snd_soc_dai *dai) { int ret = 0; - struct ux500_msp_dai_private *dai_private = - msp_dai->private_data; + struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id]; - pr_debug("%s: Enter (stream = %p - %s," - " chip_select = %d, cmd = %d).\n", + pr_debug("%s: MSP %d (%s): Enter (chip_select = %d, cmd = %d).\n", __func__, - substream, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "SNDRV_PCM_STREAM_PLAYBACK" : - "SNDRV_PCM_STREAM_CAPTURE", - (int)dai_private->i2s->chip_select, + dai->id, + stream_str(substream), + (int)drvdata->i2s->chip_select, cmd); switch (cmd) { @@ -858,9 +699,9 @@ static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream, return ret; } -struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI] = { +static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { { - .name = "ux500_i2s-0", + .name = "ux500-msp.0", .id = 0, .suspend = NULL, .resume = NULL, @@ -888,10 +729,9 @@ struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI] = { .hw_params = ux500_msp_dai_hw_params, } }, - .private_data = &ux500_msp_dai_private[0], }, { - .name = "ux500_i2s-1", + .name = "ux500-msp.1", .id = 1, .suspend = NULL, .resume = NULL, @@ -919,10 +759,9 @@ struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI] = { .hw_params = ux500_msp_dai_hw_params, } }, - .private_data = &ux500_msp_dai_private[1], }, { - .name = "ux500_i2s-2", + .name = "ux500-msp.2", .id = 2, .suspend = NULL, .resume = NULL, @@ -950,51 +789,92 @@ struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI] = { .hw_params = ux500_msp_dai_hw_params, } }, - .private_data = &ux500_msp_dai_private[2], }, }; -EXPORT_SYMBOL(ux500_msp_dai); +EXPORT_SYMBOL(ux500_msp_dai_drv); -static int __init ux500_msp_dai_init(void) +static int __devinit ux500_msp_drv_probe(struct i2s_device *i2s_dev) { - int i; int ret = 0; + struct ux500_platform_drvdata *drvdata; + int msp_idx = i2s_dev->chip_select; + + pr_debug("%s: Enter (idx: %d, dev-name: %s, drv-name: %s).\n", + __func__, + msp_idx, + dev_name(&i2s_dev->dev), + i2s_dev->dev.driver->name); + + drvdata = &platform_drvdata[msp_idx]; + drvdata->i2s = i2s_dev; + + try_module_get(i2s_dev->controller->dev.parent->driver->owner); + i2s_set_drvdata(i2s_dev, drvdata); - ret = i2s_register_driver(&i2sdrv_i2s); + pr_debug("%s: Register MSP %d.\n", __func__, msp_idx); + ret = snd_soc_register_dai(&i2s_dev->dev, &ux500_msp_dai_drv[msp_idx]); if (ret < 0) { - pr_err("%s: Unable to register as a I2S driver.\n", - __func__); + pr_err("Error: %s: Failed to register MSP %d.\n", __func__, msp_idx); return ret; } - for (i = 0; i < UX500_NBR_OF_DAI; i++) { - pr_debug("%s: Register MSP dai %d.\n", - __func__, - i); - ret = snd_soc_register_dai(&ux500_msp_dai[i]); - if (ret < 0) { - pr_err("Error: Failed to register MSP dai %d.\n", - i); - return ret; - } - } - return ret; } -static void __exit ux500_msp_dai_exit(void) +static int ux500_msp_drv_remove(struct i2s_device *i2s_dev) { - int i; + struct ux500_platform_drvdata *drvdata = i2s_get_drvdata(i2s_dev); + int msp_idx = i2s_dev->chip_select; + + pr_debug("%s: Enter (idx: %d, dev-name: %s, drv-name: %s).\n", + __func__, + msp_idx, + dev_name(&i2s_dev->dev), + i2s_dev->dev.driver->name); + + drvdata->i2s = NULL; + i2s_set_drvdata(i2s_dev, NULL); + + pr_debug("%s: Calling module_put.\n", __func__); + module_put(i2s_dev->controller->dev.parent->driver->owner); + + pr_debug("%s: Unregister ux500-pcm SoC platform driver.\n", __func__); + snd_soc_unregister_dais(&i2s_dev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); + + return 0; +} +static const struct i2s_device_id dev_id_table[] = { + { "i2s_device.0", 0, 0 }, + { "i2s_device.1", 1, 0 }, + { "i2s_device.2", 2, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2s, dev_id_table); + +static struct i2s_driver i2sdrv_i2s = { + .driver = { + .name = "i2s", + .owner = THIS_MODULE, + }, + .probe = ux500_msp_drv_probe, + .remove = __devexit_p(ux500_msp_drv_remove), + .id_table = dev_id_table, +}; + +static int __init ux500_msp_init(void) +{ + return i2s_register_driver(&i2sdrv_i2s); +} + +static void __exit ux500_msp_exit(void) +{ pr_debug("%s: Enter.\n", __func__); i2s_unregister_driver(&i2sdrv_i2s); - - for (i = 0; i < UX500_NBR_OF_DAI; i++) - snd_soc_unregister_dai(&ux500_msp_dai[i]); } -module_init(ux500_msp_dai_init); -module_exit(ux500_msp_dai_exit); +module_init(ux500_msp_init); +module_exit(ux500_msp_exit); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index 90bc518fc83..28f06120f58 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -1,8 +1,8 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Ola Lilja ola.o.lilja@stericsson.com, - * Roger Nilsson roger.xr.nilsson@stericsson.com + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. * * License terms: @@ -38,13 +38,15 @@ #define UX500_MSP_MIN_CHANNELS 1 #define UX500_MSP_MAX_CHANNELS 8 -struct ux500_msp_dai_private { +struct ux500_platform_drvdata { struct i2s_device *i2s; unsigned int fmt; unsigned int tx_mask; unsigned int rx_mask; int slots; int slot_width; + bool playback_active; + bool capture_active; }; extern struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI]; diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index c0765f7a839..f8c92b59da2 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -1,8 +1,8 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Ola Lilja (ola.o.lilja@stericsson.com), - * Roger Nilsson (roger.xr.nilsson@stericsson.com) + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. * * License terms: @@ -68,6 +68,14 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = { .periods_max = UX500_PLATFORM_PERIODS_MAX, }; +static const char *stream_str(struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; +} + static void ux500_pcm_dma_hw_free(struct device *dev, struct snd_pcm_substream *substream) { @@ -94,8 +102,10 @@ void ux500_pcm_dma_eot_handler(void *data) struct snd_pcm_substream *substream = data; struct snd_pcm_runtime *runtime; struct ux500_pcm_private *private; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *dai = rtd->cpu_dai; - pr_debug("%s: Enter\n", __func__); + pr_err("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); if (substream) { runtime = substream->runtime; @@ -115,17 +125,35 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct ux500_pcm_private *private; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *dai = rtd->cpu_dai; + int ret; - pr_info("%s: Enter\n", __func__); + pr_debug("%s: MSP %d (%s): Enter.\n", __func__, dai->id, stream_str(substream)); + + pr_debug("%s: Set runtime hwparams.\n", __func__); + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw_playback); + else + snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw_capture); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + pr_err("%s: Error: snd_pcm_hw_constraints failed (%d)\n", + __func__, + ret); + return ret; + } + + pr_debug("%s: Init runtime private data.\n", __func__); private = kzalloc(sizeof(struct ux500_pcm_private), GFP_KERNEL); if (private == NULL) return -ENOMEM; - - private->msp_id = rtd->dai->cpu_dai->id; + private->msp_id = dai->id; runtime->private_data = private; - pr_debug("%s: Setting HW-config\n", __func__); + pr_debug("%s: Set hw-struct for %s.\n", __func__, stream_str(substream)); runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? ux500_pcm_hw_playback : ux500_pcm_hw_capture; @@ -332,35 +360,66 @@ static int ux500_pcm_resume(struct snd_soc_dai *dai) return 0; } -struct snd_soc_platform ux500_soc_platform = { - .name = "ux500-audio", - .pcm_ops = &ux500_pcm_ops, +struct snd_soc_platform_driver ux500_pcm_soc_drv = { + .ops = &ux500_pcm_ops, .pcm_new = ux500_pcm_new, .pcm_free = ux500_pcm_free, .suspend = ux500_pcm_suspend, .resume = ux500_pcm_resume, }; -EXPORT_SYMBOL(ux500_soc_platform); +EXPORT_SYMBOL(ux500_pcm_soc_drv); -static int __init ux500_pcm_init(void) +static int __devinit ux500_pcm_drv_probe(struct platform_device *pdev) { int ret; - pr_debug("%s: Register platform.\n", __func__); - ret = snd_soc_register_platform(&ux500_soc_platform); - if (ret < 0) - pr_debug("%s: Error: Failed to register platform!\n", - __func__); + pr_debug("%s: Register ux500-pcm SoC platform driver.\n", __func__); + ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); + if (ret < 0) { + pr_err("%s: Error: Failed to register " + "ux500-pcm SoC platform driver (%d)!\n", + __func__, + ret); + return ret; + } return 0; } -static void __exit ux500_pcm_exit(void) +static int __devexit ux500_pcm_drv_remove(struct platform_device *pdev) { - snd_soc_unregister_platform(&ux500_soc_platform); + pr_debug("%s: Unregister ux500-pcm SoC platform driver.\n", __func__); + snd_soc_unregister_platform(&pdev->dev); + + return 0; +} + +static struct platform_driver ux500_pcm_drv = { + .driver = { + .name = "ux500-pcm", + .owner = THIS_MODULE, + }, + + .probe = ux500_pcm_drv_probe, + .remove = __devexit_p(ux500_pcm_drv_remove), +}; + +static int __init ux500_pcm_drv_init(void) +{ + pr_debug("%s: Register ux500-pcm platform driver.\n", __func__); + + return platform_driver_register(&ux500_pcm_drv); +} + + +static void __exit ux500_pcm_drv_exit(void) +{ + pr_debug("%s: Unregister ux500-pcm platform driver.\n", __func__); + + platform_driver_unregister(&ux500_pcm_drv); } -module_init(ux500_pcm_init); -module_exit(ux500_pcm_exit); +module_init(ux500_pcm_drv_init); +module_exit(ux500_pcm_drv_exit); MODULE_LICENSE("GPL"); diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h index 9d8b36d9b6f..de2df94fd97 100644 --- a/sound/soc/ux500/ux500_pcm.h +++ b/sound/soc/ux500/ux500_pcm.h @@ -1,8 +1,8 @@ /* * Copyright (C) ST-Ericsson SA 2010 * - * Author: Ola Lilja ola.o.lilja@stericsson.com, - * Roger Nilsson roger.xr.nilsson@stericsson.com + * Author: Ola Lilja <ola.o.lilja@stericsson.com>, + * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. * * License terms: |