diff options
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
| -rw-r--r-- | sound/soc/codecs/cs4270.c | 614 |
1 files changed, 249 insertions, 365 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ffe122d1cd7..9947a958367 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -22,14 +22,15 @@ */ #include <linux/module.h> -#include <linux/platform_device.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/soc.h> #include <sound/initval.h> #include <linux/i2c.h> #include <linux/delay.h> - -#include "cs4270.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,14 +107,52 @@ #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 { - struct snd_soc_codec codec; - 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; unsigned int manual_mute; + + /* power domain regulators */ + 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" }, }; /** @@ -171,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 @@ -192,43 +245,19 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { * This function must be called by the machine driver's 'startup' function, * otherwise the list of supported sample rates will not be available in * time for ALSA. + * + * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause + * theoretically possible sample rates to be enabled. Call it again with a + * proper value set one the external clock is set (most probably you would do + * that from a machine's driver 'hw_param' hook. */ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - struct cs4270_private *cs4270 = codec->private_data; - unsigned int rates = 0; - unsigned int rate_min = -1; - unsigned int rate_max = 0; - unsigned int i; + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); cs4270->mclk = freq; - - for (i = 0; i < NUM_MCLK_RATIOS; i++) { - unsigned int rate = freq / cs4270_mode_ratios[i].ratio; - rates |= snd_pcm_rate_to_rate_bit(rate); - if (rate < rate_min) - rate_min = rate; - if (rate > rate_max) - rate_max = rate; - } - /* FIXME: soc should support a rate list */ - rates &= ~SNDRV_PCM_RATE_KNOT; - - if (!rates) { - dev_err(codec->dev, "could not find a valid sample rate\n"); - return -EINVAL; - } - - codec_dai->playback.rates = rates; - codec_dai->playback.rate_min = rate_min; - codec_dai->playback.rate_max = rate_max; - - codec_dai->capture.rates = rates; - codec_dai->capture.rate_min = rate_min; - codec_dai->capture.rate_max = rate_max; - return 0; } @@ -249,8 +278,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int format) { struct snd_soc_codec *codec = codec_dai->codec; - struct cs4270_private *cs4270 = codec->private_data; - int ret = 0; + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); /* set DAI format */ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -260,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 */ @@ -273,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; @@ -388,10 +326,8 @@ 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_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - struct cs4270_private *cs4270 = codec->private_data; + struct snd_soc_codec *codec = dai->codec; + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); int ret; unsigned int i; unsigned int rate; @@ -470,7 +406,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - struct cs4270_private *cs4270 = codec->private_data; + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); int reg6; reg6 = snd_soc_read(codec, CS4270_MUTE); @@ -502,8 +438,8 @@ 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 cs4270_private *cs4270 = codec->private_data; + 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]; @@ -528,45 +464,35 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { snd_soc_get_volsw, cs4270_soc_put_mute), }; -/* - * cs4270_codec - global variable to store codec for the ASoC probe function - * - * If struct i2c_driver had a private_data field, we wouldn't need to use - * cs4270_codec. This is the only way to pass the codec structure from - * cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good - * way to synchronize these two functions. cs4270_i2c_probe() can be called - * multiple times before cs4270_probe() is called even once. So for now, we - * also only allow cs4270_i2c_probe() to be run once. That means that we do - * not support more than one cs4270 device in the system, at least for now. - */ -static struct snd_soc_codec *cs4270_codec; - -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, .digital_mute = cs4270_dai_mute, }; -struct snd_soc_dai cs4270_dai = { - .name = "cs4270", +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 = 0, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 4000, + .rate_max = 216000, .formats = CS4270_FORMATS, }, .capture = { .stream_name = "Capture", - .channels_min = 1, + .channels_min = 2, .channels_max = 2, - .rates = 0, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 4000, + .rate_max = 216000, .formats = CS4270_FORMATS, }, .ops = &cs4270_dai_ops, }; -EXPORT_SYMBOL_GPL(cs4270_dai); /** * cs4270_probe - ASoC probe function @@ -575,34 +501,36 @@ EXPORT_SYMBOL_GPL(cs4270_dai); * This function is called when ASoC has all the pieces it needs to * instantiate a sound driver. */ -static int cs4270_probe(struct platform_device *pdev) +static int cs4270_probe(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = cs4270_codec; + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); int ret; - /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ - socdev->card->codec = codec; - - /* Register PCMs */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + /* 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. + */ + ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0); if (ret < 0) { - dev_err(codec->dev, "failed to create pcms\n"); + 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)); + /* Disable automatic volume control. The hardware enables, and it + * causes volume change commands to be delayed, sometimes until after + * playback has started. An application (e.g. alsactl) can + * re-enabled it by using the controls. + */ + ret = snd_soc_update_bits(codec, CS4270_TRANS, + CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0); if (ret < 0) { - dev_err(codec->dev, "failed to add controls\n"); - goto error_free_pcms; + dev_err(codec->dev, "i2c write failed\n"); + return ret; } - return 0; - -error_free_pcms: - snd_soc_free_pcms(socdev); + ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); return ret; } @@ -613,15 +541,111 @@ error_free_pcms: * * This function is the counterpart to cs4270_probe(). */ -static int cs4270_remove(struct platform_device *pdev) +static int cs4270_remove(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); - snd_soc_free_pcms(socdev); + regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); return 0; }; +#ifdef CONFIG_PM + +/* This suspend/resume implementation can handle both - a simple standby + * where the codec remains powered, and a full suspend, where the voltage + * domain the codec is connected to is teared down and/or any other hardware + * reset condition is asserted. + * + * The codec's own power saving features are enabled in the suspend callback, + * and all registers are written back to the hardware when resuming. + */ + +static int cs4270_soc_suspend(struct snd_soc_codec *codec) +{ + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); + int reg, ret; + + reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; + if (reg < 0) + return reg; + + ret = snd_soc_write(codec, CS4270_PWRCTL, reg); + if (ret < 0) + return ret; + + regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); + + return 0; +} + +static int cs4270_soc_resume(struct snd_soc_codec *codec) +{ + struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); + int reg, ret; + + 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 ... */ + regcache_sync(cs4270->regmap); + + /* ... then disable the power-down bits */ + reg = snd_soc_read(codec, CS4270_PWRCTL); + reg &= ~CS4270_PWRCTL_PDN_ALL; + + return snd_soc_write(codec, CS4270_PWRCTL, reg); +} +#else +#define cs4270_soc_suspend NULL +#define cs4270_soc_resume NULL +#endif /* CONFIG_PM */ + +/* + * ASoC codec driver structure + */ +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, +}; + /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object @@ -633,32 +657,56 @@ static int cs4270_remove(struct platform_device *pdev) static int cs4270_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { - struct snd_soc_codec *codec; + struct device_node *np = i2c_client->dev.of_node; struct cs4270_private *cs4270; - unsigned int reg; - int ret; + unsigned int val; + int ret, i; - /* For now, we only support one cs4270 device in the system. See the - * comment for cs4270_codec. - */ - if (cs4270_codec) { - dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n", - i2c_client->addr); - dev_err(&i2c_client->dev, "only one per board allowed\n"); - /* Should we return something other than ENODEV here? */ - return -ENODEV; + 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; } - /* Verify that we have a CS4270 */ + /* 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; + + /* 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; + } + } - ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); + 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; @@ -666,96 +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); - - /* Allocate enough space for the snd_soc_codec structure - and our private data together. */ - cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL); - if (!cs4270) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); - return -ENOMEM; - } - codec = &cs4270->codec; - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->dev = &i2c_client->dev; - codec->name = "CS4270"; - codec->owner = THIS_MODULE; - codec->dai = &cs4270_dai; - codec->num_dai = 1; - codec->private_data = cs4270; - codec->control_data = i2c_client; - codec->read = cs4270_read_reg_cache; - codec->write = cs4270_i2c_write; - codec->reg_cache = cs4270->reg_cache; - codec->reg_cache_size = CS4270_NUMREGS; - - /* The I2C interface is set up, so pre-fill our register cache */ - - ret = cs4270_fill_cache(codec); - if (ret < 0) { - dev_err(&i2c_client->dev, "failed to fill register cache\n"); - goto error_free_codec; - } - - /* 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); - if (ret < 0) { - dev_err(&i2c_client->dev, "i2c write failed\n"); - return ret; - } - - /* Disable automatic volume control. The hardware enables, and it - * causes volume change commands to be delayed, sometimes until after - * 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); - if (ret < 0) { - dev_err(&i2c_client->dev, "i2c write failed\n"); - return ret; - } - - /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI - * structure for each CS4270 device, but the machine driver needs to - * have a pointer to the DAI structure, so for now it must be a global - * variable. - */ - cs4270_dai.dev = &i2c_client->dev; - - /* Register the DAI. If all the other ASoC driver have already - * registered, then this will call our probe function, so - * cs4270_codec needs to be ready. - */ - cs4270_codec = codec; - ret = snd_soc_register_dai(&cs4270_dai); - if (ret < 0) { - dev_err(&i2c_client->dev, "failed to register DAIe\n"); - goto error_free_codec; - } + dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF); i2c_set_clientdata(i2c_client, cs4270); - return 0; - -error_free_codec: - kfree(cs4270); - cs4270_codec = NULL; - cs4270_dai.dev = NULL; - + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_device_cs4270, &cs4270_dai, 1); return ret; } @@ -767,74 +731,19 @@ error_free_codec: */ static int cs4270_i2c_remove(struct i2c_client *i2c_client) { - struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client); - - kfree(cs4270); - cs4270_codec = NULL; - cs4270_dai.dev = NULL; - + snd_soc_unregister_codec(&i2c_client->dev); 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}, {} }; MODULE_DEVICE_TABLE(i2c, cs4270_id); -#ifdef CONFIG_PM - -/* This suspend/resume implementation can handle both - a simple standby - * where the codec remains powered, and a full suspend, where the voltage - * domain the codec is connected to is teared down and/or any other hardware - * reset condition is asserted. - * - * The codec's own power saving features are enabled in the suspend callback, - * and all registers are written back to the hardware when resuming. - */ - -static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - struct snd_soc_codec *codec = cs4270_codec; - int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; - - return snd_soc_write(codec, CS4270_PWRCTL, reg); -} - -static int cs4270_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_codec *codec = cs4270_codec; - struct i2c_client *i2c_client = codec->control_data; - int reg; - - /* 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; - } - } - - /* ... then disable the power-down bits */ - reg = snd_soc_read(codec, CS4270_PWRCTL); - reg &= ~CS4270_PWRCTL_PDN_ALL; - - return snd_soc_write(codec, CS4270_PWRCTL, reg); -} -#else -#define cs4270_soc_suspend NULL -#define cs4270_soc_resume NULL -#endif /* CONFIG_PM */ - /* * cs4270_i2c_driver - I2C device identification * @@ -845,39 +754,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, }; -/* - * ASoC codec device structure - * - * Assign this variable to the codec_dev field of the machine driver's - * snd_soc_device structure. - */ -struct snd_soc_codec_device soc_codec_device_cs4270 = { - .probe = cs4270_probe, - .remove = cs4270_remove, - .suspend = cs4270_soc_suspend, - .resume = cs4270_soc_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); - -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"); |
