diff options
Diffstat (limited to 'sound/soc/codecs/wm9090.c')
-rw-r--r-- | sound/soc/codecs/wm9090.c | 183 |
1 files changed, 59 insertions, 124 deletions
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 1592250daec0..7a1825418ee4 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -34,8 +34,6 @@ #include "wm9090.h" -static struct snd_soc_codec *wm9090_codec; - static const u16 wm9090_reg_defaults[] = { 0x9093, /* R0 - Software Reset */ 0x0006, /* R1 - Power Management (1) */ @@ -142,15 +140,10 @@ static const u16 wm9090_reg_defaults[] = { /* This struct is used to save the context */ struct wm9090_priv { - /* We're not really registering as a CODEC since ASoC core - * does not yet support multiple CODECs but having the CODEC - * structure means we can reuse some of the ASoC core - * features. - */ - struct snd_soc_codec codec; struct mutex mutex; u16 reg_cache[WM9090_MAX_REGISTER + 1]; struct wm9090_platform_data pdata; + void *control_data; }; static int wm9090_volatile(unsigned int reg) @@ -523,7 +516,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Restore the register cache */ - for (i = 1; i < codec->reg_cache_size; i++) { + for (i = 1; i < codec->driver->reg_cache_size; i++) { if (reg_cache[i] == wm9090_reg_defaults[i]) continue; if (wm9090_volatile(i)) @@ -556,51 +549,67 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm9090_probe(struct platform_device *pdev) +static int wm9090_probe(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - int ret = 0; + struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); + int ret; - if (wm9090_codec == NULL) { - dev_err(&pdev->dev, "Codec device not registered\n"); - return -ENODEV; + codec->control_data = wm9090->control_data; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; } - socdev->card->codec = wm9090_codec; - codec = wm9090_codec; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(codec->dev, "failed to create pcms: %d\n", ret); - goto pcm_err; + ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); + if (ret < 0) + return ret; + if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { + dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret); + return -EINVAL; } + ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0); + if (ret < 0) + return ret; + + /* Configure some defaults; they will be written out when we + * bring the bias up. + */ + wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU + | WM9090_IN1A_ZC; + wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU + | WM9090_IN1B_ZC; + wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU + | WM9090_IN2A_ZC; + wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU + | WM9090_IN2B_ZC; + wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |= + WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC; + wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= + WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC; + wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |= + WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC; + + wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA; + + wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm9090_add_controls(codec); return 0; - -pcm_err: - return ret; } #ifdef CONFIG_PM -static int wm9090_suspend(struct platform_device *pdev, pm_message_t state) +static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } -static int wm9090_resume(struct platform_device *pdev) +static int wm9090_resume(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; @@ -610,29 +619,29 @@ static int wm9090_resume(struct platform_device *pdev) #define wm9090_resume NULL #endif -static int wm9090_remove(struct platform_device *pdev) +static int wm9090_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); + wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } -struct snd_soc_codec_device soc_codec_dev_wm9090 = { +static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { .probe = wm9090_probe, .remove = wm9090_remove, .suspend = wm9090_suspend, .resume = wm9090_resume, + .set_bias_level = wm9090_set_bias_level, + .reg_cache_size = (WM9090_MAX_REGISTER + 1), + .reg_word_size = sizeof(u16), + .reg_cache_default = wm9090_reg_defaults, + .volatile_register = wm9090_volatile, }; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090); static int wm9090_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm9090_priv *wm9090; - struct snd_soc_codec *codec; int ret; wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL); @@ -640,102 +649,28 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Can not allocate memory\n"); return -ENOMEM; } - codec = &wm9090->codec; if (i2c->dev.platform_data) memcpy(&wm9090->pdata, i2c->dev.platform_data, sizeof(wm9090->pdata)); - wm9090_codec = codec; - i2c_set_clientdata(i2c, wm9090); + wm9090->control_data = i2c; + mutex_init(&wm9090->mutex); - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->control_data = i2c; - snd_soc_codec_set_drvdata(codec, wm9090); - codec->dev = &i2c->dev; - codec->name = "WM9090"; - codec->owner = THIS_MODULE; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->set_bias_level = wm9090_set_bias_level, - codec->reg_cache_size = WM9090_MAX_REGISTER + 1; - codec->reg_cache = &wm9090->reg_cache; - codec->volatile_register = wm9090_volatile; - - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - - memcpy(&wm9090->reg_cache, wm9090_reg_defaults, - sizeof(wm9090->reg_cache)); - - ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); - if (ret < 0) - goto err; - if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { - dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret); - ret = -EINVAL; - goto err; - } - - ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0); + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_wm9090, NULL, 0); if (ret < 0) - goto err; - - /* Configure some defaults; they will be written out when we - * bring the bias up. - */ - wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU - | WM9090_IN1A_ZC; - wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU - | WM9090_IN1B_ZC; - wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU - | WM9090_IN2A_ZC; - wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU - | WM9090_IN2B_ZC; - wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |= - WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC; - wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= - WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC; - wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |= - WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC; - - wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA; - - wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - ret = snd_soc_register_codec(codec); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err_bias; - } - - return 0; - -err_bias: - wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); -err: - kfree(wm9090); - i2c_set_clientdata(i2c, NULL); - wm9090_codec = NULL; - + kfree(wm9090); return ret; } static int wm9090_i2c_remove(struct i2c_client *i2c) { struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); - struct snd_soc_codec *codec = &wm9090->codec; - snd_soc_unregister_codec(codec); - wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_codec(&i2c->dev); kfree(wm9090); - wm9090_codec = NULL; return 0; } @@ -748,7 +683,7 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id); static struct i2c_driver wm9090_i2c_driver = { .driver = { - .name = "wm9090", + .name = "wm9090-codec", .owner = THIS_MODULE, }, .probe = wm9090_i2c_probe, |