diff options
68 files changed, 987 insertions, 617 deletions
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt new file mode 100644 index 000000000000..6b222f9b8ef5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4270.txt @@ -0,0 +1,21 @@ +CS4270 audio CODEC + +The driver for this device currently only supports I2C. + +Required properties: + + - compatible : "cirrus,cs4270" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset-gpio : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + +Example: + +codec: cs4270@48 { + compatible = "cirrus,cs4270"; + reg = <0x48>; +}; diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt new file mode 100644 index 000000000000..65dec876cb2d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt @@ -0,0 +1,91 @@ +* Texas Instruments OMAP4+ and twl6040 based audio setups + +Required properties: +- compatible: "ti,abe-twl6040" +- ti,model: Name of the sound card ( for example "SDP4430") +- ti,mclk-freq: MCLK frequency for HPPLL operation +- ti,mcpdm: phandle for the McPDM node +- ti,twl6040: phandle for the twl6040 core node +- ti,audio-routing: List of connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + +Optional properties: +- ti,dmic: phandle for the OMAP dmic node if the machine have it connected +- ti,jack_detection: Need to be set to <1> if the board capable to detect jack + insertion, removal. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Earphone Spk + * Ext Spk + * Line Out + * Vibrator + * Headset Mic + * Main Handset Mic + * Sub Handset Mic + * Line In + * Digital Mic + +twl6040 pins: + * HSOL + * HSOR + * EP + * HFL + * HFR + * AUXL + * AUXR + * VIBRAL + * VIBRAR + * HSMIC + * MAINMIC + * SUBMIC + * AFML + * AFMR + + * Headset Mic Bias + * Main Mic Bias + * Digital Mic1 Bias + * Digital Mic2 Bias + +Digital mic pins: + * DMic + +Example: + +sound { + compatible = "ti,abe-twl6040"; + ti,model = "SDP4430"; + + ti,jack-detection = <1>; + ti,mclk-freq = <38400000>; + + ti,mcpdm = <&mcpdm>; + ti,dmic = <&dmic>; + + ti,twl6040 = <&twl6040>; + + /* Audio routing */ + ti,audio-routing = + "Headset Stereophone", "HSOL", + "Headset Stereophone", "HSOR", + "Earphone Spk", "EP", + "Ext Spk", "HFL", + "Ext Spk", "HFR", + "Line Out", "AUXL", + "Line Out", "AUXR", + "Vibrator", "VIBRAL", + "Vibrator", "VIBRAR", + "HSMIC", "Headset Mic", + "Headset Mic", "Headset Mic Bias", + "MAINMIC", "Main Handset Mic", + "Main Handset Mic", "Main Mic Bias", + "SUBMIC", "Sub Handset Mic", + "Sub Handset Mic", "Main Mic Bias", + "AFML", "Line In", + "AFMR", "Line In", + "DMic", "Digital Mic", + "Digital Mic", "Digital Mic1 Bias"; +}; diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 3c795921c5f6..b7836503dc69 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2404,8 +2404,12 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) dev_dbg(dev, "%s: Enter.\n", __func__); + /* Inform SoC Core that we have our own I/O arrangements. */ + codec->control_data = (void *)true; + /* Setup AB8500 according to board-settings */ - pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent); + pdata = dev_get_platdata(dev->parent); + status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); if (status < 0) { pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 8c39dddd7d00..11b1b714b8b5 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -186,6 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) printk(KERN_INFO "AD1980 SoC Audio Codec\n"); + codec->control_data = codec; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 44f59064d8de..704544bfc90d 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1392,17 +1392,7 @@ static struct i2c_driver adau1373_i2c_driver = { .id_table = adau1373_i2c_id, }; -static int __init adau1373_init(void) -{ - return i2c_add_driver(&adau1373_i2c_driver); -} -module_init(adau1373_init); - -static void __exit adau1373_exit(void) -{ - i2c_del_driver(&adau1373_i2c_driver); -} -module_exit(adau1373_exit); +module_i2c_driver(adau1373_i2c_driver); MODULE_DESCRIPTION("ASoC ADAU1373 driver"); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 3d50fc8646b6..51f2f3cd8136 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -527,17 +527,7 @@ static struct i2c_driver adau1701_i2c_driver = { .id_table = adau1701_i2c_id, }; -static int __init adau1701_init(void) -{ - return i2c_add_driver(&adau1701_i2c_driver); -} -module_init(adau1701_init); - -static void __exit adau1701_exit(void) -{ - i2c_del_driver(&adau1701_i2c_driver); -} -module_exit(adau1701_exit); +module_i2c_driver(adau1701_i2c_driver); MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver"); MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>"); diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 5fb7c2a80e6d..2b457976a7bf 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -696,17 +696,7 @@ static struct i2c_driver ak4671_i2c_driver = { .id_table = ak4671_i2c_id, }; -static int __init ak4671_modinit(void) -{ - return i2c_add_driver(&ak4671_i2c_driver); -} -module_init(ak4671_modinit); - -static void __exit ak4671_exit(void) -{ - i2c_del_driver(&ak4671_i2c_driver); -} -module_exit(ak4671_exit); +module_i2c_driver(ak4671_i2c_driver); MODULE_DESCRIPTION("ASoC AK4671 codec driver"); MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 5c9cacaf2d52..5e96a0a1669c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -229,6 +229,69 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(arizona_out_ev); +static unsigned int arizona_sysclk_48k_rates[] = { + 6144000, + 12288000, + 22579200, + 49152000, +}; + +static unsigned int arizona_sysclk_44k1_rates[] = { + 5644800, + 11289600, + 24576000, + 45158400, +}; + +static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, + unsigned int freq) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int reg; + unsigned int *rates; + int ref, div, refclk; + + switch (clk) { + case ARIZONA_CLK_OPCLK: + reg = ARIZONA_OUTPUT_SYSTEM_CLOCK; + refclk = priv->sysclk; + break; + case ARIZONA_CLK_ASYNC_OPCLK: + reg = ARIZONA_OUTPUT_ASYNC_CLOCK; + refclk = priv->asyncclk; + break; + default: + return -EINVAL; + } + + if (refclk % 8000) + rates = arizona_sysclk_44k1_rates; + else + rates = arizona_sysclk_48k_rates; + + for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) && + rates[ref] <= refclk; ref++) { + div = 1; + while (rates[ref] / div >= freq && div < 32) { + if (rates[ref] / div == freq) { + dev_dbg(codec->dev, "Configured %dHz OPCLK\n", + freq); + snd_soc_update_bits(codec, reg, + ARIZONA_OPCLK_DIV_MASK | + ARIZONA_OPCLK_SEL_MASK, + (div << + ARIZONA_OPCLK_DIV_SHIFT) | + ref); + return 0; + } + div++; + } + } + + dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq); + return -EINVAL; +} + int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { @@ -252,6 +315,9 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, reg = ARIZONA_ASYNC_CLOCK_1; clk = &priv->asyncclk; break; + case ARIZONA_CLK_OPCLK: + case ARIZONA_CLK_ASYNC_OPCLK: + return arizona_set_opclk(codec, clk_id, freq); default: return -EINVAL; } diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 59caca8865e8..eb66b52777c9 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -17,8 +17,10 @@ #include <sound/soc.h> -#define ARIZONA_CLK_SYSCLK 1 -#define ARIZONA_CLK_ASYNCCLK 2 +#define ARIZONA_CLK_SYSCLK 1 +#define ARIZONA_CLK_ASYNCCLK 2 +#define ARIZONA_CLK_OPCLK 3 +#define ARIZONA_CLK_ASYNC_OPCLK 4 #define ARIZONA_CLK_SRC_MCLK1 0x0 #define ARIZONA_CLK_SRC_MCLK2 0x1 diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 047917f0b8ae..44a176f74170 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -29,6 +29,8 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/regulator/consumer.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> /* * The codec isn't really big-endian or little-endian, since the I2S @@ -639,6 +641,15 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { .reg_cache_default = cs4270_default_reg_cache, }; +/* + * cs4270_of_match - the device tree bindings + */ +static const struct of_device_id cs4270_of_match[] = { + { .compatible = "cirrus,cs4270", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs4270_of_match); + /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object @@ -650,9 +661,25 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { static int cs4270_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device_node *np = i2c_client->dev.of_node; struct cs4270_private *cs4270; int ret; + /* See if we have a way to bring the codec out of reset */ + if (np) { + enum of_gpio_flags flags; + int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); + + if (gpio_is_valid(gpio)) { + ret = devm_gpio_request_one(&i2c_client->dev, gpio, + flags & OF_GPIO_ACTIVE_LOW ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + "cs4270 reset"); + if (ret < 0) + return ret; + } + } + /* Verify that we have a CS4270 */ ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); @@ -718,23 +745,14 @@ static struct i2c_driver cs4270_i2c_driver = { .driver = { .name = "cs4270", .owner = THIS_MODULE, + .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, .probe = cs4270_i2c_probe, .remove = cs4270_i2c_remove, }; -static int __init cs4270_init(void) -{ - return i2c_add_driver(&cs4270_i2c_driver); -} -module_init(cs4270_init); - -static void __exit cs4270_exit(void) -{ - i2c_del_driver(&cs4270_i2c_driver); -} -module_exit(cs4270_exit); +module_i2c_driver(cs4270_i2c_driver); MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 091d0193f507..1e0fa3b5f79a 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -614,24 +614,7 @@ static struct i2c_driver cs42l51_i2c_driver = { .remove = cs42l51_i2c_remove, }; -static int __init cs42l51_init(void) -{ - int ret; - - ret = i2c_add_driver(&cs42l51_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "%s: can't add i2c driver\n", __func__); - return ret; - } - return 0; -} -module_init(cs42l51_init); - -static void __exit cs42l51_exit(void) -{ - i2c_del_driver(&cs42l51_i2c_driver); -} -module_exit(cs42l51_exit); +module_i2c_driver(cs42l51_i2c_driver); MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 628daf6a1d97..61599298fb26 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -24,7 +24,6 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/platform_device.h> -#include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5d8f39e32978..1bf55602c9eb 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -13,7 +13,6 @@ */ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index ba4fafb93e56..81a328c78838 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -250,17 +250,7 @@ static struct i2c_driver lm4857_i2c_driver = { .id_table = lm4857_i2c_id, }; -static int __init lm4857_init(void) -{ - return i2c_add_driver(&lm4857_i2c_driver); -} -module_init(lm4857_init); - -static void __exit lm4857_exit(void) -{ - i2c_del_driver(&lm4857_i2c_driver); -} -module_exit(lm4857_exit); +module_i2c_driver(lm4857_i2c_driver); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("LM4857 amplifier driver"); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index af7324b79dd0..3264a5169306 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2107,23 +2107,7 @@ static struct i2c_driver max98088_i2c_driver = { .id_table = max98088_i2c_id, }; -static int __init max98088_init(void) -{ - int ret; - - ret = i2c_add_driver(&max98088_i2c_driver); - if (ret) - pr_err("Failed to register max98088 I2C driver: %d\n", ret); - - return ret; -} -module_init(max98088_init); - -static void __exit max98088_exit(void) -{ - i2c_del_driver(&max98088_i2c_driver); -} -module_exit(max98088_exit); +module_i2c_driver(max98088_i2c_driver); MODULE_DESCRIPTION("ALSA SoC MAX98088 driver"); MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin"); diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 7cd508e16a5c..38d43c59d3f4 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2533,23 +2533,7 @@ static struct i2c_driver max98095_i2c_driver = { .id_table = max98095_i2c_id, }; -static int __init max98095_init(void) -{ - int ret; - - ret = i2c_add_driver(&max98095_i2c_driver); - if (ret) - pr_err("Failed to register max98095 I2C driver: %d\n", ret); - - return ret; -} -module_init(max98095_init); - -static void __exit max98095_exit(void) -{ - i2c_del_driver(&max98095_i2c_driver); -} -module_exit(max98095_exit); +module_i2c_driver(max98095_i2c_driver); MODULE_DESCRIPTION("ALSA SoC MAX98095 driver"); MODULE_AUTHOR("Peter Hsiang"); diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index a1913091f56c..efe535c37b39 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -369,17 +369,7 @@ static struct i2c_driver max9850_i2c_driver = { .id_table = max9850_i2c_id, }; -static int __init max9850_init(void) -{ - return i2c_add_driver(&max9850_i2c_driver); -} -module_init(max9850_init); - -static void __exit max9850_exit(void) -{ - i2c_del_driver(&max9850_i2c_driver); -} -module_exit(max9850_exit); +module_i2c_driver(max9850_i2c_driver); MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>"); MODULE_DESCRIPTION("ASoC MAX9850 codec driver"); diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 3a2ba3d8fd6d..d15e5943c85e 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -291,17 +291,7 @@ static struct i2c_driver max9877_i2c_driver = { .id_table = max9877_i2c_id, }; -static int __init max9877_init(void) -{ - return i2c_add_driver(&max9877_i2c_driver); -} -module_init(max9877_init); - -static void __exit max9877_exit(void) -{ - i2c_del_driver(&max9877_i2c_driver); -} -module_exit(max9877_exit); +module_i2c_driver(max9877_i2c_driver); MODULE_DESCRIPTION("ASoC MAX9877 amp driver"); MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 6276e352125f..8f726c063f42 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -581,6 +581,8 @@ static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); + codec->control_data = priv->mc13xxx; + mc13xxx_lock(priv->mc13xxx); /* these are the reset values */ diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 8af6a5245b18..df2f99d1d428 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -239,6 +239,7 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = { {"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */ {"LO", NULL, "DAC"}, /* dac --> line_out */ + {"LINE_IN", NULL, "VAG_POWER"}, {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */ {"HP", NULL, "Headphone Mux"}, /* hp_mux --> hp */ @@ -1357,8 +1358,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) if (ret) goto err; - snd_soc_dapm_new_widgets(&codec->dapm); - return 0; err: diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 8d717f4b5a87..51b7313a4c14 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1006,17 +1006,7 @@ static struct i2c_driver sta32x_i2c_driver = { .id_table = sta32x_i2c_id, }; -static int __init sta32x_init(void) -{ - return i2c_add_driver(&sta32x_i2c_driver); -} -module_init(sta32x_init); - -static void __exit sta32x_exit(void) -{ - i2c_del_driver(&sta32x_i2c_driver); -} -module_exit(sta32x_exit); +module_i2c_driver(sta32x_i2c_driver); MODULE_DESCRIPTION("ASoC STA32X driver"); MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>"); diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 0c225cd569d2..9e3144862386 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -358,7 +358,7 @@ static int sta529_resume(struct snd_soc_codec *codec) return 0; } -struct snd_soc_codec_driver sta529_codec_driver = { +static const struct snd_soc_codec_driver sta529_codec_driver = { .probe = sta529_probe, .remove = sta529_remove, .set_bias_level = sta529_set_bias_level, diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 982e437799a8..33c0f3d39c87 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -340,6 +340,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); + codec->control_data = codec; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) goto codec_err; diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index b0a73d37ed52..f230292ba96b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -746,24 +746,7 @@ static struct i2c_driver aic32x4_i2c_driver = { .id_table = aic32x4_i2c_id, }; -static int __init aic32x4_modinit(void) -{ - int ret = 0; - - ret = i2c_add_driver(&aic32x4_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(aic32x4_modinit); - -static void __exit aic32x4_exit(void) -{ - i2c_del_driver(&aic32x4_i2c_driver); -} -module_exit(aic32x4_exit); +module_i2c_driver(aic32x4_i2c_driver); MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index dc78f5a4bcbf..01485bd51404 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1499,23 +1499,7 @@ static struct i2c_driver aic3x_i2c_driver = { .id_table = aic3x_i2c_id, }; -static int __init aic3x_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&aic3x_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n", - ret); - } - return ret; -} -module_init(aic3x_modinit); - -static void __exit aic3x_exit(void) -{ - i2c_del_driver(&aic3x_i2c_driver); -} -module_exit(aic3x_exit); +module_i2c_driver(aic3x_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 0dd41077ab79..d2e16c5d7d1f 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1621,24 +1621,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = { .id_table = tlv320dac33_i2c_id, }; -static int __init dac33_module_init(void) -{ - int r; - r = i2c_add_driver(&tlv320dac33_i2c_driver); - if (r < 0) { - printk(KERN_ERR "DAC33: driver registration failed\n"); - return r; - } - return 0; -} -module_init(dac33_module_init); - -static void __exit dac33_module_exit(void) -{ - i2c_del_driver(&tlv320dac33_i2c_driver); -} -module_exit(dac33_module_exit); - +module_i2c_driver(tlv320dac33_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver"); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6fe4aa3ac544..565ff39ad3a3 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -487,19 +487,8 @@ static struct i2c_driver tpa6130a2_i2c_driver = { .id_table = tpa6130a2_id, }; -static int __init tpa6130a2_init(void) -{ - return i2c_add_driver(&tpa6130a2_i2c_driver); -} - -static void __exit tpa6130a2_exit(void) -{ - i2c_del_driver(&tpa6130a2_i2c_driver); -} +module_i2c_driver(tpa6130a2_i2c_driver); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver"); MODULE_LICENSE("GPL"); - -module_init(tpa6130a2_init); -module_exit(tpa6130a2_exit); diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 3fd5b29dc933..89cd6fcad015 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -858,17 +858,7 @@ static struct i2c_driver wm2000_i2c_driver = { .id_table = wm2000_i2c_id, }; -static int __init wm2000_init(void) -{ - return i2c_add_driver(&wm2000_i2c_driver); -} -module_init(wm2000_init); - -static void __exit wm2000_exit(void) -{ - i2c_del_driver(&wm2000_i2c_driver); -} -module_exit(wm2000_exit); +module_i2c_driver(wm2000_i2c_driver); MODULE_DESCRIPTION("ASoC WM2000 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 32682c1b7cde..71debd0a3822 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2270,17 +2270,7 @@ static struct i2c_driver wm2200_i2c_driver = { .id_table = wm2200_i2c_id, }; -static int __init wm2200_modinit(void) -{ - return i2c_add_driver(&wm2200_i2c_driver); -} -module_init(wm2200_modinit); - -static void __exit wm2200_exit(void) -{ - i2c_del_driver(&wm2200_i2c_driver); -} -module_exit(wm2200_exit); +module_i2c_driver(wm2200_i2c_driver); MODULE_DESCRIPTION("ASoC WM2200 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 6537f16d383e..4c2fc361051c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -285,6 +285,10 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, + ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, + ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 8033f7065189..3db6e6e7a591 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -305,6 +305,10 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, + ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, + ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 73f1c8d7bafb..839414f9e2ed 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2241,23 +2241,7 @@ static struct i2c_driver wm8903_i2c_driver = { .id_table = wm8903_i2c_id, }; -static int __init wm8903_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8903_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8903_modinit); - -static void __exit wm8903_exit(void) -{ - i2c_del_driver(&wm8903_i2c_driver); -} -module_exit(wm8903_exit); +module_i2c_driver(wm8903_i2c_driver); MODULE_DESCRIPTION("ASoC WM8903 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>"); diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 481a3d9cfe48..b20aa4e7c3f9 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -785,23 +785,7 @@ static struct i2c_driver wm8940_i2c_driver = { .id_table = wm8940_i2c_id, }; -static int __init wm8940_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8940_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8940_modinit); - -static void __exit wm8940_exit(void) -{ - i2c_del_driver(&wm8940_i2c_driver); -} -module_exit(wm8940_exit); +module_i2c_driver(wm8940_i2c_driver); MODULE_DESCRIPTION("ASoC WM8940 driver"); MODULE_AUTHOR("Jonathan Cameron"); diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 61fe97433e73..2f1c075755b1 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1071,23 +1071,7 @@ static struct i2c_driver wm8955_i2c_driver = { .id_table = wm8955_i2c_id, }; -static int __init wm8955_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8955_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8955_modinit); - -static void __exit wm8955_exit(void) -{ - i2c_del_driver(&wm8955_i2c_driver); -} -module_exit(wm8955_exit); +module_i2c_driver(wm8955_i2c_driver); MODULE_DESCRIPTION("ASoC WM8955 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 1332692ef81b..00121ba36597 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -946,7 +946,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->mbc_texts = kmalloc(sizeof(char *) * pdata->num_mbc_cfgs, GFP_KERNEL); if (!wm8994->mbc_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d MBC config texts\n", pdata->num_mbc_cfgs); return; @@ -958,9 +958,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->mbc_enum.max = pdata->num_mbc_cfgs; wm8994->mbc_enum.texts = wm8994->mbc_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add MBC mode controls: %d\n", ret); } @@ -974,7 +975,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_texts = kmalloc(sizeof(char *) * pdata->num_vss_cfgs, GFP_KERNEL); if (!wm8994->vss_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d VSS config texts\n", pdata->num_vss_cfgs); return; @@ -986,9 +987,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_enum.max = pdata->num_vss_cfgs; wm8994->vss_enum.texts = wm8994->vss_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add VSS mode controls: %d\n", ret); } @@ -1003,7 +1005,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_hpf_texts = kmalloc(sizeof(char *) * pdata->num_vss_hpf_cfgs, GFP_KERNEL); if (!wm8994->vss_hpf_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d VSS HPF config texts\n", pdata->num_vss_hpf_cfgs); return; @@ -1015,9 +1017,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add VSS HPFmode controls: %d\n", ret); } @@ -1033,7 +1036,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->enh_eq_texts = kmalloc(sizeof(char *) * pdata->num_enh_eq_cfgs, GFP_KERNEL); if (!wm8994->enh_eq_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d enhanced EQ config texts\n", pdata->num_enh_eq_cfgs); return; @@ -1045,9 +1048,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add enhanced EQ controls: %d\n", ret); } diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 96518ac8e24c..804f4116912f 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1010,23 +1010,7 @@ static struct i2c_driver wm8960_i2c_driver = { .id_table = wm8960_i2c_id, }; -static int __init wm8960_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8960_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8960_modinit); - -static void __exit wm8960_exit(void) -{ - i2c_del_driver(&wm8960_i2c_driver); -} -module_exit(wm8960_exit); +module_i2c_driver(wm8960_i2c_driver); MODULE_DESCRIPTION("ASoC WM8960 driver"); MODULE_AUTHOR("Liam Girdwood"); diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 01edbcc754d2..719fb69a17c8 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1114,23 +1114,7 @@ static struct i2c_driver wm8961_i2c_driver = { .id_table = wm8961_i2c_id, }; -static int __init wm8961_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8961_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8961_modinit); - -static void __exit wm8961_exit(void) -{ - i2c_del_driver(&wm8961_i2c_driver); -} -module_exit(wm8961_exit); +module_i2c_driver(wm8961_i2c_driver); MODULE_DESCRIPTION("ASoC WM8961 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index eaf65863ec21..aa9ce9dd7d8a 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2501,6 +2501,9 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, /* VMID 2*250k */ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x100); + + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + msleep(100); break; case SND_SOC_BIAS_OFF: diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index eef783f6b6d6..5ce647758443 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -721,23 +721,7 @@ static struct i2c_driver wm8971_i2c_driver = { .id_table = wm8971_i2c_id, }; -static int __init wm8971_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8971_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8971_modinit); - -static void __exit wm8971_exit(void) -{ - i2c_del_driver(&wm8971_i2c_driver); -} -module_exit(wm8971_exit); +module_i2c_driver(wm8971_i2c_driver); MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d93c03f820c9..9a39511af52a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -659,23 +659,7 @@ static struct i2c_driver wm8974_i2c_driver = { .id_table = wm8974_i2c_id, }; -static int __init wm8974_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8974_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8974_modinit); - -static void __exit wm8974_exit(void) -{ - i2c_del_driver(&wm8974_i2c_driver); -} -module_exit(wm8974_exit); +module_i2c_driver(wm8974_i2c_driver); MODULE_DESCRIPTION("ASoC WM8974 driver"); MODULE_AUTHOR("Liam Girdwood"); diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index a5be3adecf75..5421fd9fbcb5 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1105,23 +1105,7 @@ static struct i2c_driver wm8978_i2c_driver = { .id_table = wm8978_i2c_id, }; -static int __init wm8978_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8978_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8978_modinit); - -static void __exit wm8978_exit(void) -{ - i2c_del_driver(&wm8978_i2c_driver); -} -module_exit(wm8978_exit); +module_i2c_driver(wm8978_i2c_driver); MODULE_DESCRIPTION("ASoC WM8978 codec driver"); MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 9ac31ba9b82e..b9dbfebbda13 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1400,23 +1400,7 @@ static struct i2c_driver wm8991_i2c_driver = { .id_table = wm8991_i2c_id, }; -static int __init wm8991_modinit(void) -{ - int ret; - ret = i2c_add_driver(&wm8991_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n", - ret); - } - return 0; -} -module_init(wm8991_modinit); - -static void __exit wm8991_exit(void) -{ - i2c_del_driver(&wm8991_i2c_driver); -} -module_exit(wm8991_exit); +module_i2c_driver(wm8991_i2c_driver); MODULE_DESCRIPTION("ASoC WM8991 driver"); MODULE_AUTHOR("Graeme Gregory"); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bb62f4b3d563..02080da8b451 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -789,11 +789,27 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: return configure_clock(codec); + case SND_SOC_DAPM_POST_PMU: + /* + * JACKDET won't run until we start the clock and it + * only reports deltas, make sure we notify the state + * up the stack on startup. Use a *very* generous + * timeout for paranoia, there's no urgency and we + * don't want false reports. + */ + if (wm8994->jackdet && !wm8994->clk_has_run) { + schedule_delayed_work(&wm8994->jackdet_bootstrap, + msecs_to_jiffies(1000)); + wm8994->clk_has_run = true; + } + break; + case SND_SOC_DAPM_POST_PMD: configure_clock(codec); break; @@ -1632,7 +1648,8 @@ SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0), @@ -2102,6 +2119,10 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, case WM8994_FLL_SRC_LRCLK: case WM8994_FLL_SRC_BCLK: break; + case WM8994_FLL_SRC_INTERNAL: + freq_in = 12000000; + freq_out = 12000000; + break; default: return -EINVAL; } @@ -2161,12 +2182,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset, WM8994_FLL1_N_MASK, - fll.n << WM8994_FLL1_N_SHIFT); + fll.n << WM8994_FLL1_N_SHIFT); snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, - WM8958_FLL1_BYP | + WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | WM8994_FLL1_REFCLK_DIV_MASK | WM8994_FLL1_REFCLK_SRC_MASK, + ((src == WM8994_FLL_SRC_INTERNAL) + << WM8994_FLL1_FRC_NCO_SHIFT) | (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | (src - 1)); @@ -2192,13 +2215,16 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, } } + reg = WM8994_FLL1_ENA; + if (fll.k) - reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; - else - reg = WM8994_FLL1_ENA; + reg |= WM8994_FLL1_FRAC; + if (src == WM8994_FLL_SRC_INTERNAL) + reg |= WM8994_FLL1_OSC_ENA; + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, - WM8994_FLL1_ENA | WM8994_FLL1_FRAC, - reg); + WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA | + WM8994_FLL1_FRAC, reg); if (wm8994->fll_locked_irq) { timeout = wait_for_completion_timeout(&wm8994->fll_locked[id], @@ -2649,7 +2675,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - bclk_rate = params_rate(params) * 2; + bclk_rate = params_rate(params) * 4; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: bclk_rate *= 16; @@ -3027,7 +3053,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec) static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) { - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; struct wm8994_pdata *pdata = wm8994->pdata; struct snd_kcontrol_new controls[] = { SOC_ENUM_EXT("AIF1.1 EQ Mode", @@ -3085,16 +3111,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, controls, + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, ARRAY_SIZE(controls)); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add ReTune Mobile controls: %d\n", ret); } static void wm8994_handle_pdata(struct wm8994_priv *wm8994) { - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; struct wm8994_pdata *pdata = wm8994->pdata; int ret, i; @@ -3123,10 +3149,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) }; /* We need an array of texts for the enum API */ - wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev, + wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev, sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL); if (!wm8994->drc_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d DRC config texts\n", pdata->num_drc_cfgs); return; @@ -3138,10 +3164,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) wm8994->drc_enum.max = pdata->num_drc_cfgs; wm8994->drc_enum.texts = wm8994->drc_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, controls, + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, ARRAY_SIZE(controls)); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add DRC mode controls: %d\n", ret); for (i = 0; i < WM8994_NUM_DRC; i++) @@ -3154,7 +3180,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) if (pdata->num_retune_mobile_cfgs) wm8994_handle_retune_mobile_pdata(wm8994); else - snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls, + snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls, ARRAY_SIZE(wm8994_eq_controls)); for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) { @@ -3236,6 +3262,12 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg); + /* enable MICDET and MICSHRT deboune */ + snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE, + WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK | + WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK, + WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB); + snd_soc_dapm_sync(&codec->dapm); return 0; @@ -3253,10 +3285,13 @@ static void wm8994_mic_work(struct work_struct *work) int ret; int report; + pm_runtime_get_sync(dev); + ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, ®); if (ret < 0) { dev_err(dev, "Failed to read microphone status: %d\n", ret); + pm_runtime_put(dev); return; } @@ -3299,12 +3334,14 @@ static void wm8994_mic_work(struct work_struct *work) snd_soc_jack_report(priv->micdet[1].jack, report, SND_JACK_HEADSET | SND_JACK_BTN_0); + + pm_runtime_put(dev); } static irqreturn_t wm8994_mic_irq(int irq, void *data) { struct wm8994_priv *priv = data; - struct snd_soc_codec *codec = priv->codec; + struct snd_soc_codec *codec = priv->hubs.codec; #ifndef CONFIG_SND_SOC_WM8994_MODULE trace_snd_soc_jack_irq(dev_name(codec->dev)); @@ -3340,7 +3377,7 @@ static void wm8958_default_micdet(u16 status, void *data) snd_soc_jack_report(wm8994->micdet[0].jack, 0, wm8994->btn_mask | - SND_JACK_HEADSET); + SND_JACK_HEADSET); } return; } @@ -3417,16 +3454,19 @@ static void wm8958_default_micdet(u16 status, void *data) static irqreturn_t wm1811_jackdet_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; int reg; bool present; + pm_runtime_get_sync(codec->dev); + mutex_lock(&wm8994->accdet_lock); reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); if (reg < 0) { dev_err(codec->dev, "Failed to read jack status: %d\n", reg); mutex_unlock(&wm8994->accdet_lock); + pm_runtime_put(codec->dev); return IRQ_NONE; } @@ -3491,9 +3531,22 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) SND_JACK_MECHANICAL | SND_JACK_HEADSET | wm8994->btn_mask); + /* Since we only report deltas force an update, ensures we + * avoid bootstrapping issues with the core. */ + snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0); + + pm_runtime_put(codec->dev); return IRQ_HANDLED; } +static void wm1811_jackdet_bootstrap(struct work_struct *work) +{ + struct wm8994_priv *wm8994 = container_of(work, + struct wm8994_priv, + jackdet_bootstrap.work); + wm1811_jackdet_irq(0, wm8994); +} + /** * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ * @@ -3564,6 +3617,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, * otherwise jump straight to microphone detection. */ if (wm8994->jackdet) { + /* Disable debounce for the initial detect */ + snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, + WM1811_JACKDET_DB, 0); + snd_soc_update_bits(codec, WM8958_MICBIAS2, WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); @@ -3591,7 +3648,7 @@ EXPORT_SYMBOL_GPL(wm8958_mic_detect); static irqreturn_t wm8958_mic_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; int reg, count; /* @@ -3602,6 +3659,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) return IRQ_HANDLED; + pm_runtime_get_sync(codec->dev); + /* We may occasionally read a detection without an impedence * range being provided - if that happens loop again. */ @@ -3612,6 +3671,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) dev_err(codec->dev, "Failed to read mic detect status: %d\n", reg); + pm_runtime_put(codec->dev); return IRQ_NONE; } @@ -3639,6 +3699,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) dev_warn(codec->dev, "Accessory detection with no callback\n"); out: + pm_runtime_put(codec->dev); return IRQ_HANDLED; } @@ -3677,15 +3738,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) unsigned int reg; int ret, i; - wm8994->codec = codec; + wm8994->hubs.codec = codec; codec->control_data = control->regmap; snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); - wm8994->codec = codec; - mutex_init(&wm8994->accdet_lock); INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); + INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, + wm1811_jackdet_bootstrap); for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) init_completion(&wm8994->fll_locked[i]); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index d77e06f0a675..f142ec198db3 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -28,10 +28,11 @@ #define WM8994_FLL1 1 #define WM8994_FLL2 2 -#define WM8994_FLL_SRC_MCLK1 1 -#define WM8994_FLL_SRC_MCLK2 2 -#define WM8994_FLL_SRC_LRCLK 3 -#define WM8994_FLL_SRC_BCLK 4 +#define WM8994_FLL_SRC_MCLK1 1 +#define WM8994_FLL_SRC_MCLK2 2 +#define WM8994_FLL_SRC_LRCLK 3 +#define WM8994_FLL_SRC_BCLK 4 +#define WM8994_FLL_SRC_INTERNAL 5 enum wm8994_vmid_mode { WM8994_VMID_NORMAL, @@ -72,7 +73,6 @@ struct wm8994; struct wm8994_priv { struct wm_hubs_data hubs; struct wm8994 *wm8994; - struct snd_soc_codec *codec; int sysclk[2]; int sysclk_rate[2]; int mclk[2]; @@ -81,6 +81,7 @@ struct wm8994_priv { struct completion fll_locked[2]; bool fll_locked_irq; bool fll_byp; + bool clk_has_run; int vmid_refcount; int active_refcount; @@ -134,6 +135,7 @@ struct wm8994_priv { int btn_mask; bool jackdet; int jackdet_mode; + struct delayed_work jackdet_bootstrap; wm8958_micdet_cb jack_cb; void *jack_cb_data; diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 2c2346fdd637..c7ddc56175d1 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -695,17 +695,7 @@ static struct i2c_driver wm9090_i2c_driver = { .id_table = wm9090_id, }; -static int __init wm9090_init(void) -{ - return i2c_add_driver(&wm9090_i2c_driver); -} -module_init(wm9090_init); - -static void __exit wm9090_exit(void) -{ - i2c_del_driver(&wm9090_i2c_driver); -} -module_exit(wm9090_exit); +module_i2c_driver(wm9090_i2c_driver); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("WM9090 ASoC driver"); diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 099e6ec32125..c9c696ca76f7 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -146,7 +146,7 @@ SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1), SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1), -SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), +SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1), SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), @@ -619,6 +619,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) { int ret = 0; + codec->control_data = codec; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); @@ -683,8 +684,8 @@ static int __devexit wm9712_remove(struct platform_device *pdev) static struct platform_driver wm9712_codec_driver = { .driver = { - .name = "wm9712-codec", - .owner = THIS_MODULE, + .name = "wm9712-codec", + .owner = THIS_MODULE, }, .probe = wm9712_probe, diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 3eb19fb71d17..d0b8a3287a85 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1196,6 +1196,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) if (wm9713 == NULL) return -ENOMEM; snd_soc_codec_set_drvdata(codec, wm9713); + codec->control_data = wm9713; /* we don't use regmap! */ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 61baa48823cb..05a02e1b7e92 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -199,15 +199,56 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg) list_add_tail(&cache->list, &hubs->dcs_cache); } +static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec, + u16 *reg_l, u16 *reg_r) +{ + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + u16 dcs_reg, reg; + + switch (hubs->dcs_readback_mode) { + case 2: + dcs_reg = WM8994_DC_SERVO_4E; + break; + case 1: + dcs_reg = WM8994_DC_SERVO_READBACK; + break; + default: + dcs_reg = WM8993_DC_SERVO_3; + break; + } + + /* Different chips in the family support different readback + * methods. + */ + switch (hubs->dcs_readback_mode) { + case 0: + *reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) + & WM8993_DCS_INTEG_CHAN_0_MASK; + *reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) + & WM8993_DCS_INTEG_CHAN_1_MASK; + break; + case 2: + case 1: + reg = snd_soc_read(codec, dcs_reg); + *reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) + >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; + *reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; + break; + default: + WARN(1, "Unknown DCS readback method\n"); + return; + } +} + /* * Startup calibration of the DC servo */ -static void calibrate_dc_servo(struct snd_soc_codec *codec) +static void enable_dc_servo(struct snd_soc_codec *codec) { struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct wm_hubs_dcs_cache *cache; s8 offset; - u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg; + u16 reg_l, reg_r, dcs_cfg, dcs_reg; switch (hubs->dcs_readback_mode) { case 2: @@ -245,27 +286,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) WM8993_DCS_TRIG_STARTUP_1); } - /* Different chips in the family support different readback - * methods. - */ - switch (hubs->dcs_readback_mode) { - case 0: - reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) - & WM8993_DCS_INTEG_CHAN_0_MASK; - reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) - & WM8993_DCS_INTEG_CHAN_1_MASK; - break; - case 2: - case 1: - reg = snd_soc_read(codec, dcs_reg); - reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) - >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; - reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; - break; - default: - WARN(1, "Unknown DCS readback method\n"); - return; - } + wm_hubs_read_dc_servo(codec, ®_l, ®_r); dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); @@ -535,7 +556,7 @@ static int hp_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WM8993_DC_SERVO_1, WM8993_DCS_TIMER_PERIOD_01_MASK, 0); - calibrate_dc_servo(codec); + enable_dc_servo(codec); reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; @@ -1112,6 +1133,8 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; + hubs->codec = codec; + INIT_LIST_HEAD(&hubs->dcs_cache); init_completion(&hubs->dcs_done); diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index da2dc899ce6d..a5a09e6f87d5 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -46,6 +46,8 @@ struct wm_hubs_data { bool dcs_done_irq; struct completion dcs_done; + + struct snd_soc_codec *codec; }; extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 10a2d8c788b7..c80c20a89b11 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -24,7 +24,6 @@ #include <mach/asp.h> #include <mach/edma.h> -#include <mach/mux.h> #include "davinci-pcm.h" #include "davinci-i2s.h" diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 95441bfc8190..d919fb8de7a3 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -21,7 +21,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/io.h> -#include <linux/clk.h> +#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/pcm.h> @@ -776,20 +776,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!dev->clk_active) { - clk_enable(dev->clk); - dev->clk_active = 1; - } + ret = pm_runtime_get_sync(dev->dev); + if (IS_ERR_VALUE(ret)) + dev_err(dev->dev, "pm_runtime_get_sync() failed\n"); davinci_mcasp_start(dev, substream->stream); break; case SNDRV_PCM_TRIGGER_SUSPEND: davinci_mcasp_stop(dev, substream->stream); - if (dev->clk_active) { - clk_disable(dev->clk); - dev->clk_active = 0; - } - + ret = pm_runtime_put_sync(dev->dev); + if (IS_ERR_VALUE(ret)) + dev_err(dev->dev, "pm_runtime_put_sync() failed\n"); break; case SNDRV_PCM_TRIGGER_STOP: @@ -886,12 +883,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } pdata = pdev->dev.platform_data; - dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) - return -ENODEV; + pm_runtime_enable(&pdev->dev); - clk_enable(dev->clk); - dev->clk_active = 1; + ret = pm_runtime_get_sync(&pdev->dev); + if (IS_ERR_VALUE(ret)) { + dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); + return ret; + } dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); if (!dev->base) { @@ -908,6 +906,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->version = pdata->version; dev->txnumevt = pdata->txnumevt; dev->rxnumevt = pdata->rxnumevt; + dev->dev = &pdev->dev; dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; @@ -949,19 +948,18 @@ static int davinci_mcasp_probe(struct platform_device *pdev) return 0; err_release_clk: - clk_disable(dev->clk); - clk_put(dev->clk); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); return ret; } static int davinci_mcasp_remove(struct platform_device *pdev) { - struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); - clk_disable(dev->clk); - clk_put(dev->clk); - dev->clk = NULL; + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 4681acc63606..51479f9ee909 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -40,9 +40,8 @@ struct davinci_audio_dev { struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; int sample_rate; - struct clk *clk; + struct device *dev; unsigned int codec_fmt; - u8 clk_active; /* McASP specific data */ int tdm_slots; diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 28dd76c7cb1c..3c520c46fa4a 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -523,7 +523,7 @@ static int imx_ssi_probe(struct platform_device *pdev) int ret = 0; struct snd_soc_dai_driver *dai; - ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; dev_set_drvdata(&pdev->dev, ssi); @@ -536,7 +536,7 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->irq = platform_get_irq(pdev, 0); - ssi->clk = clk_get(&pdev->dev, NULL); + ssi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); dev_err(&pdev->dev, "Cannot get the clock: %d\n", @@ -551,23 +551,18 @@ static int imx_ssi_probe(struct platform_device *pdev) goto failed_get_resource; } - if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto failed_get_resource; - } - - ssi->base = ioremap(res->start, resource_size(res)); + ssi->base = devm_request_and_ioremap(&pdev->dev, res); if (!ssi->base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENODEV; - goto failed_ioremap; + goto failed_register; } if (ssi->flags & IMX_SSI_USE_AC97) { if (ac97_ssi) { + dev_err(&pdev->dev, "AC'97 SSI already registered\n"); ret = -EBUSY; - goto failed_ac97; + goto failed_register; } ac97_ssi = ssi; setup_channel_to_ac97(ssi); @@ -636,15 +631,10 @@ failed_pdev_fiq_add: failed_pdev_fiq_alloc: snd_soc_unregister_dai(&pdev->dev); failed_register: -failed_ac97: - iounmap(ssi->base); -failed_ioremap: release_mem_region(res->start, resource_size(res)); failed_get_resource: clk_disable_unprepare(ssi->clk); - clk_put(ssi->clk); failed_clk: - kfree(ssi); return ret; } @@ -662,11 +652,8 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev) if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; - iounmap(ssi->base); release_mem_region(res->start, resource_size(res)); clk_disable_unprepare(ssi->clk); - clk_put(ssi->clk); - kfree(ssi); return 0; } diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index aba71bfa33b1..aa037b292f3d 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -394,9 +394,14 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + struct mxs_saif *master_saif; u32 scr, stat; int ret; + master_saif = mxs_saif_get_master(saif); + if (!master_saif) + return -EINVAL; + /* mclk should already be set */ if (!saif->mclk && saif->mclk_in_use) { dev_err(cpu_dai->dev, "set mclk first\n"); @@ -420,6 +425,25 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, return ret; } + /* prepare clk in hw_param, enable in trigger */ + clk_prepare(saif->clk); + if (saif != master_saif) { + /* + * Set an initial clock rate for the saif internal logic to work + * properly. This is important when working in EXTMASTER mode + * that uses the other saif's BITCLK&LRCLK but it still needs a + * basic clock which should be fast enough for the internal + * logic. + */ + clk_enable(saif->clk); + ret = clk_set_rate(saif->clk, 24000000); + clk_disable(saif->clk); + if (ret) + return ret; + + clk_prepare(master_saif->clk); + } + scr = __raw_readl(saif->base + SAIF_CTRL); scr &= ~BM_SAIF_CTRL_WORD_LENGTH; @@ -680,7 +704,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) return ret; } - saif->clk = clk_get(&pdev->dev, NULL); + saif->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(saif->clk)) { ret = PTR_ERR(saif->clk); dev_err(&pdev->dev, "Cannot get the clock: %d\n", @@ -693,8 +717,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) saif->base = devm_request_and_ioremap(&pdev->dev, iores); if (!saif->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENODEV; - goto failed_get_resource; + return -ENODEV; } dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -707,7 +730,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) &saif->dma_param.chan_num); if (ret) { dev_err(&pdev->dev, "failed to get dma channel\n"); - goto failed_get_resource; + return ret; } } else { saif->dma_param.chan_num = dmares->start; @@ -718,7 +741,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) ret = saif->irq; dev_err(&pdev->dev, "failed to get irq resource: %d\n", ret); - goto failed_get_resource; + return ret; } saif->dev = &pdev->dev; @@ -726,7 +749,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) "mxs-saif", saif); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); - goto failed_get_resource; + return ret; } saif->dma_param.chan_irq = platform_get_irq(pdev, 1); @@ -734,7 +757,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) ret = saif->dma_param.chan_irq; dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", ret); - goto failed_get_resource; + return ret; } platform_set_drvdata(pdev, saif); @@ -742,7 +765,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); - goto failed_get_resource; + return ret; } ret = mxs_pcm_platform_register(&pdev->dev); @@ -755,19 +778,14 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) failed_pdev_alloc: snd_soc_unregister_dai(&pdev->dev); -failed_get_resource: - clk_put(saif->clk); return ret; } static int __devexit mxs_saif_remove(struct platform_device *pdev) { - struct mxs_saif *saif = platform_get_drvdata(pdev); - mxs_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); - clk_put(saif->clk); return 0; } diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 9d93793d3077..be525dfe9faa 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -25,6 +25,7 @@ #include <linux/mfd/twl6040.h> #include <linux/platform_data/omap-abe-twl6040.h> #include <linux/module.h> +#include <linux/of.h> #include <sound/core.h> #include <sound/pcm.h> @@ -43,6 +44,8 @@ struct abe_twl6040 { int jack_detection; /* board can detect jack events */ int mclk_freq; /* MCLK frequency speed for twl6040 */ + + struct platform_device *dmic_codec_dev; }; static int omap_abe_hw_params(struct snd_pcm_substream *substream, @@ -185,17 +188,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) int hs_trim; int ret = 0; - /* Disable not connected paths if not used */ - twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); - twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); - twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); - twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); - twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); - twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); - /* * Configure McPDM offset cancellation based on the HSOTRIM value from * twl6040. @@ -216,6 +208,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); } + /* + * NULL pdata means we booted with DT. In this case the routing is + * provided and the card is fully routed, no need to mark pins. + */ + if (!pdata) + return ret; + + /* Disable not connected paths if not used */ + twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); + twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); + twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); + twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); + return ret; } @@ -270,52 +280,116 @@ static struct snd_soc_card omap_abe_card = { static __devinit int omap_abe_probe(struct platform_device *pdev) { struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); + struct device_node *node = pdev->dev.of_node; struct snd_soc_card *card = &omap_abe_card; struct abe_twl6040 *priv; int num_links = 0; - int ret; + int ret = 0; card->dev = &pdev->dev; - if (!pdata) { - dev_err(&pdev->dev, "Missing pdata\n"); - return -ENODEV; - } - priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - if (pdata->card_name) { - card->name = pdata->card_name; + priv->dmic_codec_dev = ERR_PTR(-EINVAL); + + if (node) { + struct device_node *dai_node; + + if (snd_soc_of_parse_card_name(card, "ti,model")) { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + ret = snd_soc_of_parse_audio_routing(card, + "ti,audio-routing"); + if (ret) { + dev_err(&pdev->dev, + "Error while parsing DAPM routing\n"); + return ret; + } + + dai_node = of_parse_phandle(node, "ti,mcpdm", 0); + if (!dai_node) { + dev_err(&pdev->dev, "McPDM node is not provided\n"); + return -EINVAL; + } + abe_twl6040_dai_links[0].cpu_dai_name = NULL; + abe_twl6040_dai_links[0].cpu_of_node = dai_node; + + dai_node = of_parse_phandle(node, "ti,dmic", 0); + if (dai_node) { + num_links = 2; + abe_twl6040_dai_links[1].cpu_dai_name = NULL; + abe_twl6040_dai_links[1].cpu_of_node = dai_node; + + priv->dmic_codec_dev = platform_device_register_simple( + "dmic-codec", -1, NULL, 0); + if (IS_ERR(priv->dmic_codec_dev)) { + dev_err(&pdev->dev, + "Can't instantiate dmic-codec\n"); + return PTR_ERR(priv->dmic_codec_dev); + } + } else { + num_links = 1; + } + + of_property_read_u32(node, "ti,jack-detection", + &priv->jack_detection); + of_property_read_u32(node, "ti,mclk-freq", + &priv->mclk_freq); + if (!priv->mclk_freq) { + dev_err(&pdev->dev, "MCLK frequency not provided\n"); + ret = -EINVAL; + goto err_unregister; + } + + omap_abe_card.fully_routed = 1; + } else if (pdata) { + if (pdata->card_name) { + card->name = pdata->card_name; + } else { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + if (pdata->has_dmic) + num_links = 2; + else + num_links = 1; + + priv->jack_detection = pdata->jack_detection; + priv->mclk_freq = pdata->mclk_freq; } else { - dev_err(&pdev->dev, "Card name is not provided\n"); + dev_err(&pdev->dev, "Missing pdata\n"); return -ENODEV; } - priv->jack_detection = pdata->jack_detection; - priv->mclk_freq = pdata->mclk_freq; - if (!priv->mclk_freq) { dev_err(&pdev->dev, "MCLK frequency missing\n"); - return -ENODEV; + ret = -ENODEV; + goto err_unregister; } - if (pdata->has_dmic) - num_links = 2; - else - num_links = 1; - card->dai_link = abe_twl6040_dai_links; card->num_links = num_links; snd_soc_card_set_drvdata(card, priv); ret = snd_soc_register_card(card); - if (ret) + if (ret) { dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + goto err_unregister; + } + + return 0; + +err_unregister: + if (!IS_ERR(priv->dmic_codec_dev)) + platform_device_unregister(priv->dmic_codec_dev); return ret; } @@ -323,17 +397,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) static int __devexit omap_abe_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); snd_soc_unregister_card(card); + if (!IS_ERR(priv->dmic_codec_dev)) + platform_device_unregister(priv->dmic_codec_dev); + return 0; } +static const struct of_device_id omap_abe_of_match[] = { + {.compatible = "ti,abe-twl6040", }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_abe_of_match); + static struct platform_driver omap_abe_driver = { .driver = { .name = "omap-abe-twl6040", .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, + .of_match_table = omap_abe_of_match, }, .probe = omap_abe_probe, .remove = __devexit_p(omap_abe_remove), diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 1046083e90a0..acdd3ef14e08 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -820,3 +820,4 @@ module_platform_driver(asoc_mcbsp_driver); MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-mcbsp"); diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 2c66e2498a45..f7babb374a37 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -445,9 +445,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) { struct omap_mcpdm *mcpdm; struct resource *res; - int ret = 0; - mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); + mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL); if (!mcpdm) return -ENOMEM; @@ -456,55 +455,30 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) mutex_init(&mcpdm->mutex); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no resource\n"); - goto err_res; - } + if (res == NULL) + return -ENOMEM; - if (!request_mem_region(res->start, resource_size(res), "McPDM")) { - ret = -EBUSY; - goto err_res; - } + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), "McPDM")) + return -EBUSY; - mcpdm->io_base = ioremap(res->start, resource_size(res)); - if (!mcpdm->io_base) { - ret = -ENOMEM; - goto err_iomap; - } + mcpdm->io_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!mcpdm->io_base) + return -ENOMEM; mcpdm->irq = platform_get_irq(pdev, 0); - if (mcpdm->irq < 0) { - ret = mcpdm->irq; - goto err_irq; - } + if (mcpdm->irq < 0) + return mcpdm->irq; mcpdm->dev = &pdev->dev; - ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); - if (!ret) - return 0; - -err_irq: - iounmap(mcpdm->io_base); -err_iomap: - release_mem_region(res->start, resource_size(res)); -err_res: - kfree(mcpdm); - return ret; + return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); } static int __devexit asoc_mcpdm_remove(struct platform_device *pdev) { - struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev); - struct resource *res; - snd_soc_unregister_dai(&pdev->dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iounmap(mcpdm->io_base); - release_mem_region(res->start, resource_size(res)); - - kfree(mcpdm); return 0; } diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 5a649da9122a..f0feb06615f8 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -441,3 +441,4 @@ module_platform_driver(omap_pcm_driver); MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-pcm-audio"); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index fe3995ce9b38..fb5600083612 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -199,6 +199,14 @@ config SND_SOC_TOBERMORY select SND_SAMSUNG_I2S select SND_SOC_WM8962 +config SND_SOC_BELLS + tristate "Audio support for Wolfson Bells" + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + select SND_SAMSUNG_I2S + select SND_SOC_WM5102 + select SND_SOC_WM5110 + select SND_SOC_WM9081 + config SND_SOC_LOWLAND tristate "Audio support for Wolfson Lowland" depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 9d03beb40c86..709f6059ad67 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -42,6 +42,7 @@ snd-soc-speyside-objs := speyside.o snd-soc-tobermory-objs := tobermory.o snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o +snd-soc-bells-objs := bells.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -65,3 +66,4 @@ obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o +obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c new file mode 100644 index 000000000000..5dc10dfc0d42 --- /dev/null +++ b/sound/soc/samsung/bells.c @@ -0,0 +1,346 @@ +/* + * Bells audio support + * + * Copyright 2012 Wolfson Microelectronics + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include <linux/gpio.h> +#include <linux/module.h> + +#include "../codecs/wm5102.h" +#include "../codecs/wm9081.h" + +/* + * 44.1kHz based clocks for the SYSCLK domain, use a very high clock + * to allow all the DSP functionality to be enabled if desired. + */ +#define SYSCLK_RATE (44100 * 1024) + +/* 48kHz based clocks for the ASYNC domain */ +#define ASYNCCLK_RATE (48000 * 512) + +/* BCLK2 is fixed at this currently */ +#define BCLK2_RATE (64 * 8000) + +/* + * Expect a 24.576MHz crystal if one is fitted (the driver will function + * if this is not fitted). + */ +#define MCLK_RATE 24576000 + +#define WM9081_AUDIO_RATE 44100 +#define WM9081_MCLK_RATE (WM9081_AUDIO_RATE * 256) + +static int bells_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { + ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + SYSCLK_RATE); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + + ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + ARIZONA_FLL_SRC_AIF2BCLK, + BCLK2_RATE, + ASYNCCLK_RATE); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + } + break; + + default: + break; + } + + return 0; +} + +static int bells_set_bias_level_post(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_STANDBY: + ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL: %d\n", ret); + return ret; + } + break; + + default: + break; + } + + dapm->bias_level = level; + + return 0; +} + +static int bells_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_codec *codec = card->rtd[0].codec; + struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; + struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai; + struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret != 0) { + dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); + if (ret != 0) { + dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret != 0) { + dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE, + SND_SOC_CLOCK_IN); + if (ret != 0) { + dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, + WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT); + if (ret != 0) { + dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE, + SND_SOC_CLOCK_IN); + if (ret != 0) { + dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, + 0, WM9081_MCLK_RATE, 0); + if (ret != 0) { + dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_pcm_stream baseband_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 2, + .channels_max = 2, +}; + +static const struct snd_soc_pcm_stream sub_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = WM9081_AUDIO_RATE, + .rate_max = WM9081_AUDIO_RATE, + .channels_min = 2, + .channels_max = 2, +}; + +static struct snd_soc_dai_link bells_dai_wm5102[] = { + { + .name = "CPU", + .stream_name = "CPU", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm5102-aif1", + .platform_name = "samsung-audio", + .codec_name = "wm5102-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "Baseband", + .stream_name = "Baseband", + .cpu_dai_name = "wm5102-aif2", + .codec_dai_name = "wm1250-ev1", + .codec_name = "wm1250-ev1.1-0027", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + .params = &baseband_params, + }, + { + .name = "Sub", + .stream_name = "Sub", + .cpu_dai_name = "wm5102-aif3", + .codec_dai_name = "wm9081-hifi", + .codec_name = "wm9081.1-006c", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .ignore_suspend = 1, + .params = &sub_params, + }, +}; + +static struct snd_soc_dai_link bells_dai_wm5110[] = { + { + .name = "CPU", + .stream_name = "CPU", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm5110-aif1", + .platform_name = "samsung-audio", + .codec_name = "wm5110-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "Baseband", + .stream_name = "Baseband", + .cpu_dai_name = "wm5110-aif2", + .codec_dai_name = "wm1250-ev1", + .codec_name = "wm1250-ev1.1-0027", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + .params = &baseband_params, + }, + { + .name = "Sub", + .stream_name = "Sub", + .cpu_dai_name = "wm5102-aif3", + .codec_dai_name = "wm9081-hifi", + .codec_name = "wm9081.1-006c", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .ignore_suspend = 1, + .params = &sub_params, + }, +}; + +static struct snd_soc_codec_conf bells_codec_conf[] = { + { + .dev_name = "wm9081.1-006c", + .name_prefix = "Sub", + }, +}; + +static struct snd_soc_dapm_route bells_routes[] = { + { "Sub CLK_SYS", NULL, "OPCLK" }, +}; + +static struct snd_soc_card bells_cards[] = { + { + .name = "Bells WM5102", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm5102, + .num_links = ARRAY_SIZE(bells_dai_wm5102), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + }, + { + .name = "Bells WM5110", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm5110, + .num_links = ARRAY_SIZE(bells_dai_wm5110), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + }, +}; + + +static __devinit int bells_probe(struct platform_device *pdev) +{ + int ret; + + bells_cards[pdev->id].dev = &pdev->dev; + + ret = snd_soc_register_card(&bells_cards[pdev->id]); + if (ret) { + dev_err(&pdev->dev, + "snd_soc_register_card(%s) failed: %d\n", + bells_cards[pdev->id].name, ret); + return ret; + } + + return 0; +} + +static int __devexit bells_remove(struct platform_device *pdev) +{ + snd_soc_unregister_card(&bells_cards[pdev->id]); + + return 0; +} + +static struct platform_driver bells_driver = { + .driver = { + .name = "bells", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = bells_probe, + .remove = __devexit_p(bells_remove), +}; + +module_platform_driver(bells_driver); + +MODULE_DESCRIPTION("Bells audio support"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bells"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f219b2f7ee68..f585d0239551 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1096,7 +1096,7 @@ static int soc_probe_codec(struct snd_soc_card *card, } /* If the driver didn't set I/O up try regmap */ - if (!codec->control_data) + if (!codec->write && dev_get_regmap(codec->dev, NULL)) snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); if (driver->controls) @@ -1814,7 +1814,6 @@ base_error: static int soc_probe(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - int ret = 0; /* * no card, so machine driver should be registering card @@ -1830,13 +1829,7 @@ static int soc_probe(struct platform_device *pdev) /* Bodge while we unpick instantiation */ card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to register card\n"); - return ret; - } - - return 0; + return snd_soc_register_card(card); } static int soc_cleanup_card_resources(struct snd_soc_card *card) @@ -3715,6 +3708,9 @@ int snd_soc_register_dai(struct device *dev, } } + if (!dai->codec) + dai->dapm.idle_bias_off = 1; + list_add(&dai->list, &dai_list); mutex_unlock(&client_mutex); @@ -3803,6 +3799,9 @@ int snd_soc_register_dais(struct device *dev, } } + if (!dai->codec) + dai->dapm.idle_bias_off = 1; + list_add(&dai->list, &dai_list); mutex_unlock(&client_mutex); diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 7f8b3b7428bb..2ca3c734a288 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -83,11 +83,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) jack->status &= ~mask; jack->status |= status & mask; - /* The DAPM sync is expensive enough to be worth skipping. - * However, empty mask means pin synchronization is desired. */ - if (mask && (jack->status == oldstatus)) - goto out; - trace_snd_soc_jack_notify(jack, status); list_for_each_entry(pin, &jack->pins, list) { @@ -109,7 +104,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) snd_jack_report(jack->jack, jack->status); -out: mutex_unlock(&jack->mutex); } EXPORT_SYMBOL_GPL(snd_soc_jack_report); diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index d684df294c0c..e463529b38bb 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -177,7 +177,7 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) } alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (alc5632->gpio_hp_det == -ENODEV) + if (alc5632->gpio_hp_det == -EPROBE_DEFER) return -EPROBE_DEFER; ret = snd_soc_of_parse_card_name(card, "nvidia,model"); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 0c5bb33d258e..d4f14e492341 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -284,27 +284,27 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) } else if (np) { pdata->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios", 0); - if (pdata->gpio_spkr_en == -ENODEV) + if (pdata->gpio_spkr_en == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios", 0); - if (pdata->gpio_hp_mute == -ENODEV) + if (pdata->gpio_hp_mute == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (pdata->gpio_hp_det == -ENODEV) + if (pdata->gpio_hp_det == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_int_mic_en = of_get_named_gpio(np, "nvidia,int-mic-en-gpios", 0); - if (pdata->gpio_int_mic_en == -ENODEV) + if (pdata->gpio_int_mic_en == -EPROBE_DEFER) return -EPROBE_DEFER; pdata->gpio_ext_mic_en = of_get_named_gpio(np, "nvidia,ext-mic-en-gpios", 0); - if (pdata->gpio_ext_mic_en == -ENODEV) + if (pdata->gpio_ext_mic_en == -EPROBE_DEFER) return -EPROBE_DEFER; } diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 62ac0285bfaf..772cb19d2fb3 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -21,7 +21,7 @@ #include <linux/mfd/dbx500-prcmu.h> #include <mach/hardware.h> -#include <mach/board-mop500-msp.h> +#include <mach/msp.h> #include <sound/soc.h> #include <sound/soc-dai.h> @@ -760,6 +760,9 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp_i2s_drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + drvdata->fmt = 0; drvdata->slots = 1; drvdata->tx_mask = 0x01; diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index ee14d2dac2f5..36be11e47ad6 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <mach/hardware.h> -#include <mach/board-mop500-msp.h> +#include <mach/msp.h> #include <sound/soc.h> @@ -673,6 +673,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL); msp = *msp_p; + if (!msp) + return -ENOMEM; msp->id = platform_data->id; msp->dev = &pdev->dev; diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 7f71b4a0d4bc..2d9136da9865 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -17,7 +17,7 @@ #include <linux/platform_device.h> -#include <mach/board-mop500-msp.h> +#include <mach/msp.h> #define MSP_INPUT_FREQ_APB 48000000 |