diff options
Diffstat (limited to 'sound/soc/codecs/ssm2602.c')
| -rw-r--r-- | sound/soc/codecs/ssm2602.c | 138 | 
1 files changed, 94 insertions, 44 deletions
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index de2b20544ce..079066fef42 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -33,6 +33,7 @@  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/spi/spi.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -43,8 +44,6 @@  #include "ssm2602.h" -#define SSM2602_VERSION "0.1" -  enum ssm2602_type {  	SSM2602,  	SSM2604, @@ -53,10 +52,12 @@ enum ssm2602_type {  /* codec private data */  struct ssm2602_priv {  	unsigned int sysclk; -	enum snd_soc_control_type control_type; +	struct snd_pcm_hw_constraint_list *sysclk_constraints;  	struct snd_pcm_substream *master_substream;  	struct snd_pcm_substream *slave_substream; +	struct regmap *regmap; +  	enum ssm2602_type type;  	unsigned int clk_out_pwr;  }; @@ -73,7 +74,6 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {  	0x0000, 0x0000  }; -#define ssm2602_reset(c)	snd_soc_write(c, SSM2602_RESET, 0)  /*Appending several "None"s just for OSS mixer use*/  static const char *ssm2602_input_select[] = { @@ -195,6 +195,24 @@ static const struct snd_soc_dapm_route ssm2604_routes[] = {  	{"ADC", NULL, "Line Input"},  }; +static const unsigned int ssm2602_rates_12288000[] = { +	8000, 32000, 48000, 96000, +}; + +static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { +	.list = ssm2602_rates_12288000, +	.count = ARRAY_SIZE(ssm2602_rates_12288000), +}; + +static const unsigned int ssm2602_rates_11289600[] = { +	8000, 44100, 88200, +}; + +static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { +	.list = ssm2602_rates_11289600, +	.count = ARRAY_SIZE(ssm2602_rates_11289600), +}; +  struct ssm2602_coeff {  	u32 mclk;  	u32 rate; @@ -254,11 +272,10 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,  	struct snd_pcm_hw_params *params,  	struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); -	u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;  	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params)); +	unsigned int iface;  	if (substream == ssm2602->slave_substream) {  		dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n"); @@ -268,31 +285,34 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,  	if (srate < 0)  		return srate; -	snd_soc_write(codec, SSM2602_SRATE, srate); +	regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);  	/* bit size */  	switch (params_format(params)) {  	case SNDRV_PCM_FORMAT_S16_LE: +		iface = 0x0;  		break;  	case SNDRV_PCM_FORMAT_S20_3LE: -		iface |= 0x0004; +		iface = 0x4;  		break;  	case SNDRV_PCM_FORMAT_S24_LE: -		iface |= 0x0008; +		iface = 0x8;  		break;  	case SNDRV_PCM_FORMAT_S32_LE: -		iface |= 0x000c; +		iface = 0xc;  		break; +	default: +		return -EINVAL;  	} -	snd_soc_write(codec, SSM2602_IFACE, iface); +	regmap_update_bits(ssm2602->regmap, SSM2602_IFACE, +		IFACE_AUDIO_DATA_LEN, iface);  	return 0;  }  static int ssm2602_startup(struct snd_pcm_substream *substream,  			   struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);  	struct snd_pcm_runtime *master_runtime; @@ -322,14 +342,19 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,  	} else  		ssm2602->master_substream = substream; +	if (ssm2602->sysclk_constraints) { +		snd_pcm_hw_constraint_list(substream->runtime, 0, +				   SNDRV_PCM_HW_PARAM_RATE, +				   ssm2602->sysclk_constraints); +	} +  	return 0;  }  static void ssm2602_shutdown(struct snd_pcm_substream *substream,  			     struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);  	if (ssm2602->master_substream == substream) @@ -341,14 +366,14 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,  static int ssm2602_mute(struct snd_soc_dai *dai, int mute)  { -	struct snd_soc_codec *codec = dai->codec; +	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);  	if (mute) -		snd_soc_update_bits(codec, SSM2602_APDIGI, +		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,  				    APDIGI_ENABLE_DAC_MUTE,  				    APDIGI_ENABLE_DAC_MUTE);  	else -		snd_soc_update_bits(codec, SSM2602_APDIGI, +		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,  				    APDIGI_ENABLE_DAC_MUTE, 0);  	return 0;  } @@ -364,16 +389,21 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,  			return -EINVAL;  		switch (freq) { -		case 11289600: -		case 12000000:  		case 12288000: -		case 16934400:  		case 18432000: -			ssm2602->sysclk = freq; +			ssm2602->sysclk_constraints = &ssm2602_constraints_12288000; +			break; +		case 11289600: +		case 16934400: +			ssm2602->sysclk_constraints = &ssm2602_constraints_11289600; +			break; +		case 12000000: +			ssm2602->sysclk_constraints = NULL;  			break;  		default:  			return -EINVAL;  		} +		ssm2602->sysclk = freq;  	} else {  		unsigned int mask; @@ -393,7 +423,7 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,  		else  			ssm2602->clk_out_pwr &= ~mask; -		snd_soc_update_bits(codec, SSM2602_PWR, +		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,  			PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);  	} @@ -403,8 +433,8 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,  static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,  		unsigned int fmt)  { -	struct snd_soc_codec *codec = codec_dai->codec; -	u16 iface = 0; +	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec_dai->codec); +	unsigned int iface = 0;  	/* set master/slave audio interface */  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -455,7 +485,7 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,  	}  	/* set iface */ -	snd_soc_write(codec, SSM2602_IFACE, iface); +	regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);  	return 0;  } @@ -467,7 +497,7 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,  	switch (level) {  	case SND_SOC_BIAS_ON:  		/* vref/mid on, osc and clkout on if enabled */ -		snd_soc_update_bits(codec, SSM2602_PWR, +		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,  			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,  			ssm2602->clk_out_pwr);  		break; @@ -475,13 +505,13 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_STANDBY:  		/* everything off except vref/vmid, */ -		snd_soc_update_bits(codec, SSM2602_PWR, +		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,  			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,  			PWR_CLK_OUT_PDN | PWR_OSC_PDN);  		break;  	case SND_SOC_BIAS_OFF:  		/* everything off */ -		snd_soc_update_bits(codec, SSM2602_PWR, +		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,  			PWR_POWER_OFF, PWR_POWER_OFF);  		break; @@ -540,12 +570,13 @@ static int ssm2602_resume(struct snd_soc_codec *codec)  static int ssm2602_probe(struct snd_soc_codec *codec)  { +	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = &codec->dapm;  	int ret; -	snd_soc_update_bits(codec, SSM2602_LOUT1V, +	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,  			    LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH); -	snd_soc_update_bits(codec, SSM2602_ROUT1V, +	regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,  			    ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);  	ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls, @@ -581,27 +612,26 @@ static int ssm260x_probe(struct snd_soc_codec *codec)  	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);  	int ret; -	pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); - -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type); +	codec->control_data = ssm2602->regmap; +	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret;  	} -	ret = ssm2602_reset(codec); +	ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);  		return ret;  	}  	/* set the update bits */ -	snd_soc_update_bits(codec, SSM2602_LINVOL, +	regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,  			    LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH); -	snd_soc_update_bits(codec, SSM2602_RINVOL, +	regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,  			    RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);  	/*select Line in as default input*/ -	snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | +	regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |  			APANA_ENABLE_MIC_BOOST);  	switch (ssm2602->type) { @@ -634,9 +664,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {  	.suspend =	ssm2602_suspend,  	.resume =	ssm2602_resume,  	.set_bias_level = ssm2602_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(ssm2602_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = ssm2602_reg,  	.controls = ssm260x_snd_controls,  	.num_controls = ARRAY_SIZE(ssm260x_snd_controls), @@ -646,6 +673,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {  	.num_dapm_routes = ARRAY_SIZE(ssm260x_routes),  }; +static bool ssm2602_register_volatile(struct device *dev, unsigned int reg) +{ +	return reg == SSM2602_RESET; +} + +static const struct regmap_config ssm2602_regmap_config = { +	.val_bits = 9, +	.reg_bits = 7, + +	.max_register = SSM2602_RESET, +	.volatile_reg = ssm2602_register_volatile, + +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults_raw = ssm2602_reg, +	.num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg), +}; +  #if defined(CONFIG_SPI_MASTER)  static int __devinit ssm2602_spi_probe(struct spi_device *spi)  { @@ -658,9 +702,12 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi)  		return -ENOMEM;  	spi_set_drvdata(spi, ssm2602); -	ssm2602->control_type = SND_SOC_SPI;  	ssm2602->type = SSM2602; +	ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config); +	if (IS_ERR(ssm2602->regmap)) +		return PTR_ERR(ssm2602->regmap); +  	ret = snd_soc_register_codec(&spi->dev,  			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);  	return ret; @@ -701,9 +748,12 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,  		return -ENOMEM;  	i2c_set_clientdata(i2c, ssm2602); -	ssm2602->control_type = SND_SOC_I2C;  	ssm2602->type = id->driver_data; +	ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config); +	if (IS_ERR(ssm2602->regmap)) +		return PTR_ERR(ssm2602->regmap); +  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);  	return ret;  |