diff options
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
| -rw-r--r-- | sound/soc/codecs/cs4270.c | 354 | 
1 files changed, 148 insertions, 206 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 6d4bdc609ac..9947a958367 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -22,7 +22,6 @@   */  #include <linux/module.h> -#include <linux/platform_device.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/soc.h> @@ -30,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 @@ -106,15 +107,29 @@  #define CS4270_MUTE_DAC_A	0x01  #define CS4270_MUTE_DAC_B	0x02 +/* Power-on default values for the registers + * + * This array contains the power-on default values of the registers, with the + * exception of the "CHIPID" register (01h).  The lower four bits of that + * register contain the hardware revision, so it is treated as volatile. + */ +static const struct reg_default cs4270_reg_defaults[] = { +	{ 2, 0x00 }, +	{ 3, 0x30 }, +	{ 4, 0x00 }, +	{ 5, 0x60 }, +	{ 6, 0x20 }, +	{ 7, 0x00 }, +	{ 8, 0x00 }, +}; +  static const char *supply_names[] = {  	"va", "vd", "vlc"  };  /* Private data for the CS4270 */  struct cs4270_private { -	enum snd_soc_control_type control_type; -	void *control_data; -	u8 reg_cache[CS4270_NUMREGS]; +	struct regmap *regmap;  	unsigned int mclk; /* Input frequency of the MCLK pin */  	unsigned int mode; /* The mode (I2S or left-justified) */  	unsigned int slave_mode; @@ -124,6 +139,22 @@ struct cs4270_private {  	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];  }; +static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("AINL"), +SND_SOC_DAPM_INPUT("AINR"), + +SND_SOC_DAPM_OUTPUT("AOUTL"), +SND_SOC_DAPM_OUTPUT("AOUTR"), +}; + +static const struct snd_soc_dapm_route cs4270_dapm_routes[] = { +	{ "Capture", NULL, "AINA" }, +	{ "Capture", NULL, "AINB" }, + +	{ "AOUTA", NULL, "Playback" }, +	{ "AOUTB", NULL, "Playback" }, +}; +  /**   * struct cs4270_mode_ratios - clock ratio tables   * @ratio: the ratio of MCLK to the sample rate @@ -179,6 +210,20 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {  /* The number of MCLK/LRCK ratios supported by the CS4270 */  #define NUM_MCLK_RATIOS		ARRAY_SIZE(cs4270_mode_ratios) +static bool cs4270_reg_is_readable(struct device *dev, unsigned int reg) +{ +	return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG); +} + +static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg) +{ +	/* Unreadable registers are considered volatile */ +	if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) +		return 1; + +	return reg == CS4270_CHIPID; +} +  /**   * cs4270_set_dai_sysclk - determine the CS4270 samples rates.   * @codec_dai: the codec DAI @@ -234,7 +279,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,  {  	struct snd_soc_codec *codec = codec_dai->codec;  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); -	int ret = 0;  	/* set DAI format */  	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -244,7 +288,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,  		break;  	default:  		dev_err(codec->dev, "invalid dai format\n"); -		ret = -EINVAL; +		return -EINVAL;  	}  	/* set master/slave audio interface */ @@ -257,98 +301,8 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,  		break;  	default:  		/* all other modes are unsupported by the hardware */ -		ret = -EINVAL; -	} - -	return ret; -} - -/** - * cs4270_fill_cache - pre-fill the CS4270 register cache. - * @codec: the codec for this CS4270 - * - * This function fills in the CS4270 register cache by reading the register - * values from the hardware. - * - * This CS4270 registers are cached to avoid excessive I2C I/O operations. - * After the initial read to pre-fill the cache, the CS4270 never updates - * the register values, so we won't have a cache coherency problem. - * - * We use the auto-increment feature of the CS4270 to read all registers in - * one shot. - */ -static int cs4270_fill_cache(struct snd_soc_codec *codec) -{ -	u8 *cache = codec->reg_cache; -	struct i2c_client *i2c_client = codec->control_data; -	s32 length; - -	length = i2c_smbus_read_i2c_block_data(i2c_client, -		CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache); - -	if (length != CS4270_NUMREGS) { -		dev_err(codec->dev, "i2c read failure, addr=0x%x\n", -		       i2c_client->addr); -		return -EIO; -	} - -	return 0; -} - -/** - * cs4270_read_reg_cache - read from the CS4270 register cache. - * @codec: the codec for this CS4270 - * @reg: the register to read - * - * This function returns the value for a given register.  It reads only from - * the register cache, not the hardware itself. - * - * This CS4270 registers are cached to avoid excessive I2C I/O operations. - * After the initial read to pre-fill the cache, the CS4270 never updates - * the register values, so we won't have a cache coherency problem. - */ -static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, -	unsigned int reg) -{ -	u8 *cache = codec->reg_cache; - -	if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) -		return -EIO; - -	return cache[reg - CS4270_FIRSTREG]; -} - -/** - * cs4270_i2c_write - write to a CS4270 register via the I2C bus. - * @codec: the codec for this CS4270 - * @reg: the register to write - * @value: the value to write to the register - * - * This function writes the given value to the given CS4270 register, and - * also updates the register cache. - * - * Note that we don't use the hw_write function pointer of snd_soc_codec. - * That's because it's too clunky: the hw_write_t prototype does not match - * i2c_smbus_write_byte_data(), and it's just another layer of overhead. - */ -static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, -			    unsigned int value) -{ -	u8 *cache = codec->reg_cache; - -	if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) -		return -EIO; - -	/* Only perform an I2C operation if the new value is different */ -	if (cache[reg - CS4270_FIRSTREG] != value) { -		struct i2c_client *client = codec->control_data; -		if (i2c_smbus_write_byte_data(client, reg, value)) { -			dev_err(codec->dev, "i2c write failed\n"); -			return -EIO; -		} - -		/* We've written to the hardware, so update the cache */ -		cache[reg - CS4270_FIRSTREG] = value; +		dev_err(codec->dev, "Unknown master/slave configuration\n"); +		return -EINVAL;  	}  	return 0; @@ -372,8 +326,7 @@ static int cs4270_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 cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	int ret;  	unsigned int i; @@ -485,7 +438,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)  static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol)  { -	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	int left = !ucontrol->value.integer.value[0];  	int right = !ucontrol->value.integer.value[1]; @@ -511,7 +464,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {  		snd_soc_get_volsw, cs4270_soc_put_mute),  }; -static struct snd_soc_dai_ops cs4270_dai_ops = { +static const struct snd_soc_dai_ops cs4270_dai_ops = {  	.hw_params	= cs4270_hw_params,  	.set_sysclk	= cs4270_set_dai_sysclk,  	.set_fmt	= cs4270_set_dai_fmt, @@ -522,7 +475,7 @@ static struct snd_soc_dai_driver cs4270_dai = {  	.name = "cs4270-hifi",  	.playback = {  		.stream_name = "Playback", -		.channels_min = 1, +		.channels_min = 2,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_CONTINUOUS,  		.rate_min = 4000, @@ -531,7 +484,7 @@ static struct snd_soc_dai_driver cs4270_dai = {  	},  	.capture = {  		.stream_name = "Capture", -		.channels_min = 1, +		.channels_min = 2,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_CONTINUOUS,  		.rate_min = 4000, @@ -551,27 +504,14 @@ static struct snd_soc_dai_driver cs4270_dai = {  static int cs4270_probe(struct snd_soc_codec *codec)  {  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); -	int i, ret, reg; - -	codec->control_data = cs4270->control_data; - -	/* The I2C interface is set up, so pre-fill our register cache */ - -	ret = cs4270_fill_cache(codec); -	if (ret < 0) { -		dev_err(codec->dev, "failed to fill register cache\n"); -		return ret; -	} +	int ret;  	/* Disable auto-mute.  This feature appears to be buggy.  In some  	 * situations, auto-mute will not deactivate when it should, so we want  	 * this feature disabled by default.  An application (e.g. alsactl) can  	 * re-enabled it by using the controls.  	 */ - -	reg = cs4270_read_reg_cache(codec, CS4270_MUTE); -	reg &= ~CS4270_MUTE_AUTO; -	ret = cs4270_i2c_write(codec, CS4270_MUTE, reg); +	ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0);  	if (ret < 0) {  		dev_err(codec->dev, "i2c write failed\n");  		return ret; @@ -582,42 +522,15 @@ static int cs4270_probe(struct snd_soc_codec *codec)  	 * playback has started.  An application (e.g. alsactl) can  	 * re-enabled it by using the controls.  	 */ - -	reg = cs4270_read_reg_cache(codec, CS4270_TRANS); -	reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); -	ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); +	ret = snd_soc_update_bits(codec, CS4270_TRANS, +		CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);  	if (ret < 0) {  		dev_err(codec->dev, "i2c write failed\n");  		return ret;  	} -	/* Add the non-DAPM controls */ -	ret = snd_soc_add_controls(codec, cs4270_snd_controls, -				ARRAY_SIZE(cs4270_snd_controls)); -	if (ret < 0) { -		dev_err(codec->dev, "failed to add controls\n"); -		return ret; -	} - -	/* get the power supply regulators */ -	for (i = 0; i < ARRAY_SIZE(supply_names); i++) -		cs4270->supplies[i].supply = supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), -				 cs4270->supplies); -	if (ret < 0) -		return ret; -  	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),  				    cs4270->supplies); -	if (ret < 0) -		goto error_free_regulators; - -	return 0; - -error_free_regulators: -	regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), -			    cs4270->supplies);  	return ret;  } @@ -633,7 +546,6 @@ static int cs4270_remove(struct snd_soc_codec *codec)  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); -	regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);  	return 0;  }; @@ -649,7 +561,7 @@ static int cs4270_remove(struct snd_soc_codec *codec)   * and all registers are written back to the hardware when resuming.   */ -static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg) +static int cs4270_soc_suspend(struct snd_soc_codec *codec)  {  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	int reg, ret; @@ -671,25 +583,19 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)  static int cs4270_soc_resume(struct snd_soc_codec *codec)  {  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); -	struct i2c_client *i2c_client = codec->control_data; -	int reg; +	int reg, ret; -	regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), -			      cs4270->supplies); +	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), +				    cs4270->supplies); +	if (ret != 0) +		return ret;  	/* In case the device was put to hard reset during sleep, we need to  	 * wait 500ns here before any I2C communication. */  	ndelay(500);  	/* first restore the entire register cache ... */ -	for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) { -		u8 val = snd_soc_read(codec, reg); - -		if (i2c_smbus_write_byte_data(i2c_client, reg, val)) { -			dev_err(codec->dev, "i2c write failed\n"); -			return -EIO; -		} -	} +	regcache_sync(cs4270->regmap);  	/* ... then disable the power-down bits */  	reg = snd_soc_read(codec, CS4270_PWRCTL); @@ -703,20 +609,41 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)  #endif /* CONFIG_PM */  /* - * ASoC codec device structure - * - * Assign this variable to the codec_dev field of the machine driver's - * snd_soc_device structure. + * ASoC codec driver structure   */ -static struct snd_soc_codec_driver soc_codec_device_cs4270 = { -	.probe =	cs4270_probe, -	.remove =	cs4270_remove, -	.suspend =	cs4270_soc_suspend, -	.resume =	cs4270_soc_resume, -	.read = cs4270_read_reg_cache, -	.write = cs4270_i2c_write, -	.reg_cache_size = CS4270_NUMREGS, -	.reg_word_size = sizeof(u8), +static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { +	.probe =		cs4270_probe, +	.remove =		cs4270_remove, +	.suspend =		cs4270_soc_suspend, +	.resume =		cs4270_soc_resume, + +	.controls =		cs4270_snd_controls, +	.num_controls =		ARRAY_SIZE(cs4270_snd_controls), +	.dapm_widgets =		cs4270_dapm_widgets, +	.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets), +	.dapm_routes =		cs4270_dapm_routes, +	.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes), +}; + +/* + * 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); + +static const struct regmap_config cs4270_regmap = { +	.reg_bits =		8, +	.val_bits =		8, +	.max_register =		CS4270_LASTREG, +	.reg_defaults =		cs4270_reg_defaults, +	.num_reg_defaults =	ARRAY_SIZE(cs4270_reg_defaults), +	.cache_type =		REGCACHE_RBTREE, + +	.readable_reg =		cs4270_reg_is_readable, +	.volatile_reg =		cs4270_reg_is_volatile,  };  /** @@ -730,19 +657,56 @@ static 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; +	unsigned int val; +	int ret, i; -	/* Verify that we have a CS4270 */ +	cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private), +			      GFP_KERNEL); +	if (!cs4270) { +		dev_err(&i2c_client->dev, "could not allocate codec\n"); +		return -ENOMEM; +	} + +	/* get the power supply regulators */ +	for (i = 0; i < ARRAY_SIZE(supply_names); i++) +		cs4270->supplies[i].supply = supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c_client->dev, +				      ARRAY_SIZE(cs4270->supplies), +				      cs4270->supplies); +	if (ret < 0) +		return ret; -	ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); +	/* 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; +		} +	} + +	cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap); +	if (IS_ERR(cs4270->regmap)) +		return PTR_ERR(cs4270->regmap); + +	/* Verify that we have a CS4270 */ +	ret = regmap_read(cs4270->regmap, CS4270_CHIPID, &val);  	if (ret < 0) {  		dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",  		       i2c_client->addr);  		return ret;  	}  	/* The top four bits of the chip ID should be 1100. */ -	if ((ret & 0xF0) != 0xC0) { +	if ((val & 0xF0) != 0xC0) {  		dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",  		       i2c_client->addr);  		return -ENODEV; @@ -750,22 +714,12 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,  	dev_info(&i2c_client->dev, "found device at i2c address %X\n",  		i2c_client->addr); -	dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF); - -	cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL); -	if (!cs4270) { -		dev_err(&i2c_client->dev, "could not allocate codec\n"); -		return -ENOMEM; -	} +	dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF);  	i2c_set_clientdata(i2c_client, cs4270); -	cs4270->control_data = i2c_client; -	cs4270->control_type = SND_SOC_I2C;  	ret = snd_soc_register_codec(&i2c_client->dev,  			&soc_codec_device_cs4270, &cs4270_dai, 1); -	if (ret < 0) -		kfree(cs4270);  	return ret;  } @@ -778,14 +732,13 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,  static int cs4270_i2c_remove(struct i2c_client *i2c_client)  {  	snd_soc_unregister_codec(&i2c_client->dev); -	kfree(i2c_get_clientdata(i2c_client));  	return 0;  }  /*   * cs4270_id - I2C device IDs supported by this driver   */ -static struct i2c_device_id cs4270_id[] = { +static const struct i2c_device_id cs4270_id[] = {  	{"cs4270", 0},  	{}  }; @@ -799,27 +752,16 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);   */  static struct i2c_driver cs4270_i2c_driver = {  	.driver = { -		.name = "cs4270-codec", +		.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) -{ -	pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n"); - -	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");  | 
