diff options
Diffstat (limited to 'sound/soc/codecs/wm8776.c')
| -rw-r--r-- | sound/soc/codecs/wm8776.c | 247 | 
1 files changed, 62 insertions, 185 deletions
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 4e212ed62ea6..053030679c1a 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -31,20 +31,13 @@  #include "wm8776.h" -static struct snd_soc_codec *wm8776_codec; -struct snd_soc_codec_device soc_codec_dev_wm8776; -  /* codec private data */  struct wm8776_priv { -	struct snd_soc_codec codec; +	enum snd_soc_control_type control_type;  	u16 reg_cache[WM8776_CACHEREGNUM];  	int sysclk[2];  }; -#ifdef CONFIG_SPI_MASTER -static int wm8776_spi_write(struct spi_device *spi, const char *data, int len); -#endif -  static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {  	0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */  	0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */ @@ -144,7 +137,7 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	struct snd_soc_codec *codec = dai->codec;  	int reg, iface, master; -	switch (dai->id) { +	switch (dai->driver->id) {  	case WM8776_DAI_DAC:  		reg = WM8776_DACIFCTRL;  		master = 0x80; @@ -233,7 +226,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,  	iface = 0; -	switch (dai->id) { +	switch (dai->driver->id) {  	case WM8776_DAI_DAC:  		iface_reg = WM8776_DACIFCTRL;  		master = 0x80; @@ -267,7 +260,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,  	/* Only need to set MCLK/LRCLK ratio if we're master */  	if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {  		for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) { -			if (wm8776->sysclk[dai->id] / params_rate(params) +			if (wm8776->sysclk[dai->driver->id] / params_rate(params)  			    == mclk_ratios[i])  				break;  		} @@ -275,7 +268,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,  		if (i == ARRAY_SIZE(mclk_ratios)) {  			dev_err(codec->dev,  				"Unable to configure MCLK ratio %d/%d\n", -				wm8776->sysclk[dai->id], params_rate(params)); +				wm8776->sysclk[dai->driver->id], params_rate(params));  			return -EINVAL;  		} @@ -305,9 +298,9 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,  	struct snd_soc_codec *codec = dai->codec;  	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec); -	BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk)); +	BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk)); -	wm8776->sysclk[dai->id] = freq; +	wm8776->sysclk[dai->driver->id] = freq;  	return 0;  } @@ -357,10 +350,10 @@ static struct snd_soc_dai_ops wm8776_adc_ops = {  	.set_sysclk     = wm8776_set_sysclk,  }; -struct snd_soc_dai wm8776_dai[] = { +static struct snd_soc_dai_driver wm8776_dai[] = {  	{ -		.name = "WM8776 Playback", -		.id = WM8776_DAI_DAC, +		.name = "wm8776-hifi-playback", +		.id	= WM8776_DAI_DAC,  		.playback = {  			.stream_name = "Playback",  			.channels_min = 2, @@ -371,8 +364,8 @@ struct snd_soc_dai wm8776_dai[] = {  		.ops = &wm8776_dac_ops,  	},  	{ -		.name = "WM8776 Capture", -		.id = WM8776_DAI_ADC, +		.name = "wm8776-hifi-capture", +		.id	= WM8776_DAI_ADC,  		.capture = {  			.stream_name = "Capture",  			.channels_min = 2, @@ -383,23 +376,17 @@ struct snd_soc_dai wm8776_dai[] = {  		.ops = &wm8776_adc_ops,  	},  }; -EXPORT_SYMBOL_GPL(wm8776_dai);  #ifdef CONFIG_PM -static int wm8776_suspend(struct platform_device *pdev, pm_message_t state) +static int wm8776_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; -  	wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);  	return 0;  } -static int wm8776_resume(struct platform_device *pdev) +static int wm8776_resume(struct snd_soc_codec *codec)  { -	struct snd_soc_device *socdev = platform_get_drvdata(pdev); -	struct snd_soc_codec *codec = socdev->card->codec;  	int i;  	u8 data[2];  	u16 *cache = codec->reg_cache; @@ -422,27 +409,30 @@ static int wm8776_resume(struct platform_device *pdev)  #define wm8776_resume NULL  #endif -static int wm8776_probe(struct platform_device *pdev) +static int wm8776_probe(struct snd_soc_codec *codec)  { -	struct snd_soc_device *socdev = platform_get_drvdata(pdev); -	struct snd_soc_codec *codec; +	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);  	int ret = 0; -	if (wm8776_codec == NULL) { -		dev_err(&pdev->dev, "Codec device not registered\n"); -		return -ENODEV; +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); +		return ret;  	} -	socdev->card->codec = wm8776_codec; -	codec = wm8776_codec; - -	/* register pcms */ -	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); +	ret = wm8776_reset(codec);  	if (ret < 0) { -		dev_err(codec->dev, "failed to create pcms: %d\n", ret); -		goto pcm_err; +		dev_err(codec->dev, "Failed to issue reset: %d\n", ret); +		return ret;  	} +	wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + +	/* Latch the update bits; right channel only since we always +	 * update both. */ +	snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); +	snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100); +  	snd_soc_add_controls(codec, wm8776_snd_controls,  			     ARRAY_SIZE(wm8776_snd_controls));  	snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets, @@ -450,168 +440,56 @@ static int wm8776_probe(struct platform_device *pdev)  	snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));  	return ret; - -pcm_err: -	return ret;  }  /* power down chip */ -static int wm8776_remove(struct platform_device *pdev) +static int wm8776_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); - +	wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);  	return 0;  } -struct snd_soc_codec_device soc_codec_dev_wm8776 = { +static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {  	.probe = 	wm8776_probe,  	.remove = 	wm8776_remove,  	.suspend = 	wm8776_suspend,  	.resume =	wm8776_resume, +	.set_bias_level = wm8776_set_bias_level, +	.reg_cache_size = sizeof(wm8776_reg), +	.reg_word_size = sizeof(u16), +	.reg_cache_default = wm8776_reg,  }; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776); - -static int wm8776_register(struct wm8776_priv *wm8776, -			   enum snd_soc_control_type control) -{ -	int ret, i; -	struct snd_soc_codec *codec = &wm8776->codec; - -	if (wm8776_codec) { -		dev_err(codec->dev, "Another WM8776 is registered\n"); -		ret = -EINVAL; -		goto err; -	} - -	mutex_init(&codec->mutex); -	INIT_LIST_HEAD(&codec->dapm_widgets); -	INIT_LIST_HEAD(&codec->dapm_paths); - -	snd_soc_codec_set_drvdata(codec, wm8776); -	codec->name = "WM8776"; -	codec->owner = THIS_MODULE; -	codec->bias_level = SND_SOC_BIAS_OFF; -	codec->set_bias_level = wm8776_set_bias_level; -	codec->dai = wm8776_dai; -	codec->num_dai = ARRAY_SIZE(wm8776_dai); -	codec->reg_cache_size = WM8776_CACHEREGNUM; -	codec->reg_cache = &wm8776->reg_cache; - -	memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg)); - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		goto err; -	} - -	for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++) -		wm8776_dai[i].dev = codec->dev; - -	ret = wm8776_reset(codec); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to issue reset: %d\n", ret); -		goto err; -	} - -	wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - -	/* Latch the update bits; right channel only since we always -	 * update both. */ -	snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); -	snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100); - -	wm8776_codec = codec; - -	ret = snd_soc_register_codec(codec); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to register codec: %d\n", ret); -		goto err; -	} - -	ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai)); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); -		goto err_codec; -	} - -	return 0; - -err_codec: -	snd_soc_unregister_codec(codec); -err: -	kfree(wm8776); -	return ret; -} - -static void wm8776_unregister(struct wm8776_priv *wm8776) -{ -	wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF); -	snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai)); -	snd_soc_unregister_codec(&wm8776->codec); -	kfree(wm8776); -	wm8776_codec = NULL; -}  #if defined(CONFIG_SPI_MASTER) -static int wm8776_spi_write(struct spi_device *spi, const char *data, int len) -{ -	struct spi_transfer t; -	struct spi_message m; -	u8 msg[2]; - -	if (len <= 0) -		return 0; - -	msg[0] = data[0]; -	msg[1] = data[1]; - -	spi_message_init(&m); -	memset(&t, 0, (sizeof t)); - -	t.tx_buf = &msg[0]; -	t.len = len; - -	spi_message_add_tail(&t, &m); -	spi_sync(spi, &m); - -	return len; -} -  static int __devinit wm8776_spi_probe(struct spi_device *spi)  { -	struct snd_soc_codec *codec;  	struct wm8776_priv *wm8776; +	int ret;  	wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);  	if (wm8776 == NULL)  		return -ENOMEM; -	codec = &wm8776->codec; -	codec->control_data = spi; -	codec->hw_write = (hw_write_t)wm8776_spi_write; -	codec->dev = &spi->dev; +	wm8776->control_type = SND_SOC_SPI; +	spi_set_drvdata(spi, wm8776); -	dev_set_drvdata(&spi->dev, wm8776); - -	return wm8776_register(wm8776, SND_SOC_SPI); +	ret = snd_soc_register_codec(&spi->dev, +			&soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai)); +	if (ret < 0) +		kfree(wm8776); +	return ret;  }  static int __devexit wm8776_spi_remove(struct spi_device *spi)  { -	struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev); - -	wm8776_unregister(wm8776); - +	snd_soc_unregister_codec(&spi->dev); +	kfree(spi_get_drvdata(spi));  	return 0;  }  static struct spi_driver wm8776_spi_driver = {  	.driver = { -		.name	= "wm8776", +		.name	= "wm8776-codec",  		.bus	= &spi_bus_type,  		.owner	= THIS_MODULE,  	}, @@ -625,27 +503,26 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,  				      const struct i2c_device_id *id)  {  	struct wm8776_priv *wm8776; -	struct snd_soc_codec *codec; +	int ret;  	wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);  	if (wm8776 == NULL)  		return -ENOMEM; -	codec = &wm8776->codec; -	codec->hw_write = (hw_write_t)i2c_master_send; -  	i2c_set_clientdata(i2c, wm8776); -	codec->control_data = i2c; - -	codec->dev = &i2c->dev; +	wm8776->control_type = SND_SOC_I2C; -	return wm8776_register(wm8776, SND_SOC_I2C); +	ret =  snd_soc_register_codec(&i2c->dev, +			&soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai)); +	if (ret < 0) +		kfree(wm8776); +	return ret;  }  static __devexit int wm8776_i2c_remove(struct i2c_client *client)  { -	struct wm8776_priv *wm8776 = i2c_get_clientdata(client); -	wm8776_unregister(wm8776); +	snd_soc_unregister_codec(&client->dev); +	kfree(i2c_get_clientdata(client));  	return 0;  } @@ -657,7 +534,7 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);  static struct i2c_driver wm8776_i2c_driver = {  	.driver = { -		.name = "wm8776", +		.name = "wm8776-codec",  		.owner = THIS_MODULE,  	},  	.probe =    wm8776_i2c_probe, @@ -668,22 +545,22 @@ static struct i2c_driver wm8776_i2c_driver = {  static int __init wm8776_modinit(void)  { -	int ret; +	int ret = 0;  #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  	ret = i2c_add_driver(&wm8776_i2c_driver);  	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n", +		printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",  		       ret);  	}  #endif  #if defined(CONFIG_SPI_MASTER)  	ret = spi_register_driver(&wm8776_spi_driver);  	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n", +		printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",  		       ret);  	}  #endif -	return 0; +	return ret;  }  module_init(wm8776_modinit);  |