From fdf200290581150f7b69148abf6ca860684cbfbb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 1 Sep 2013 20:24:50 -0700 Subject: regmap: add regmap_field_update_bits() Current regmap_field is supporting read/write functions. This patch adds new update_bits function for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7d689a1..285afa7 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1369,6 +1369,26 @@ int regmap_field_write(struct regmap_field *field, unsigned int val) } EXPORT_SYMBOL_GPL(regmap_field_write); +/** + * regmap_field_update_bits(): Perform a read/modify/write cycle + * on the register field + * + * @field: Register field to write to + * @mask: Bitmask to change + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) +{ + mask = (mask << field->shift) & field->mask; + + return regmap_update_bits(field->regmap, field->reg, + mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_field_update_bits); + /* * regmap_bulk_write(): Write multiple registers to the device * diff --git a/include/linux/regmap.h b/include/linux/regmap.h index a10380b..4c8c20a 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -448,6 +448,8 @@ void devm_regmap_field_free(struct device *dev, struct regmap_field *field); int regmap_field_read(struct regmap_field *field, unsigned int *val); int regmap_field_write(struct regmap_field *field, unsigned int val); +int regmap_field_update_bits(struct regmap_field *field, + unsigned int mask, unsigned int val); /** * Description of an IRQ for the generic regmap irq_chip. -- cgit v0.10.2 From 175ee39e8f4053f95e1948afd75c74552b3a175c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 31 Aug 2013 20:31:11 +0200 Subject: ASoC: Remove support for reg_access_defaults No users of reg_access_defaults are left and new drivers are going to use regmap for this, so support for it can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index d22cb0a..447278a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -403,12 +403,6 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); int snd_soc_cache_read(struct snd_soc_codec *codec, unsigned int reg, unsigned int *value); -int snd_soc_default_volatile_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_default_readable_register(struct snd_soc_codec *codec, - unsigned int reg); -int snd_soc_default_writable_register(struct snd_soc_codec *codec, - unsigned int reg); int snd_soc_platform_read(struct snd_soc_platform *platform, unsigned int reg); int snd_soc_platform_write(struct snd_soc_platform *platform, @@ -542,22 +536,6 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); /** - * struct snd_soc_reg_access - Describes whether a given register is - * readable, writable or volatile. - * - * @reg: the register number - * @read: whether this register is readable - * @write: whether this register is writable - * @vol: whether this register is volatile - */ -struct snd_soc_reg_access { - u16 reg; - u16 read; - u16 write; - u16 vol; -}; - -/** * struct snd_soc_jack_pin - Describes a pin to update based on jack detection * * @pin: name of the pin to update @@ -760,8 +738,6 @@ struct snd_soc_codec_driver { short reg_cache_step; short reg_word_size; const void *reg_cache_default; - short reg_access_size; - const struct snd_soc_reg_access *reg_access_default; enum snd_soc_compress_type compress_type; /* codec bias level */ diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index e72f554..eaa898f 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -275,66 +275,3 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec) return ret; } EXPORT_SYMBOL_GPL(snd_soc_cache_sync); - -static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, - unsigned int reg) -{ - const struct snd_soc_codec_driver *codec_drv; - unsigned int min, max, index; - - codec_drv = codec->driver; - min = 0; - max = codec_drv->reg_access_size - 1; - do { - index = (min + max) / 2; - if (codec_drv->reg_access_default[index].reg == reg) - return index; - if (codec_drv->reg_access_default[index].reg < reg) - min = index + 1; - else - max = index; - } while (min <= max); - return -1; -} - -int snd_soc_default_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - int index; - - if (reg >= codec->driver->reg_cache_size) - return 1; - index = snd_soc_get_reg_access_index(codec, reg); - if (index < 0) - return 0; - return codec->driver->reg_access_default[index].vol; -} -EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); - -int snd_soc_default_readable_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - int index; - - if (reg >= codec->driver->reg_cache_size) - return 1; - index = snd_soc_get_reg_access_index(codec, reg); - if (index < 0) - return 0; - return codec->driver->reg_access_default[index].read; -} -EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); - -int snd_soc_default_writable_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - int index; - - if (reg >= codec->driver->reg_cache_size) - return 1; - index = snd_soc_get_reg_access_index(codec, reg); - if (index < 0) - return 0; - return codec->driver->reg_access_default[index].write; -} -EXPORT_SYMBOL_GPL(snd_soc_default_writable_register); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d05613..f5ec301 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4224,15 +4224,6 @@ int snd_soc_register_codec(struct device *dev, } } - if (codec_drv->reg_access_size && codec_drv->reg_access_default) { - if (!codec->volatile_register) - codec->volatile_register = snd_soc_default_volatile_register; - if (!codec->readable_register) - codec->readable_register = snd_soc_default_readable_register; - if (!codec->writable_register) - codec->writable_register = snd_soc_default_writable_register; - } - for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); fixup_codec_formats(&dai_drv[i].capture); -- cgit v0.10.2 From 2a1212a8342c469cee240cf69fe3001b898cda8e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 31 Aug 2013 20:31:12 +0200 Subject: ASoC: Remove snd_soc_bulk_write_raw() No users of snd_soc_bulk_write_raw() are left and new drivers are going to use regmap directly for this, so the function can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 447278a..3f7de6f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -686,7 +686,6 @@ struct snd_soc_codec { unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); - int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t); void *reg_cache; const void *reg_def_copy; const struct snd_soc_cache_ops *cache_ops; @@ -1097,8 +1096,6 @@ struct soc_enum { unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); unsigned int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val); -unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, - unsigned int reg, const void *data, size_t len); /* device driver data */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f5ec301..4ce02e6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2298,13 +2298,6 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_write); -unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, - unsigned int reg, const void *data, size_t len) -{ - return codec->bulk_write_raw(codec, reg, data, len); -} -EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw); - /** * snd_soc_update_bits - update codec register bits * @codec: audio codec diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 122c0c1..4f11d23 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -65,31 +65,6 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) return val; } -/* Primitive bulk write support for soc-cache. The data pointed to by - * `data' needs to already be in the form the hardware expects. Any - * data written through this function will not go through the cache as - * it only handles writing to volatile or out of bounds registers. - * - * This is currently only supported for devices using the regmap API - * wrappers. - */ -static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, - unsigned int reg, - const void *data, size_t len) -{ - /* To ensure that we don't get out of sync with the cache, check - * whether the base register is volatile or if we've directly asked - * to bypass the cache. Out of bounds registers are considered - * volatile. - */ - if (!codec->cache_bypass - && !snd_soc_codec_volatile_register(codec, reg) - && reg < codec->driver->reg_cache_size) - return -EINVAL; - - return regmap_raw_write(codec->control_data, reg, data, len); -} - /** * snd_soc_codec_set_cache_io: Set up standard I/O functions. * @@ -119,7 +94,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, memset(&config, 0, sizeof(config)); codec->write = hw_write; codec->read = hw_read; - codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; config.reg_bits = addr_bits; config.val_bits = data_bits; -- cgit v0.10.2 From b012aa619e50d22df0835b64a5dcebc221fb8053 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 31 Aug 2013 20:31:13 +0200 Subject: ASoC: Remove reg_def_copy reg_def_copy was introduced in commit 3335ddca ("ASoC: soc-cache: Use reg_def_copy instead of reg_cache_default") to keep a copy of the register defaults around in case the register defaults where placed in the __devinitdata section. With the __devinitdata section gone we effectivly keep the same data around twice. This patch removes reg_def_copy and uses reg_cache_default directly instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 3f7de6f..62f320f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -687,7 +687,6 @@ struct snd_soc_codec { unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); void *reg_cache; - const void *reg_def_copy; const struct snd_soc_cache_ops *cache_ops; struct mutex cache_rw_mutex; int val_bytes; diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index eaa898f..a7f83c0 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -78,8 +78,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) ret = snd_soc_cache_read(codec, i, &val); if (ret) return ret; - if (codec->reg_def_copy) - if (snd_soc_get_cache_val(codec->reg_def_copy, + if (codec_drv->reg_cache_default) + if (snd_soc_get_cache_val(codec_drv->reg_cache_default, i, codec_drv->reg_word_size) == val) continue; @@ -121,8 +121,10 @@ static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) { - if (codec->reg_def_copy) - codec->reg_cache = kmemdup(codec->reg_def_copy, + const struct snd_soc_codec_driver *codec_drv = codec->driver; + + if (codec_drv->reg_cache_default) + codec->reg_cache = kmemdup(codec_drv->reg_cache_default, codec->reg_size, GFP_KERNEL); else codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4ce02e6..bbe833a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4201,20 +4201,6 @@ int snd_soc_register_codec(struct device *dev, if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; codec->reg_size = reg_size; - /* it is necessary to make a copy of the default register cache - * because in the case of using a compression type that requires - * the default register cache to be marked as the - * kernel might have freed the array by the time we initialize - * the cache. - */ - if (codec_drv->reg_cache_default) { - codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, - reg_size, GFP_KERNEL); - if (!codec->reg_def_copy) { - ret = -ENOMEM; - goto fail_codec_name; - } - } } for (i = 0; i < num_dai; i++) { @@ -4273,7 +4259,6 @@ found: dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name); snd_soc_cache_exit(codec); - kfree(codec->reg_def_copy); kfree(codec->name); kfree(codec); } -- cgit v0.10.2 From a94ed23436fb28bdcdd66e7fcf68ca5f7967e456 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 31 Aug 2013 20:31:14 +0200 Subject: ASoC: Remove 'reg_size' field from snd_soc_codec struct The reg_size field is calculated in snd_soc_register_codec() and then used exactly once in snd_soc_flat_cache_init(). Since it is calculated based on other fields from the codec struct just move the calculation to snd_soc_flat_cache_init() and remove the 'reg_size' field from the codec struct. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 62f320f..5772126 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -662,7 +662,6 @@ struct snd_soc_codec { struct list_head card_list; int num_dai; enum snd_soc_compress_type compress_type; - size_t reg_size; /* reg_cache_size * reg_word_size */ int (*volatile_register)(struct snd_soc_codec *, unsigned int); int (*readable_register)(struct snd_soc_codec *, unsigned int); int (*writable_register)(struct snd_soc_codec *, unsigned int); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index a7f83c0..9542c83 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -122,12 +122,15 @@ static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) { const struct snd_soc_codec_driver *codec_drv = codec->driver; + size_t reg_size; + + reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; if (codec_drv->reg_cache_default) codec->reg_cache = kmemdup(codec_drv->reg_cache_default, - codec->reg_size, GFP_KERNEL); + reg_size, GFP_KERNEL); else - codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); + codec->reg_cache = kzalloc(reg_size, GFP_KERNEL); if (!codec->reg_cache) return -ENOMEM; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bbe833a..af96484 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4159,7 +4159,6 @@ int snd_soc_register_codec(struct device *dev, struct snd_soc_dai_driver *dai_drv, int num_dai) { - size_t reg_size; struct snd_soc_codec *codec; int ret, i; @@ -4197,12 +4196,6 @@ int snd_soc_register_codec(struct device *dev, codec->num_dai = num_dai; mutex_init(&codec->mutex); - /* allocate CODEC register cache */ - if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { - reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; - codec->reg_size = reg_size; - } - for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); fixup_codec_formats(&dai_drv[i].capture); -- cgit v0.10.2 From f90fb3f778042b0b9f9aa1fd48cb76047a25eac0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 31 Aug 2013 20:31:15 +0200 Subject: ASoC: Remove infrastructure for supporting multiple cache types The only cache type left is the flat cache and new other cache types won't be added since new drivers are supposed to use regmap directly for IO and caching. This patch removes the snd_soc_cache_ops indirection that was added to support multiple cache types and modifies the code to always use the flat cache directly. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 5772126..a72af63 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -330,7 +330,6 @@ struct soc_enum; struct snd_soc_jack; struct snd_soc_jack_zone; struct snd_soc_jack_pin; -struct snd_soc_cache_ops; #include #include @@ -348,10 +347,6 @@ enum snd_soc_control_type { SND_SOC_REGMAP, }; -enum snd_soc_compress_type { - SND_SOC_FLAT_COMPRESSION = 1, -}; - enum snd_soc_pcm_subclass { SND_SOC_PCM_CLASS_PCM = 0, SND_SOC_PCM_CLASS_BE = 1, @@ -635,19 +630,6 @@ struct snd_soc_compr_ops { int (*trigger)(struct snd_compr_stream *); }; -/* SoC cache ops */ -struct snd_soc_cache_ops { - const char *name; - enum snd_soc_compress_type id; - int (*init)(struct snd_soc_codec *codec); - int (*exit)(struct snd_soc_codec *codec); - int (*read)(struct snd_soc_codec *codec, unsigned int reg, - unsigned int *value); - int (*write)(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value); - int (*sync)(struct snd_soc_codec *codec); -}; - /* SoC Audio Codec device */ struct snd_soc_codec { const char *name; @@ -661,7 +643,6 @@ struct snd_soc_codec { struct list_head list; struct list_head card_list; int num_dai; - enum snd_soc_compress_type compress_type; int (*volatile_register)(struct snd_soc_codec *, unsigned int); int (*readable_register)(struct snd_soc_codec *, unsigned int); int (*writable_register)(struct snd_soc_codec *, unsigned int); @@ -686,7 +667,6 @@ struct snd_soc_codec { unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); void *reg_cache; - const struct snd_soc_cache_ops *cache_ops; struct mutex cache_rw_mutex; int val_bytes; @@ -735,7 +715,6 @@ struct snd_soc_codec_driver { short reg_cache_step; short reg_word_size; const void *reg_cache_default; - enum snd_soc_compress_type compress_type; /* codec bias level */ int (*set_bias_level)(struct snd_soc_codec *, @@ -917,12 +896,6 @@ struct snd_soc_codec_conf { * associated per device */ const char *name_prefix; - - /* - * set this to the desired compression type if you want to - * override the one supplied in codec->driver->compress_type - */ - enum snd_soc_compress_type compress_type; }; struct snd_soc_aux_dev { diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 9542c83..1b6663f 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -11,12 +11,9 @@ * option) any later version. */ -#include -#include #include -#include -#include #include +#include #include @@ -66,66 +63,18 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, return -1; } -static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) -{ - int i; - int ret; - const struct snd_soc_codec_driver *codec_drv; - unsigned int val; - - codec_drv = codec->driver; - for (i = 0; i < codec_drv->reg_cache_size; ++i) { - ret = snd_soc_cache_read(codec, i, &val); - if (ret) - return ret; - if (codec_drv->reg_cache_default) - if (snd_soc_get_cache_val(codec_drv->reg_cache_default, - i, codec_drv->reg_word_size) == val) - continue; - - WARN_ON(!snd_soc_codec_writable_register(codec, i)); - - ret = snd_soc_write(codec, i, val); - if (ret) - return ret; - dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", - i, val); - } - return 0; -} - -static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - snd_soc_set_cache_val(codec->reg_cache, reg, value, - codec->driver->reg_word_size); - return 0; -} - -static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, - unsigned int reg, unsigned int *value) -{ - *value = snd_soc_get_cache_val(codec->reg_cache, reg, - codec->driver->reg_word_size); - return 0; -} - -static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) -{ - if (!codec->reg_cache) - return 0; - kfree(codec->reg_cache); - codec->reg_cache = NULL; - return 0; -} - -static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) +int snd_soc_cache_init(struct snd_soc_codec *codec) { const struct snd_soc_codec_driver *codec_drv = codec->driver; size_t reg_size; reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; + mutex_init(&codec->cache_rw_mutex); + + dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", + codec->name); + if (codec_drv->reg_cache_default) codec->reg_cache = kmemdup(codec_drv->reg_cache_default, reg_size, GFP_KERNEL); @@ -137,60 +86,19 @@ static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) return 0; } -/* an array of all supported compression types */ -static const struct snd_soc_cache_ops cache_types[] = { - /* Flat *must* be the first entry for fallback */ - { - .id = SND_SOC_FLAT_COMPRESSION, - .name = "flat", - .init = snd_soc_flat_cache_init, - .exit = snd_soc_flat_cache_exit, - .read = snd_soc_flat_cache_read, - .write = snd_soc_flat_cache_write, - .sync = snd_soc_flat_cache_sync - }, -}; - -int snd_soc_cache_init(struct snd_soc_codec *codec) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cache_types); ++i) - if (cache_types[i].id == codec->compress_type) - break; - - /* Fall back to flat compression */ - if (i == ARRAY_SIZE(cache_types)) { - dev_warn(codec->dev, "ASoC: Could not match compress type: %d\n", - codec->compress_type); - i = 0; - } - - mutex_init(&codec->cache_rw_mutex); - codec->cache_ops = &cache_types[i]; - - if (codec->cache_ops->init) { - if (codec->cache_ops->name) - dev_dbg(codec->dev, "ASoC: Initializing %s cache for %s codec\n", - codec->cache_ops->name, codec->name); - return codec->cache_ops->init(codec); - } - return -ENOSYS; -} - /* * NOTE: keep in mind that this function might be called * multiple times. */ int snd_soc_cache_exit(struct snd_soc_codec *codec) { - if (codec->cache_ops && codec->cache_ops->exit) { - if (codec->cache_ops->name) - dev_dbg(codec->dev, "ASoC: Destroying %s cache for %s codec\n", - codec->cache_ops->name, codec->name); - return codec->cache_ops->exit(codec); - } - return -ENOSYS; + dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", + codec->name); + if (!codec->reg_cache) + return 0; + kfree(codec->reg_cache); + codec->reg_cache = NULL; + return 0; } /** @@ -203,18 +111,15 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) int snd_soc_cache_read(struct snd_soc_codec *codec, unsigned int reg, unsigned int *value) { - int ret; + if (!value) + return -EINVAL; mutex_lock(&codec->cache_rw_mutex); - - if (value && codec->cache_ops && codec->cache_ops->read) { - ret = codec->cache_ops->read(codec, reg, value); - mutex_unlock(&codec->cache_rw_mutex); - return ret; - } - + *value = snd_soc_get_cache_val(codec->reg_cache, reg, + codec->driver->reg_word_size); mutex_unlock(&codec->cache_rw_mutex); - return -ENOSYS; + + return 0; } EXPORT_SYMBOL_GPL(snd_soc_cache_read); @@ -228,20 +133,42 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_read); int snd_soc_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { + mutex_lock(&codec->cache_rw_mutex); + snd_soc_set_cache_val(codec->reg_cache, reg, value, + codec->driver->reg_word_size); + mutex_unlock(&codec->cache_rw_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_cache_write); + +static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) +{ + int i; int ret; + const struct snd_soc_codec_driver *codec_drv; + unsigned int val; - mutex_lock(&codec->cache_rw_mutex); + codec_drv = codec->driver; + for (i = 0; i < codec_drv->reg_cache_size; ++i) { + ret = snd_soc_cache_read(codec, i, &val); + if (ret) + return ret; + if (codec_drv->reg_cache_default) + if (snd_soc_get_cache_val(codec_drv->reg_cache_default, + i, codec_drv->reg_word_size) == val) + continue; - if (codec->cache_ops && codec->cache_ops->write) { - ret = codec->cache_ops->write(codec, reg, value); - mutex_unlock(&codec->cache_rw_mutex); - return ret; - } + WARN_ON(!snd_soc_codec_writable_register(codec, i)); - mutex_unlock(&codec->cache_rw_mutex); - return -ENOSYS; + ret = snd_soc_write(codec, i, val); + if (ret) + return ret; + dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", + i, val); + } + return 0; } -EXPORT_SYMBOL_GPL(snd_soc_cache_write); /** * snd_soc_cache_sync: Sync the register cache with the hardware. @@ -254,26 +181,16 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write); */ int snd_soc_cache_sync(struct snd_soc_codec *codec) { + const char *name = "flat"; int ret; - const char *name; - if (!codec->cache_sync) { + if (!codec->cache_sync) return 0; - } - - if (!codec->cache_ops || !codec->cache_ops->sync) - return -ENOSYS; - - if (codec->cache_ops->name) - name = codec->cache_ops->name; - else - name = "unknown"; - if (codec->cache_ops->name) - dev_dbg(codec->dev, "ASoC: Syncing %s cache for %s codec\n", - codec->cache_ops->name, codec->name); + dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", + codec->name); trace_snd_soc_cache_sync(codec, name, "start"); - ret = codec->cache_ops->sync(codec); + ret = snd_soc_flat_cache_sync(codec); if (!ret) codec->cache_sync = 0; trace_snd_soc_cache_sync(codec, name, "end"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index af96484..16a3930 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1590,17 +1590,13 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) soc_remove_codec(codec); } -static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, - enum snd_soc_compress_type compress_type) +static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) { int ret; if (codec->cache_init) return 0; - /* override the compress_type if necessary */ - if (compress_type && codec->compress_type != compress_type) - codec->compress_type = compress_type; ret = snd_soc_cache_init(codec); if (ret < 0) { dev_err(codec->dev, @@ -1615,8 +1611,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; - struct snd_soc_codec_conf *codec_conf; - enum snd_soc_compress_type compress_type; struct snd_soc_dai_link *dai_link; int ret, i, order, dai_fmt; @@ -1640,19 +1634,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) list_for_each_entry(codec, &codec_list, list) { if (codec->cache_init) continue; - /* by default we don't override the compress_type */ - compress_type = 0; - /* check to see if we need to override the compress_type */ - for (i = 0; i < card->num_configs; ++i) { - codec_conf = &card->codec_conf[i]; - if (!strcmp(codec->name, codec_conf->dev_name)) { - compress_type = codec_conf->compress_type; - if (compress_type && compress_type - != codec->compress_type) - break; - } - } - ret = snd_soc_init_codec_cache(codec, compress_type); + ret = snd_soc_init_codec_cache(codec); if (ret < 0) goto base_error; } @@ -4175,11 +4157,6 @@ int snd_soc_register_codec(struct device *dev, goto fail_codec; } - if (codec_drv->compress_type) - codec->compress_type = codec_drv->compress_type; - else - codec->compress_type = SND_SOC_FLAT_COMPRESSION; - codec->write = codec_drv->write; codec->read = codec_drv->read; codec->volatile_register = codec_drv->volatile_register; -- cgit v0.10.2 From 56fb7421d23c63cf22ac885d2db2302cefc9e1f1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Sep 2013 18:09:46 +0100 Subject: ASoC: trace: Make sure trace header doesnt depend on any headers Fix build so that asoc trace event header doesn't depend on other headers. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 5fc2dcd..03996b2 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -14,6 +14,7 @@ struct snd_soc_codec; struct snd_soc_platform; struct snd_soc_card; struct snd_soc_dapm_widget; +struct snd_soc_dapm_path; /* * Log register events -- cgit v0.10.2 From 7f05cc98bd9b10b9a0173f3f5d20c2223fdf7470 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Sep 2013 18:09:47 +0100 Subject: ASoC: core utils: Dont set DMA params for BE substreams BE substreams dont require dummy DMA configs so dont set any. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 29b211e..5e63365 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -75,7 +75,11 @@ static const struct snd_pcm_hardware dummy_dma_hardware = { static int dummy_dma_open(struct snd_pcm_substream *substream) { - snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* BE's dont need dummy params */ + if (!rtd->dai_link->no_pcm) + snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); return 0; } -- cgit v0.10.2 From 8ecb5344fd6409c500c9d5757c3a7130d3d7db5b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 13:51:38 +0100 Subject: ASoC: cq93vc: Don't use control data for core driver data The platform data is being used to obtain the core driver data for the device (which is a bit of an abuse but not the issue at hand) so reference it directly in order to support refactoring to use regmap. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 23316c8..e2c4c0a8 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -79,7 +79,7 @@ static int cq93vc_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 davinci_vc *davinci_vc = codec->control_data; + struct davinci_vc *davinci_vc = codec->dev->platform_data; switch (freq) { case 22579200: -- cgit v0.10.2 From a851a2bb2d746ccdec0c7cc6ed1c9774921e721e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 13 Sep 2013 15:22:17 +0530 Subject: ASoC: fsl_ssi: Staticize local symbols Local symbols used only in this file are made static. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6b7439..4973be7 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -748,7 +748,7 @@ static void fsl_ssi_ac97_init(void) fsl_ssi_setup(fsl_ac97_data); } -void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, +static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct ccsr_ssi *ssi = fsl_ac97_data->ssi; @@ -770,7 +770,7 @@ void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, udelay(100); } -unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, +static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct ccsr_ssi *ssi = fsl_ac97_data->ssi; -- cgit v0.10.2 From b51600c01979ab1d1c4df17e8910696547ffb9a2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 31 Aug 2013 13:43:36 +0100 Subject: ASoC: kirkwood-dma: remove IEC958_SUBFRAME formats The Audio block does not support IEC958 subframes as formatted by ALSA: they're very close, but not close enough. The formats differ by: 3 2 2 2 1 1 1 8 4 0 6 2 8 4 0 PCUVDDDDDDDDDDDDDDDD....AAAATTTT - IEC958 subframe PCUV0000........DDDDDDDDDDDDDDDD - Audio block format Where P = parity, C = channel status, U = user data, V = validity, D = sample data, A = aux, T = preamble. As can be seen, the position of the sample is in a different position, and the audio block does not have the aux or preamble bits. Signed-off-by: Russell King Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index b238434..0c85c4e 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -29,9 +29,7 @@ #define KIRKWOOD_FORMATS \ (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE | \ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE) + SNDRV_PCM_FMTBIT_S32_LE) static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) { -- cgit v0.10.2 From 38f2b8cbfb1ef517af8af5a63bdff073b7b078fd Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 2 Sep 2013 17:56:18 -0300 Subject: ASoC: mxs: mxs-sgtl5000: Simplify probe function mxs is a device tree only platform, which allows us to simplify a bit mxs_sgtl5000_probe(), because there is no need to check whether device tree is supported or not. Remove mxs_sgtl5000_probe_dt() and place its content inside mxs_sgtl5000_probe() for making the code simpler. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 4bb2737..61822cc 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -122,14 +122,12 @@ static struct snd_soc_card mxs_sgtl5000 = { .num_links = ARRAY_SIZE(mxs_sgtl5000_dai), }; -static int mxs_sgtl5000_probe_dt(struct platform_device *pdev) +static int mxs_sgtl5000_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &mxs_sgtl5000; + int ret, i; struct device_node *np = pdev->dev.of_node; struct device_node *saif_np[2], *codec_np; - int i; - - if (!np) - return 1; /* no device tree */ saif_np[0] = of_parse_phandle(np, "saif-controllers", 0); saif_np[1] = of_parse_phandle(np, "saif-controllers", 1); @@ -152,18 +150,6 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev) of_node_put(saif_np[0]); of_node_put(saif_np[1]); - return 0; -} - -static int mxs_sgtl5000_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &mxs_sgtl5000; - int ret; - - ret = mxs_sgtl5000_probe_dt(pdev); - if (ret < 0) - return ret; - /* * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w). * The Sgtl5000 sysclk is derived from saif0 mclk and it's range -- cgit v0.10.2 From 89d051300b845e1001a9d9e9ce94da4250c21613 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 13 Sep 2013 15:22:18 +0530 Subject: ASoC: rt5640: Staticize hp_amp_power_on 'hp_amp_power_on' is used only in this file. Make it static. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index c26a8f8..2f6bb16 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -926,7 +926,7 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w, return 0; } -void hp_amp_power_on(struct snd_soc_codec *codec) +static void hp_amp_power_on(struct snd_soc_codec *codec) { struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -- cgit v0.10.2 From 9e9cb9b99615180b94d743f1d6ca0f82539c8754 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Sep 2013 17:57:35 +0100 Subject: ASoC: rt5640: Provide more useful hw_params error reasons. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 2f6bb16..de40bd9 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1609,7 +1609,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream, rt5640->lrck[dai->id] = params_rate(params); pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]); if (pre_div < 0) { - dev_err(codec->dev, "Unsupported clock setting\n"); + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5640->lrck[dai->id], dai->id); return -EINVAL; } frame_size = snd_soc_params_to_frame_size(params); -- cgit v0.10.2 From 02b80773de3732dae11c1cf0c1ce40378901bd0e Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Sep 2013 17:57:36 +0100 Subject: ASoC: rt5640: Add ACPI probing support. Allow the RT5640 to be probed as an ACPI I2C device. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index de40bd9..0bfb960 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2081,6 +2082,12 @@ static const struct i2c_device_id rt5640_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); +static struct acpi_device_id rt5640_acpi_match[] = { + { "INT33CA", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); + static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) { rt5640->pdata.in1_diff = of_property_read_bool(np, @@ -2200,6 +2207,7 @@ static struct i2c_driver rt5640_i2c_driver = { .driver = { .name = "rt5640", .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(rt5640_acpi_match), }, .probe = rt5640_i2c_probe, .remove = rt5640_i2c_remove, -- cgit v0.10.2 From 37c83edf9afd3d7b39ace9113a166c03b7a2820f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 13:17:08 +0100 Subject: ASoC: wm8400: Use supplies to manage input power Rather than using a fake register to manage input power create some supply widgets and use those. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index d2a0928..95c33d1 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -32,13 +32,6 @@ #include "wm8400.h" -/* Fake register for internal state */ -#define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1) -#define WM8400_INMIXL_PWR 0 -#define WM8400_AINLMUX_PWR 1 -#define WM8400_INMIXR_PWR 2 -#define WM8400_AINRMUX_PWR 3 - static struct regulator_bulk_data power[] = { { .supply = "I2S1VDD", @@ -79,10 +72,7 @@ static inline unsigned int wm8400_read(struct snd_soc_codec *codec, { struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); - if (reg == WM8400_INTDRIVBITS) - return wm8400->fake_register; - else - return wm8400_reg_read(wm8400->wm8400, reg); + return wm8400_reg_read(wm8400->wm8400, reg); } /* @@ -93,11 +83,7 @@ static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg, { struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); - if (reg == WM8400_INTDRIVBITS) { - wm8400->fake_register = value; - return 0; - } else - return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); + return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); } static void wm8400_codec_reset(struct snd_soc_codec *codec) @@ -352,32 +338,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, * _DAPM_ Controls */ -static int inmixer_event (struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - u16 reg, fakepower; - - reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2); - fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS); - - if (fakepower & ((1 << WM8400_INMIXL_PWR) | - (1 << WM8400_AINLMUX_PWR))) { - reg |= WM8400_AINL_ENA; - } else { - reg &= ~WM8400_AINL_ENA; - } - - if (fakepower & ((1 << WM8400_INMIXR_PWR) | - (1 << WM8400_AINRMUX_PWR))) { - reg |= WM8400_AINR_ENA; - } else { - reg &= ~WM8400_AINR_ENA; - } - snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg); - - return 0; -} - static int outmixer_event (struct snd_soc_dapm_widget *w, struct snd_kcontrol * kcontrol, int event) { @@ -658,27 +618,26 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2, 0, &wm8400_dapm_rin34_pga_controls[0], ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)), +SND_SOC_DAPM_SUPPLY("INL", WM8400_POWER_MANAGEMENT_2, WM8400_AINL_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("INR", WM8400_POWER_MANAGEMENT_2, WM8400_AINR_ENA_SHIFT, + 0, NULL, 0), + /* INMIXL */ -SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0, +SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0, &wm8400_dapm_inmixl_controls[0], - ARRAY_SIZE(wm8400_dapm_inmixl_controls), - inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + ARRAY_SIZE(wm8400_dapm_inmixl_controls)), /* AINLMUX */ -SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0, - &wm8400_dapm_ainlmux_controls, inmixer_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AILNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainlmux_controls), /* INMIXR */ -SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0, +SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0, &wm8400_dapm_inmixr_controls[0], - ARRAY_SIZE(wm8400_dapm_inmixr_controls), - inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + ARRAY_SIZE(wm8400_dapm_inmixr_controls)), /* AINRMUX */ -SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0, - &wm8400_dapm_ainrmux_controls, inmixer_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AIRNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainrmux_controls), /* Output Side */ /* DACs */ @@ -789,11 +748,13 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = { {"LIN34 PGA", "LIN3 Switch", "LIN3"}, {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"}, /* INMIXL */ + {"INMIXL", NULL, "INL"}, {"INMIXL", "Record Left Volume", "LOMIX"}, {"INMIXL", "LIN2 Volume", "LIN2"}, {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, /* AILNMUX */ + {"AILNMUX", NULL, "INL"}, {"AILNMUX", "INMIXL Mix", "INMIXL"}, {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"}, {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"}, @@ -808,12 +769,14 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = { /* RIN34 PGA */ {"RIN34 PGA", "RIN3 Switch", "RIN3"}, {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"}, - /* INMIXL */ + /* INMIXR */ + {"INMIXR", NULL, "INR"}, {"INMIXR", "Record Right Volume", "ROMIX"}, {"INMIXR", "RIN2 Volume", "RIN2"}, {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, /* AIRNMUX */ + {"AIRNMUX", NULL, "INR"}, {"AIRNMUX", "INMIXR Mix", "INMIXR"}, {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"}, {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"}, -- cgit v0.10.2 From b8cc4151f8af97e1b573ca399a77f439f401a57e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 13:21:12 +0100 Subject: ASoC: wm8400: Use regmap for I/O Since we no longer have a fake register to simulate we can use the framework for I/O. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 95c33d1..48dc7d2 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -67,25 +67,6 @@ struct wm8400_priv { int fll_in, fll_out; }; -static inline unsigned int wm8400_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); - - return wm8400_reg_read(wm8400->wm8400, reg); -} - -/* - * write to the wm8400 register space - */ -static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); - - return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); -} - static void wm8400_codec_reset(struct snd_soc_codec *codec) { struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); @@ -1328,9 +1309,12 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) return -ENOMEM; snd_soc_codec_set_drvdata(codec, priv); - codec->control_data = priv->wm8400 = wm8400; + priv->wm8400 = wm8400; + codec->control_data = wm8400->regmap; priv->codec = codec; + snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); + ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { @@ -1377,8 +1361,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .remove = wm8400_codec_remove, .suspend = wm8400_suspend, .resume = wm8400_resume, - .read = snd_soc_read, - .write = wm8400_write, .set_bias_level = wm8400_set_bias_level, .controls = wm8400_snd_controls, -- cgit v0.10.2 From a0ff6ea24f785ec58bccdbce7b366661c57e3591 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 11 Sep 2013 15:27:29 +0100 Subject: ASoC: samsung: Allow mono in i2s driver Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b302f3b..a7e3519 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1060,7 +1060,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops; i2s->i2s_dai_drv.suspend = i2s_suspend; i2s->i2s_dai_drv.resume = i2s_resume; - i2s->i2s_dai_drv.playback.channels_min = 2; + i2s->i2s_dai_drv.playback.channels_min = 1; i2s->i2s_dai_drv.playback.channels_max = 2; i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES; i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS; -- cgit v0.10.2 From b3a6006e1d106fddcfc121d0ccfa9b7faeeb8f3e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 16 Sep 2013 15:38:15 +0100 Subject: ASoC: bells: Add missing route to power up DSP clock Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 29e2468..84f5d8b 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -356,6 +356,7 @@ static struct snd_soc_dapm_widget bells_widgets[] = { static struct snd_soc_dapm_route bells_routes[] = { { "Sub CLK_SYS", NULL, "OPCLK" }, + { "CLKIN", NULL, "OPCLK" }, { "DMIC", NULL, "MICBIAS2" }, { "IN2L", NULL, "DMIC" }, -- cgit v0.10.2 From 49c60547daebaa79e8de9d2dff6dee994576c94c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 16 Sep 2013 15:34:35 +0100 Subject: ASoC: arizona: Improve handling of setting REFCLK to 0 This patch suppresses calculation of REFCLK parameters when the REFCLK source frequency is set to zero, additionally it will consider a source frequency of zero as the REFCLK being disabled and switch to using the SYNCCLK. Reported-by: Kyung Kwee Ryu Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 657808b..6f05b17 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1477,21 +1477,25 @@ static void arizona_enable_fll(struct arizona_fll *fll, { struct arizona *arizona = fll->arizona; int ret; + bool use_sync = false; /* * If we have both REFCLK and SYNCCLK then enable both, * otherwise apply the SYNCCLK settings to REFCLK. */ - if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) { + if (fll->ref_src >= 0 && fll->ref_freq && + fll->ref_src != fll->sync_src) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, false); - if (fll->sync_src >= 0) + if (fll->sync_src >= 0) { arizona_apply_fll(arizona, fll->base + 0x10, sync, fll->sync_src, true); + use_sync = true; + } } else if (fll->sync_src >= 0) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, @@ -1511,7 +1515,7 @@ static void arizona_enable_fll(struct arizona_fll *fll, * Increase the bandwidth if we're not using a low frequency * sync source. */ - if (fll->sync_src >= 0 && fll->sync_freq > 100000) + if (use_sync && fll->sync_freq > 100000) regmap_update_bits(arizona->regmap, fll->base + 0x17, ARIZONA_FLL1_SYNC_BW, 0); else @@ -1526,8 +1530,7 @@ static void arizona_enable_fll(struct arizona_fll *fll, regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (fll->ref_src >= 0 && fll->sync_src >= 0 && - fll->ref_src != fll->sync_src) + if (use_sync) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); @@ -1561,10 +1564,12 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (fll->fout && Fref > 0) { - ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); - if (ret != 0) - return ret; + if (fll->fout) { + if (Fref > 0) { + ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); + if (ret != 0) + return ret; + } if (fll->sync_src >= 0) { ret = arizona_calc_fll(fll, &sync, fll->sync_freq, -- cgit v0.10.2 From 193b2f65b87e9da78b15f3e3a0cae1d37fbafa57 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 16 Sep 2013 18:14:20 +0200 Subject: ASoC: ak4104: provide a module device table Provide a module device table for the SPI subsystem, so the driver can be autoloaded by the SPI core. While at it, get rid of an unnecessary #define. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 71059c0..b4819dc 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -45,8 +45,6 @@ #define AK4104_TX_TXE (1 << 0) #define AK4104_TX_V (1 << 1) -#define DRV_NAME "ak4104-codec" - struct ak4104_private { struct regmap *regmap; }; @@ -291,12 +289,19 @@ static const struct of_device_id ak4104_of_match[] = { }; MODULE_DEVICE_TABLE(of, ak4104_of_match); +static const struct spi_device_id ak4104_id_table[] = { + { "ak4104", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ak4104_id_table); + static struct spi_driver ak4104_spi_driver = { .driver = { - .name = DRV_NAME, + .name = "ak4104", .owner = THIS_MODULE, .of_match_table = ak4104_of_match, }, + .id_table = ak4104_id_table, .probe = ak4104_spi_probe, .remove = ak4104_spi_remove, }; -- cgit v0.10.2 From bf551413038f74343ec4d1413c3610e2362d0aeb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 13 Sep 2013 16:16:17 +0530 Subject: ASoC: twl6040: Remove redundant semicolon Redundant semicolon removed. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 3c79dbb..35059a2 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -246,7 +246,7 @@ static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec, return priv->dl2_unmuted; default: return 1; - }; + } } /* @@ -1100,7 +1100,7 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i break; default: break; - }; + } } static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute) -- cgit v0.10.2 From a0b03a616b08cf9d709812ff5cf7e9c0958d6807 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Sep 2013 20:37:34 +0100 Subject: ASoC: core: Implement devm_snd_soc_register_component() Since with the wider use of devres many drivers are now only calling snd_soc_unregister_component() in their remove functions providing a managed version will save a reasonable amount of code. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index d22cb0a..b970f01 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -386,6 +386,9 @@ void snd_soc_unregister_codec(struct device *dev); int snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *cmpnt_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); +int devm_snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_component(struct device *dev); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, unsigned int reg); diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 61a64d2..8b9e701 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o +snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) snd-soc-core-objs += soc-generic-dmaengine-pcm.o diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c new file mode 100644 index 0000000..13fe86f --- /dev/null +++ b/sound/soc/soc-devres.c @@ -0,0 +1,52 @@ +/* + * soc-devres.c -- ALSA SoC Audio Layer devres functions + * + * Copyright (C) 2013 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +static void devm_component_release(struct device *dev, void *res) +{ + snd_soc_unregister_component(*(struct device **)res); +} + +/** + * devm_snd_soc_register_component - resource managed component registration + * @dev: Device used to manage component + * @cmpnt_drv: Component driver + * @dai_drv: DAI driver + * @num_dai: Number of DAIs to register + * + * Register a component with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); -- cgit v0.10.2 From 0e4ff5c806263bf40ee5409ac283b776f0c11e41 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 16 Sep 2013 18:02:05 +0100 Subject: ASoC: core: Add devm_snd_soc_register_card() Simplify error handling and remove repetitive (and rarely executed) code for unregistration by providing a devm_snd_soc_register() card. Signed-off-by: Mark Brown Acked-by: Liam Girdwood diff --git a/include/sound/soc.h b/include/sound/soc.h index b970f01..d44728a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -369,6 +369,7 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, int snd_soc_register_card(struct snd_soc_card *card); int snd_soc_unregister_card(struct snd_soc_card *card); +int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card); int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); int snd_soc_poweroff(struct device *dev); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index 13fe86f..b1d7322 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -50,3 +50,37 @@ int devm_snd_soc_register_component(struct device *dev, return ret; } EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); + +static void devm_card_release(struct device *dev, void *res) +{ + snd_soc_unregister_card(*(struct snd_soc_card **)res); +} + +/** + * devm_snd_soc_register_card - resource managed card registration + * @dev: Device used to manage card + * @card: Card to register + * + * Register a card with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_card(card); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); -- cgit v0.10.2 From 9a8e0322f0a8c7506f4ced07ec2a7e7e2a9cbe4a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 16 Sep 2013 18:02:28 +0100 Subject: ASoC: smdk_wm8994: Use devm_snd_soc_unregister_card() Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 5fd7a05..831972d 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -193,7 +193,7 @@ static int smdk_audio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, board); - ret = snd_soc_register_card(card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); @@ -201,15 +201,6 @@ static int smdk_audio_probe(struct platform_device *pdev) return ret; } -static int smdk_audio_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - static struct platform_driver smdk_audio_driver = { .driver = { .name = "smdk-audio-wm8894", @@ -217,7 +208,6 @@ static struct platform_driver smdk_audio_driver = { .of_match_table = of_match_ptr(samsung_wm8994_of_match), }, .probe = smdk_audio_probe, - .remove = smdk_audio_remove, }; module_platform_driver(smdk_audio_driver); -- cgit v0.10.2 From d644a115e86433abbb544808c4be1e4b5a048c2b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Sep 2013 20:37:51 +0100 Subject: ASoC: samsung-i2s: Use devm_snd_soc_register_component() Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index a7e3519..32956df 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1143,9 +1143,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get drvdata\n"); return -EFAULT; } - snd_soc_register_component(&sec_dai->pdev->dev, - &samsung_i2s_component, - &sec_dai->i2s_dai_drv, 1); + devm_snd_soc_register_component(&sec_dai->pdev->dev, + &samsung_i2s_component, + &sec_dai->i2s_dai_drv, 1); samsung_asoc_dma_platform_register(&pdev->dev); return 0; } @@ -1258,8 +1258,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) goto err; } - snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component, - &pri_dai->i2s_dai_drv, 1); + devm_snd_soc_register_component(&pri_dai->pdev->dev, + &samsung_i2s_component, + &pri_dai->i2s_dai_drv, 1); pm_runtime_enable(&pdev->dev); @@ -1294,7 +1295,6 @@ static int samsung_i2s_remove(struct platform_device *pdev) i2s->sec_dai = NULL; samsung_asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v0.10.2 From 0feb23d1bdf31db903069d3d94892e56b5c11981 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 13 Sep 2013 15:50:50 +0530 Subject: ASoC: ak4642: Remove redundant break 'break' after return statement is redundant. Remove it. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 2d03787..21c35ed 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -352,7 +352,6 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) */ default: return -EINVAL; - break; } snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data); @@ -405,7 +404,6 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream, break; default: return -EINVAL; - break; } snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate); -- cgit v0.10.2 From e54cf76ba2c9ec071a68e98f2830226c0cac8086 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 16 Sep 2013 13:01:46 +0100 Subject: ASoC: core: Add API for configuration of DAI BCLK ratio Some codec drivers when running in slave mode require that BCLK to sample rate ratio is explicitly set by the machine driver as it may not be exactly rate * frame size. Extend the DAI API by adding :- int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio); Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ae9a227..d8acf0c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -105,6 +105,8 @@ int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out); +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio); + /* Digital Audio interface formatting */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); @@ -131,6 +133,7 @@ struct snd_soc_dai_ops { int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out); int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); + int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio); /* * DAI format configuration diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d05613..31adad0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3577,6 +3577,22 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); /** + * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. + * @dai: DAI + * @ratio Ratio of BCLK to Sample rate. + * + * Configures the DAI for a preset BCLK to sample rate ratio. + */ +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + if (dai->driver && dai->driver->ops->set_bclk_ratio) + return dai->driver->ops->set_bclk_ratio(dai, ratio); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); + +/** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI * @fmt: SND_SOC_DAIFMT_ format value. -- cgit v0.10.2 From d191bd8de8c61619563f2b19f1fdcc0944ff1a72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2013 19:39:03 -0700 Subject: ASoC: snd_soc_codec includes snd_soc_component Codec includes component by this patch, and component moved to upside of codec to avoid extra declaration. Codec dai will be registered via component by this patch. Current component register function is used for cpu, and it is using dai/dais functions properly to keep existing cpu dai name. And now, it will be used from codec also. But codec driver had been used dais function only even though it was single dai. This patch adds new flag which can selects dai/dais function on component register function to keep existing codec dai name. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index d22cb0a..9a81e2e 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -670,6 +670,21 @@ struct snd_soc_cache_ops { int (*sync)(struct snd_soc_codec *codec); }; +/* component interface */ +struct snd_soc_component_driver { + const char *name; +}; + +struct snd_soc_component { + const char *name; + int id; + int num_dai; + struct device *dev; + struct list_head list; + + const struct snd_soc_component_driver *driver; +}; + /* SoC Audio Codec device */ struct snd_soc_codec { const char *name; @@ -715,6 +730,9 @@ struct snd_soc_codec { struct mutex cache_rw_mutex; int val_bytes; + /* component */ + struct snd_soc_component component; + /* dapm */ struct snd_soc_dapm_context dapm; unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ @@ -733,6 +751,7 @@ struct snd_soc_codec_driver { int (*remove)(struct snd_soc_codec *); int (*suspend)(struct snd_soc_codec *); int (*resume)(struct snd_soc_codec *); + struct snd_soc_component_driver component_driver; /* Default control and setup, added after probe() is run */ const struct snd_kcontrol_new *controls; @@ -849,20 +868,6 @@ struct snd_soc_platform { #endif }; -struct snd_soc_component_driver { - const char *name; -}; - -struct snd_soc_component { - const char *name; - int id; - int num_dai; - struct device *dev; - struct list_head list; - - const struct snd_soc_component_driver *driver; -}; - struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d05613..014ac10 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4021,6 +4021,112 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count) } /** + * snd_soc_register_component - Register a component with the ASoC core + * + */ +static int +__snd_soc_register_component(struct device *dev, + struct snd_soc_component *cmpnt, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai, bool allow_single_dai) +{ + int ret; + + dev_dbg(dev, "component register %s\n", dev_name(dev)); + + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to connecting component\n"); + return -ENOMEM; + } + + cmpnt->name = fmt_single_name(dev, &cmpnt->id); + if (!cmpnt->name) { + dev_err(dev, "ASoC: Failed to simplifying name\n"); + return -ENOMEM; + } + + cmpnt->dev = dev; + cmpnt->driver = cmpnt_drv; + cmpnt->num_dai = num_dai; + + /* + * snd_soc_register_dai() uses fmt_single_name(), and + * snd_soc_register_dais() uses fmt_multiple_name() + * for dai->name which is used for name based matching + * + * this function is used from cpu/codec. + * allow_single_dai flag can ignore "codec" driver reworking + * since it had been used snd_soc_register_dais(), + */ + if ((1 == num_dai) && allow_single_dai) + ret = snd_soc_register_dai(dev, dai_drv); + else + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_component_name; + } + + mutex_lock(&client_mutex); + list_add(&cmpnt->list, &component_list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + + return ret; + +error_component_name: + kfree(cmpnt->name); + + return ret; +} + +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_component *cmpnt; + + cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to allocate memory\n"); + return -ENOMEM; + } + + return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, + dai_drv, num_dai, true); +} +EXPORT_SYMBOL_GPL(snd_soc_register_component); + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +void snd_soc_unregister_component(struct device *dev) +{ + struct snd_soc_component *cmpnt; + + list_for_each_entry(cmpnt, &component_list, list) { + if (dev == cmpnt->dev) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cmpnt->num_dai); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); + +/** * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform * @platform: The platform to add @@ -4242,10 +4348,12 @@ int snd_soc_register_codec(struct device *dev, list_add(&codec->list, &codec_list); mutex_unlock(&client_mutex); - /* register any DAIs */ - ret = snd_soc_register_dais(dev, dai_drv, num_dai); + /* register component */ + ret = __snd_soc_register_component(dev, &codec->component, + &codec_drv->component_driver, + dai_drv, num_dai, false); if (ret < 0) { - dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); + dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); goto fail_codec_name; } @@ -4280,7 +4388,7 @@ void snd_soc_unregister_codec(struct device *dev) return; found: - snd_soc_unregister_dais(dev, codec->num_dai); + snd_soc_unregister_component(dev); mutex_lock(&client_mutex); list_del(&codec->list); @@ -4295,92 +4403,6 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); - -/** - * snd_soc_register_component - Register a component with the ASoC core - * - */ -int snd_soc_register_component(struct device *dev, - const struct snd_soc_component_driver *cmpnt_drv, - struct snd_soc_dai_driver *dai_drv, - int num_dai) -{ - struct snd_soc_component *cmpnt; - int ret; - - dev_dbg(dev, "component register %s\n", dev_name(dev)); - - cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); - if (!cmpnt) { - dev_err(dev, "ASoC: Failed to allocate memory\n"); - return -ENOMEM; - } - - cmpnt->name = fmt_single_name(dev, &cmpnt->id); - if (!cmpnt->name) { - dev_err(dev, "ASoC: Failed to simplifying name\n"); - return -ENOMEM; - } - - cmpnt->dev = dev; - cmpnt->driver = cmpnt_drv; - cmpnt->num_dai = num_dai; - - /* - * snd_soc_register_dai() uses fmt_single_name(), and - * snd_soc_register_dais() uses fmt_multiple_name() - * for dai->name which is used for name based matching - */ - if (1 == num_dai) - ret = snd_soc_register_dai(dev, dai_drv); - else - ret = snd_soc_register_dais(dev, dai_drv, num_dai); - if (ret < 0) { - dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); - goto error_component_name; - } - - mutex_lock(&client_mutex); - list_add(&cmpnt->list, &component_list); - mutex_unlock(&client_mutex); - - dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); - - return ret; - -error_component_name: - kfree(cmpnt->name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_register_component); - -/** - * snd_soc_unregister_component - Unregister a component from the ASoC core - * - */ -void snd_soc_unregister_component(struct device *dev) -{ - struct snd_soc_component *cmpnt; - - list_for_each_entry(cmpnt, &component_list, list) { - if (dev == cmpnt->dev) - goto found; - } - return; - -found: - snd_soc_unregister_dais(dev, cmpnt->num_dai); - - mutex_lock(&client_mutex); - list_del(&cmpnt->list); - mutex_unlock(&client_mutex); - - dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); - kfree(cmpnt->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_component); - /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) -- cgit v0.10.2 From cb470087669a3fab1958fec79dd7db280b33f178 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Sep 2013 17:39:56 -0700 Subject: ASoC: add .of_xlate_dai_name on snd_soc_component_driver ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC. But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name. Now, CPU/CODEC are based on struct snd_soc_component, and it can care above as common issue. This patch adds .of_xlate_dai_name callback interface on struct snd_soc_component_driver, and snd_soc_of_get_dai_name() which is using .of_xlate_dai_name. Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 9a81e2e..1dd7dc5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -13,6 +13,7 @@ #ifndef __LINUX_SND_SOC_H #define __LINUX_SND_SOC_H +#include #include #include #include @@ -673,6 +674,11 @@ struct snd_soc_cache_ops { /* component interface */ struct snd_soc_component_driver { const char *name; + + /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); }; struct snd_soc_component { @@ -1206,6 +1212,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix); +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name); #include diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 014ac10..711bd36 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4590,6 +4590,41 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name) +{ + struct snd_soc_component *pos; + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(of_node, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + return ret; + + ret = -EPROBE_DEFER; + + mutex_lock(&client_mutex); + list_for_each_entry(pos, &component_list, list) { + if (pos->dev->of_node != args.np) + continue; + + if (!pos->driver->of_xlate_dai_name) { + ret = -ENOSYS; + break; + } + + ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); + break; + } + mutex_unlock(&client_mutex); + + of_node_put(args.np); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS -- cgit v0.10.2 From e19bcb6b95c0326ca364814b86b32799aa7e20db Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 13 Sep 2013 15:52:42 +0530 Subject: ASoC: fsl_spdif: Remove redundant semicolon Redundant semicolon at the end of brace is removed. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3920c3e..c0fea02 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -963,7 +963,7 @@ static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) @@ -982,7 +982,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config fsl_spdif_regmap_config = { -- cgit v0.10.2 From feb8f1147618ebf20ab3e5efc143ceb621063f81 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 13 Sep 2013 15:59:25 +0530 Subject: ASoC: fsl_ssi: Remove redundant dev_set_drvdata Driver core sets the driver data to NULL on detach. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 4973be7..6ac8730 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1135,7 +1135,6 @@ static int fsl_ssi_remove(struct platform_device *pdev) if (ssi_private->ssi_on_imx) imx_pcm_dma_exit(pdev); snd_soc_unregister_component(&pdev->dev); - dev_set_drvdata(&pdev->dev, NULL); device_remove_file(&pdev->dev, &ssi_private->dev_attr); if (ssi_private->ssi_on_imx) clk_disable_unprepare(ssi_private->clk); -- cgit v0.10.2 From a0102375ee82db1e08324b1a21484854cf2c1677 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 1 Sep 2013 20:30:50 -0700 Subject: regmap: Add regmap_fields APIs Current Linux kernel is supporting regmap_field method and it is very useful feature. It needs one regmap_filed for one register access. OTOH, there is multi port device which has many same registers in the market. The difference for each register access is only its address offset. Current API needs many regmap_field for such device, but it is not good. This patch adds new regmap_fileds API which can care about multi port/offset access via regmap. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f7778..9010614 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -179,6 +179,9 @@ struct regmap_field { /* lsb */ unsigned int shift; unsigned int reg; + + unsigned int id_size; + unsigned int id_offset; }; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 285afa7..00152bf 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -821,6 +821,8 @@ static void regmap_field_init(struct regmap_field *rm_field, rm_field->reg = reg_field.reg; rm_field->shift = reg_field.lsb; rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); + rm_field->id_size = reg_field.id_size; + rm_field->id_offset = reg_field.id_offset; } /** @@ -1389,6 +1391,54 @@ int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsi } EXPORT_SYMBOL_GPL(regmap_field_update_bits); +/** + * regmap_fields_write(): Write a value to a single register field with port ID + * + * @field: Register field to write to + * @id: port ID + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_fields_write(struct regmap_field *field, unsigned int id, + unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + return regmap_update_bits(field->regmap, + field->reg + (field->id_offset * id), + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_write); + +/** + * regmap_fields_update_bits(): Perform a read/modify/write cycle + * on the register field + * + * @field: Register field to write to + * @id: port ID + * @mask: Bitmask to change + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, + unsigned int mask, unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + mask = (mask << field->shift) & field->mask; + + return regmap_update_bits(field->regmap, + field->reg + (field->id_offset * id), + mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_update_bits); + /* * regmap_bulk_write(): Write multiple registers to the device * @@ -1697,6 +1747,39 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val) EXPORT_SYMBOL_GPL(regmap_field_read); /** + * regmap_fields_read(): Read a value to a single register field with port ID + * + * @field: Register field to read from + * @id: port ID + * @val: Pointer to store read value + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_fields_read(struct regmap_field *field, unsigned int id, + unsigned int *val) +{ + int ret; + unsigned int reg_val; + + if (id >= field->id_size) + return -EINVAL; + + ret = regmap_read(field->regmap, + field->reg + (field->id_offset * id), + ®_val); + if (ret != 0) + return ret; + + reg_val &= field->mask; + reg_val >>= field->shift; + *val = reg_val; + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_fields_read); + +/** * regmap_bulk_read(): Read multiple registers from the device * * @map: Register map to write to diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 4c8c20a..a12bea0 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -425,11 +425,15 @@ bool regmap_reg_in_ranges(unsigned int reg, * @reg: Offset of the register within the regmap bank * @lsb: lsb of the register field. * @reg: msb of the register field. + * @id_size: port size if it has some ports + * @id_offset: address offset for each ports */ struct reg_field { unsigned int reg; unsigned int lsb; unsigned int msb; + unsigned int id_size; + unsigned int id_offset; }; #define REG_FIELD(_reg, _lsb, _msb) { \ @@ -451,6 +455,13 @@ int regmap_field_write(struct regmap_field *field, unsigned int val); int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val); +int regmap_fields_write(struct regmap_field *field, unsigned int id, + unsigned int val); +int regmap_fields_read(struct regmap_field *field, unsigned int id, + unsigned int *val); +int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, + unsigned int mask, unsigned int val); + /** * Description of an IRQ for the generic regmap irq_chip. * -- cgit v0.10.2 From 072188b61c9b7aedaa15c46226b537345644beee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 1 Sep 2013 20:31:16 -0700 Subject: ASoC: rsnd: gen: rsnd_gen_ops cares .probe and .remove Current rsnd_gen_ops didn't care about .probe and .remove functions, but it was not good sense. This patch tidyup it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index babb203..331fc55 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -11,6 +11,11 @@ #include "rsnd.h" struct rsnd_gen_ops { + int (*probe)(struct platform_device *pdev, + struct rcar_snd_info *info, + struct rsnd_priv *priv); + void (*remove)(struct platform_device *pdev, + struct rsnd_priv *priv); int (*path_init)(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io); @@ -98,11 +103,6 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv, return ret; } -static struct rsnd_gen_ops rsnd_gen1_ops = { - .path_init = rsnd_gen1_path_init, - .path_exit = rsnd_gen1_path_exit, -}; - #define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \ do { \ (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \ @@ -163,7 +163,6 @@ static int rsnd_gen1_probe(struct platform_device *pdev, IS_ERR(gen->base[RSND_GEN1_SSI])) return -ENODEV; - gen->ops = &rsnd_gen1_ops; rsnd_gen1_reg_map_init(gen); dev_dbg(dev, "Gen1 device probed\n"); @@ -183,6 +182,13 @@ static void rsnd_gen1_remove(struct platform_device *pdev, { } +static struct rsnd_gen_ops rsnd_gen1_ops = { + .probe = rsnd_gen1_probe, + .remove = rsnd_gen1_remove, + .path_init = rsnd_gen1_path_init, + .path_exit = rsnd_gen1_path_exit, +}; + /* * Gen */ @@ -251,6 +257,14 @@ int rsnd_gen_probe(struct platform_device *pdev, return -ENOMEM; } + if (rsnd_is_gen1(priv)) + gen->ops = &rsnd_gen1_ops; + + if (!gen->ops) { + dev_err(dev, "unknown generation R-Car sound device\n"); + return -ENODEV; + } + priv->gen = gen; /* @@ -261,20 +275,13 @@ int rsnd_gen_probe(struct platform_device *pdev, for (i = 0; i < RSND_REG_MAX; i++) gen->reg_map[i].index = -1; - /* - * init each module - */ - if (rsnd_is_gen1(priv)) - return rsnd_gen1_probe(pdev, info, priv); - - dev_err(dev, "unknown generation R-Car sound device\n"); - - return -ENODEV; + return gen->ops->probe(pdev, info, priv); } void rsnd_gen_remove(struct platform_device *pdev, struct rsnd_priv *priv) { - if (rsnd_is_gen1(priv)) - rsnd_gen1_remove(pdev, priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + gen->ops->remove(pdev, priv); } -- cgit v0.10.2 From bcf25567ecec6cb0a8078cbf68969baed047fdf4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 17 Sep 2013 12:26:00 +0300 Subject: ASoC: davinci-evm: Move sysclk logic away from evm_hw_params The sysclk rate does not change runtime so it should be initialized at init time. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index fd7c45b..2f8161c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -27,6 +27,10 @@ #include "davinci-i2s.h" #include "davinci-mcasp.h" +struct snd_soc_card_drvdata_davinci { + unsigned sysclk; +}; + #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, @@ -35,27 +39,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *soc_card = codec->card; int ret = 0; - unsigned sysclk; - - /* ASP1 on DM355 EVM is clocked by an external oscillator */ - if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || - machine_is_davinci_dm365_evm()) - sysclk = 27000000; - - /* ASP0 in DM6446 EVM is clocked by U55, as configured by - * board-dm644x-evm.c using GPIOs from U18. There are six - * options; here we "know" we use a 48 KHz sample rate. - */ - else if (machine_is_davinci_evm()) - sysclk = 12288000; - - else if (machine_is_davinci_da830_evm() || - machine_is_davinci_da850_evm()) - sysclk = 24576000; - - else - return -EINVAL; + unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *) + snd_soc_card_get_drvdata(soc_card))->sysclk; /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); @@ -243,35 +231,65 @@ static struct snd_soc_dai_link da850_evm_dai = { }; /* davinci dm6446 evm audio machine driver */ +/* + * ASP0 in DM6446 EVM is clocked by U55, as configured by + * board-dm644x-evm.c using GPIOs from U18. There are six + * options; here we "know" we use a 48 KHz sample rate. + */ +static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = { + .sysclk = 12288000, +}; + static struct snd_soc_card dm6446_snd_soc_card_evm = { .name = "DaVinci DM6446 EVM", .owner = THIS_MODULE, .dai_link = &dm6446_evm_dai, .num_links = 1, + .drvdata = &dm6446_snd_soc_card_drvdata, }; /* davinci dm355 evm audio machine driver */ +/* ASP1 on DM355 EVM is clocked by an external oscillator */ +static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = { + .sysclk = 27000000, +}; + static struct snd_soc_card dm355_snd_soc_card_evm = { .name = "DaVinci DM355 EVM", .owner = THIS_MODULE, .dai_link = &dm355_evm_dai, .num_links = 1, + .drvdata = &dm355_snd_soc_card_drvdata, }; /* davinci dm365 evm audio machine driver */ +static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = { + .sysclk = 27000000, +}; + static struct snd_soc_card dm365_snd_soc_card_evm = { .name = "DaVinci DM365 EVM", .owner = THIS_MODULE, .dai_link = &dm365_evm_dai, .num_links = 1, + .drvdata = &dm365_snd_soc_card_drvdata, }; /* davinci dm6467 evm audio machine driver */ +static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = { + .sysclk = 27000000, +}; + static struct snd_soc_card dm6467_snd_soc_card_evm = { .name = "DaVinci DM6467 EVM", .owner = THIS_MODULE, .dai_link = dm6467_evm_dai, .num_links = ARRAY_SIZE(dm6467_evm_dai), + .drvdata = &dm6467_snd_soc_card_drvdata, +}; + +static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = { + .sysclk = 24576000, }; static struct snd_soc_card da830_snd_soc_card = { @@ -279,6 +297,11 @@ static struct snd_soc_card da830_snd_soc_card = { .owner = THIS_MODULE, .dai_link = &da830_evm_dai, .num_links = 1, + .drvdata = &da830_snd_soc_card_drvdata, +}; + +static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = { + .sysclk = 24576000, }; static struct snd_soc_card da850_snd_soc_card = { @@ -286,6 +309,7 @@ static struct snd_soc_card da850_snd_soc_card = { .owner = THIS_MODULE, .dai_link = &da850_evm_dai, .num_links = 1, + .drvdata = &da850_snd_soc_card_drvdata, }; static struct platform_device *evm_snd_device; -- cgit v0.10.2 From 5fb7680bd0035525eb1534001f7b7f2ca06a8ab7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 10:41:36 +0530 Subject: ASoC: SPEAr spdif_in: Use devm_snd_soc_register_component devm_snd_soc_register_component makes code simpler. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Mark Brown diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index 63acfeb..21a8c95 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -257,20 +257,12 @@ static int spdif_in_probe(struct platform_device *pdev) return ret; } - return snd_soc_register_component(&pdev->dev, &spdif_in_component, - &spdif_in_dai, 1); -} - -static int spdif_in_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - - return 0; + return devm_snd_soc_register_component(&pdev->dev, &spdif_in_component, + &spdif_in_dai, 1); } static struct platform_driver spdif_in_driver = { .probe = spdif_in_probe, - .remove = spdif_in_remove, .driver = { .name = "spdif-in", .owner = THIS_MODULE, -- cgit v0.10.2 From 77aea716872fd976cbb9706b4588cf1fb9d52826 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 10:41:37 +0530 Subject: ASoC: SPEAr spdif_out: Use devm_snd_soc_register_component devm_snd_soc_register_component makes code simpler. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Mark Brown diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index 2fdf68c..70fc4d6 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -307,18 +307,11 @@ static int spdif_out_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, host); - ret = snd_soc_register_component(&pdev->dev, &spdif_out_component, - &spdif_out_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &spdif_out_component, + &spdif_out_dai, 1); return ret; } -static int spdif_out_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - - return 0; -} - #ifdef CONFIG_PM static int spdif_out_suspend(struct device *dev) { @@ -357,7 +350,6 @@ static SIMPLE_DEV_PM_OPS(spdif_out_dev_pm_ops, spdif_out_suspend, \ static struct platform_driver spdif_out_driver = { .probe = spdif_out_probe, - .remove = spdif_out_remove, .driver = { .name = "spdif-out", .owner = THIS_MODULE, -- cgit v0.10.2 From be7c5926c22403b6f5895a10a73145925dd560a9 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 17 Sep 2013 12:26:06 +0300 Subject: ASoC: tlv320aic3x: Add regulators to DT bindings document Add regulator properties to tlv320aic3x DT bindings document. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 705a6b1..ba26477 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -24,10 +24,17 @@ Optional properties: 3 - MICBIAS output is connected to AVDD, If this node is not mentioned or if the value is incorrect, then MicBias is powered down. +- AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the + device as covered in Documentation/devicetree/bindings/regulator/regulator.txt Example: tlv320aic3x: tlv320aic3x@1b { compatible = "ti,tlv320aic3x"; reg = <0x1b>; + + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DRVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; }; -- cgit v0.10.2 From c9f3de41b93ae61da4cd10611e446a4b916245d2 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 17 Sep 2013 12:26:07 +0300 Subject: ASoC: tlv320aic3x: Add codec pins to DT bindings document Add list of codec pins to tlv320aic3x DT bindings document. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index ba26477..5e6040c 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -27,6 +27,25 @@ Optional properties: - AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the device as covered in Documentation/devicetree/bindings/regulator/regulator.txt +CODEC output pins: + * LLOUT + * RLOUT + * MONO_LOUT + * HPLOUT + * HPROUT + * HPLCOM + * HPRCOM + +CODEC input pins: + * MIC3L + * MIC3R + * LINE1L + * LINE2L + * LINE1R + * LINE2R + +The pins can be used in referring sound node's audio-routing property. + Example: tlv320aic3x: tlv320aic3x@1b { -- cgit v0.10.2 From 32fcb97b9f699f63742bcaadca6e0beede86e8e8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 19 Sep 2013 11:18:06 +0200 Subject: ASoC: rt5640: Omit ACPI match table only if !ACPI The ACPI_PTR() macro evaluates to NULL if ACPI is disabled and hence the ACPI match table won't be used, causing the compiler to complain. Avoid this by protecting the table using an #ifdef CONFIG_ACPI. Signed-off-by: Thierry Reding Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 0bfb960..641eeeb 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2082,11 +2082,13 @@ static const struct i2c_device_id rt5640_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); +#ifdef CONFIG_ACPI static struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); +#endif static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) { -- cgit v0.10.2 From 25db0dc88016ec67ec4e38164482a3d7b7429f75 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 19 Sep 2013 12:23:44 +0530 Subject: ASoC: SPEAr spdif_out: Remove redundant variable Return directly and remove the intermediate local variable. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Mark Brown diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index 70fc4d6..b6ef6f7 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -280,7 +280,6 @@ static int spdif_out_probe(struct platform_device *pdev) struct spdif_out_dev *host; struct spear_spdif_platform_data *pdata; struct resource *res; - int ret; host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) { @@ -307,9 +306,8 @@ static int spdif_out_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, host); - ret = devm_snd_soc_register_component(&pdev->dev, &spdif_out_component, - &spdif_out_dai, 1); - return ret; + return devm_snd_soc_register_component(&pdev->dev, &spdif_out_component, + &spdif_out_dai, 1); } #ifdef CONFIG_PM -- cgit v0.10.2 From 01984a47e21a7d36cea0d6c0933c8173391721fc Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 09:42:46 +0530 Subject: ASoC: imx-sgtl5000: Use devm_snd_soc_register_card devm_snd_soc_register_card makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 46c5b4f..78f86d8 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -159,7 +159,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); - ret = snd_soc_register_card(&data->card); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto fail; @@ -180,15 +180,6 @@ fail: return ret; } -static int imx_sgtl5000_remove(struct platform_device *pdev) -{ - struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); - - snd_soc_unregister_card(&data->card); - - return 0; -} - static const struct of_device_id imx_sgtl5000_dt_ids[] = { { .compatible = "fsl,imx-audio-sgtl5000", }, { /* sentinel */ } @@ -202,7 +193,6 @@ static struct platform_driver imx_sgtl5000_driver = { .of_match_table = imx_sgtl5000_dt_ids, }, .probe = imx_sgtl5000_probe, - .remove = imx_sgtl5000_remove, }; module_platform_driver(imx_sgtl5000_driver); -- cgit v0.10.2 From ff27d9b3d6dd26013537e4f8162627169ca92af4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 09:42:47 +0530 Subject: ASoC: imx-spdif: Use devm_snd_soc_register_card devm_snd_soc_register_card makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index 816013b..8499d52 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -87,7 +87,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) if (ret) goto error_dir; - ret = snd_soc_register_card(&data->card); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); goto error_dir; @@ -119,8 +119,6 @@ static int imx_spdif_audio_remove(struct platform_device *pdev) if (data->txdev) platform_device_unregister(data->txdev); - snd_soc_unregister_card(&data->card); - return 0; } -- cgit v0.10.2 From eafbae2919e24b6ed7078464b2c8b2313ac0252c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 09:42:48 +0530 Subject: ASoC: imx-wm8962: Use devm_snd_soc_register_card devm_snd_soc_register_card makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 722afe6..6c60666 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -266,7 +266,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) data->card.late_probe = imx_wm8962_late_probe; data->card.set_bias_level = imx_wm8962_set_bias_level; - ret = snd_soc_register_card(&data->card); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto clk_fail; @@ -296,7 +296,6 @@ static int imx_wm8962_remove(struct platform_device *pdev) if (!IS_ERR(data->codec_clk)) clk_disable_unprepare(data->codec_clk); - snd_soc_unregister_card(&data->card); return 0; } -- cgit v0.10.2 From 33c89c30afd7b6a309638d8d9b88481118d0a3ec Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 09:49:04 +0530 Subject: ASoC: mfld: Use devm_snd_soc_register_card devm_snd_soc_register_card makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index ee36384..d3d4c32 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -400,7 +400,7 @@ static int snd_mfld_mc_probe(struct platform_device *pdev) } /* register the soc card */ snd_soc_card_mfld.dev = &pdev->dev; - ret_val = snd_soc_register_card(&snd_soc_card_mfld); + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld); if (ret_val) { pr_debug("snd_soc_register_card failed %d\n", ret_val); return ret_val; @@ -410,20 +410,12 @@ static int snd_mfld_mc_probe(struct platform_device *pdev) return 0; } -static int snd_mfld_mc_remove(struct platform_device *pdev) -{ - pr_debug("snd_mfld_mc_remove called\n"); - snd_soc_unregister_card(&snd_soc_card_mfld); - return 0; -} - static struct platform_driver snd_mfld_mc_driver = { .driver = { .owner = THIS_MODULE, .name = "msic_audio", }, .probe = snd_mfld_mc_probe, - .remove = snd_mfld_mc_remove, }; module_platform_driver(snd_mfld_mc_driver); -- cgit v0.10.2 From 67a48b8181b0c981c59acf06f056e00184d3debd Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 09:53:59 +0530 Subject: ASoC: omap-twl4030: Use devm_snd_soc_register_card devm_snd_soc_register_card makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index 2a9324f..6a8d6b5 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -338,9 +338,9 @@ static int omap_twl4030_probe(struct platform_device *pdev) } snd_soc_card_set_drvdata(card, priv); - ret = snd_soc_register_card(card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", ret); return ret; } @@ -357,7 +357,6 @@ static int omap_twl4030_remove(struct platform_device *pdev) snd_soc_jack_free_gpios(&priv->hs_jack, ARRAY_SIZE(hs_jack_gpios), hs_jack_gpios); - snd_soc_unregister_card(card); return 0; } -- cgit v0.10.2 From 256218ae65d2e59ef5d257355791a62af7d31b3c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 10:13:49 +0530 Subject: ASoC: fsl_spdif: Use devm_snd_soc_register_component devm_snd_soc_register_component makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3920c3e..44378e6 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1172,23 +1172,16 @@ static int fsl_spdif_probe(struct platform_device *pdev) /* Register with ASoC */ dev_set_drvdata(&pdev->dev, spdif_priv); - ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component, - &spdif_priv->cpu_dai_drv, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component, + &spdif_priv->cpu_dai_drv, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); return ret; } ret = imx_pcm_dma_init(pdev); - if (ret) { + if (ret) dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); - goto error_component; - } - - return ret; - -error_component: - snd_soc_unregister_component(&pdev->dev); return ret; } @@ -1196,7 +1189,6 @@ error_component: static int fsl_spdif_remove(struct platform_device *pdev) { imx_pcm_dma_exit(pdev); - snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v0.10.2 From fcd70eb50e2d572a67839410aa30f6b545355980 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 10:20:09 +0530 Subject: ASoC: mxs-saif: Use devm_snd_soc_register_component devm_snd_soc_register_component makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index b56b8a0..14152f6 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -768,8 +768,8 @@ static int mxs_saif_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to init clocks\n"); } - ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component, - &mxs_saif_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component, + &mxs_saif_dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); return ret; @@ -778,21 +778,15 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = mxs_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto failed_pdev_alloc; + return ret; } return 0; - -failed_pdev_alloc: - snd_soc_unregister_component(&pdev->dev); - - return ret; } static int mxs_saif_remove(struct platform_device *pdev) { mxs_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v0.10.2 From 6c3cc302a48acdd3797d694ae4a2be82bb71a05a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 10:28:02 +0530 Subject: ASoC: omap-mcpdm: Use devm_snd_soc_register_component devm_snd_soc_register_component makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 90d2a7c..cd9ee16 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -490,14 +490,9 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dev = &pdev->dev; - return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component, - &omap_mcpdm_dai, 1); -} - -static int asoc_mcpdm_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, + &omap_mcpdm_component, + &omap_mcpdm_dai, 1); } static const struct of_device_id omap_mcpdm_of_match[] = { @@ -514,7 +509,6 @@ static struct platform_driver asoc_mcpdm_driver = { }, .probe = asoc_mcpdm_probe, - .remove = asoc_mcpdm_remove, }; module_platform_driver(asoc_mcpdm_driver); -- cgit v0.10.2 From 9ff50721e47ab0abb8b93159170f67262886ef0d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 17 Sep 2013 10:32:48 +0530 Subject: ASoC: mmp-sspa: Use devm_snd_soc_register_component devm_snd_soc_register_component makes code simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 41752a5..5bf5f1f 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -455,8 +455,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) priv->dai_fmt = (unsigned int) -1; platform_set_drvdata(pdev, priv); - return snd_soc_register_component(&pdev->dev, &mmp_sspa_component, - &mmp_sspa_dai, 1); + return devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component, + &mmp_sspa_dai, 1); } static int asoc_mmp_sspa_remove(struct platform_device *pdev) @@ -466,7 +466,6 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev) clk_disable(priv->audio_clk); clk_put(priv->audio_clk); clk_put(priv->sysclk); - snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v0.10.2 From fa129ebeba6db2b4bcea45efe87a71d68181c04c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 19 Sep 2013 18:20:26 +0100 Subject: ASoC: 88pm60x: Don't use control data for i2c In preparation for using the regmap directly in the CODEC driver replace references to the I2C client using control_data with references to the driver private data. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 8af0434..3925cf3 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1166,6 +1166,7 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, static int pm860x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec); int data; switch (level) { @@ -1179,17 +1180,17 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec, if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { /* Enable Audio PLL & Audio section */ data = AUDIO_PLL | AUDIO_SECTION_ON; - pm860x_reg_write(codec->control_data, REG_MISC2, data); + pm860x_reg_write(pm860x->i2c, REG_MISC2, data); udelay(300); data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; - pm860x_reg_write(codec->control_data, REG_MISC2, data); + pm860x_reg_write(pm860x->i2c, REG_MISC2, data); } break; case SND_SOC_BIAS_OFF: data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; - pm860x_set_bits(codec->control_data, REG_MISC2, data, 0); + pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0); break; } codec->dapm.bias_level = level; @@ -1319,17 +1320,17 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec, pm860x->det.lo_shrt = lo_shrt; if (det & SND_JACK_HEADPHONE) - pm860x_set_bits(codec->control_data, REG_HS_DET, + pm860x_set_bits(pm860x->i2c, REG_HS_DET, EN_HS_DET, EN_HS_DET); /* headset short detect */ if (hs_shrt) { data = CLR_SHORT_HS2 | CLR_SHORT_HS1; - pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); + pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); } /* Lineout short detect */ if (lo_shrt) { data = CLR_SHORT_LO2 | CLR_SHORT_LO1; - pm860x_set_bits(codec->control_data, REG_SHORTS, data, data); + pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); } /* sync status */ @@ -1347,7 +1348,7 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec, pm860x->det.mic_det = det; if (det & SND_JACK_MICROPHONE) - pm860x_set_bits(codec->control_data, REG_MIC_DET, + pm860x_set_bits(pm860x->i2c, REG_MIC_DET, MICDET_MASK, MICDET_MASK); /* sync status */ @@ -1377,7 +1378,7 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE, + ret = pm860x_bulk_read(pm860x->i2c, REG_CACHE_BASE, REG_CACHE_SIZE, codec->reg_cache); if (ret < 0) { dev_err(codec->dev, "Failed to fill register cache: %d\n", -- cgit v0.10.2 From f9ded3b2e761256301ebb8d90e87eb1b5443e3ea Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 19 Sep 2013 19:00:46 +0100 Subject: ASoC: 88pm860x: Use regmap for I/O As part of a move to remove the duplication of regmap functionality in ASoC convert the 88pm860x driver to use the regmap from the MFD. This means that we no longer cache the registers so performance will be slightly reduced on I/O operations. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 3925cf3..4633e51 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,7 @@ struct pm860x_priv { unsigned int filter; struct snd_soc_codec *codec; struct i2c_client *i2c; + struct regmap *regmap; struct pm860x_chip *chip; struct pm860x_det det; @@ -269,48 +271,6 @@ static struct st_gain st_table[] = { { -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0}, }; -static int pm860x_volatile(unsigned int reg) -{ - BUG_ON(reg >= REG_CACHE_SIZE); - - switch (reg) { - case PM860X_AUDIO_SUPPLIES_2: - return 1; - } - - return 0; -} - -static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - unsigned char *cache = codec->reg_cache; - - BUG_ON(reg >= REG_CACHE_SIZE); - - if (pm860x_volatile(reg)) - return cache[reg]; - - reg += REG_CACHE_BASE; - - return pm860x_reg_read(codec->control_data, reg); -} - -static int pm860x_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - unsigned char *cache = codec->reg_cache; - - BUG_ON(reg >= REG_CACHE_SIZE); - - if (!pm860x_volatile(reg)) - cache[reg] = (unsigned char)value; - - reg += REG_CACHE_BASE; - - return pm860x_reg_write(codec->control_data, reg, value); -} - static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1364,7 +1324,7 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x->codec = codec; - codec->control_data = pm860x->i2c; + codec->control_data = pm860x->regmap; for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, @@ -1378,14 +1338,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = pm860x_bulk_read(pm860x->i2c, REG_CACHE_BASE, - REG_CACHE_SIZE, codec->reg_cache); - if (ret < 0) { - dev_err(codec->dev, "Failed to fill register cache: %d\n", - ret); - goto out; - } - return 0; out: @@ -1408,10 +1360,6 @@ static int pm860x_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_pm860x = { .probe = pm860x_probe, .remove = pm860x_remove, - .read = pm860x_read_reg_cache, - .write = pm860x_write_reg_cache, - .reg_cache_size = REG_CACHE_SIZE, - .reg_word_size = sizeof(u8), .set_bias_level = pm860x_set_bias_level, .controls = pm860x_snd_controls, @@ -1437,6 +1385,8 @@ static int pm860x_codec_probe(struct platform_device *pdev) pm860x->chip = chip; pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap + : chip->regmap_companion; platform_set_drvdata(pdev, pm860x); for (i = 0; i < 4; i++) { diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h index 3364ba4..f7282f4 100644 --- a/sound/soc/codecs/88pm860x-codec.h +++ b/sound/soc/codecs/88pm860x-codec.h @@ -12,67 +12,66 @@ #ifndef __88PM860X_H #define __88PM860X_H -/* The offset of these registers are 0xb0 */ -#define PM860X_PCM_IFACE_1 0x00 -#define PM860X_PCM_IFACE_2 0x01 -#define PM860X_PCM_IFACE_3 0x02 -#define PM860X_PCM_RATE 0x03 -#define PM860X_EC_PATH 0x04 -#define PM860X_SIDETONE_L_GAIN 0x05 -#define PM860X_SIDETONE_R_GAIN 0x06 -#define PM860X_SIDETONE_SHIFT 0x07 -#define PM860X_ADC_OFFSET_1 0x08 -#define PM860X_ADC_OFFSET_2 0x09 -#define PM860X_DMIC_DELAY 0x0a +#define PM860X_PCM_IFACE_1 0xb0 +#define PM860X_PCM_IFACE_2 0xb1 +#define PM860X_PCM_IFACE_3 0xb2 +#define PM860X_PCM_RATE 0xb3 +#define PM860X_EC_PATH 0xb4 +#define PM860X_SIDETONE_L_GAIN 0xb5 +#define PM860X_SIDETONE_R_GAIN 0xb6 +#define PM860X_SIDETONE_SHIFT 0xb7 +#define PM860X_ADC_OFFSET_1 0xb8 +#define PM860X_ADC_OFFSET_2 0xb9 +#define PM860X_DMIC_DELAY 0xba -#define PM860X_I2S_IFACE_1 0x0b -#define PM860X_I2S_IFACE_2 0x0c -#define PM860X_I2S_IFACE_3 0x0d -#define PM860X_I2S_IFACE_4 0x0e -#define PM860X_EQUALIZER_N0_1 0x0f -#define PM860X_EQUALIZER_N0_2 0x10 -#define PM860X_EQUALIZER_N1_1 0x11 -#define PM860X_EQUALIZER_N1_2 0x12 -#define PM860X_EQUALIZER_D1_1 0x13 -#define PM860X_EQUALIZER_D1_2 0x14 -#define PM860X_LOFI_GAIN_LEFT 0x15 -#define PM860X_LOFI_GAIN_RIGHT 0x16 -#define PM860X_HIFIL_GAIN_LEFT 0x17 -#define PM860X_HIFIL_GAIN_RIGHT 0x18 -#define PM860X_HIFIR_GAIN_LEFT 0x19 -#define PM860X_HIFIR_GAIN_RIGHT 0x1a -#define PM860X_DAC_OFFSET 0x1b -#define PM860X_OFFSET_LEFT_1 0x1c -#define PM860X_OFFSET_LEFT_2 0x1d -#define PM860X_OFFSET_RIGHT_1 0x1e -#define PM860X_OFFSET_RIGHT_2 0x1f -#define PM860X_ADC_ANA_1 0x20 -#define PM860X_ADC_ANA_2 0x21 -#define PM860X_ADC_ANA_3 0x22 -#define PM860X_ADC_ANA_4 0x23 -#define PM860X_ANA_TO_ANA 0x24 -#define PM860X_HS1_CTRL 0x25 -#define PM860X_HS2_CTRL 0x26 -#define PM860X_LO1_CTRL 0x27 -#define PM860X_LO2_CTRL 0x28 -#define PM860X_EAR_CTRL_1 0x29 -#define PM860X_EAR_CTRL_2 0x2a -#define PM860X_AUDIO_SUPPLIES_1 0x2b -#define PM860X_AUDIO_SUPPLIES_2 0x2c -#define PM860X_ADC_EN_1 0x2d -#define PM860X_ADC_EN_2 0x2e -#define PM860X_DAC_EN_1 0x2f -#define PM860X_DAC_EN_2 0x31 -#define PM860X_AUDIO_CAL_1 0x32 -#define PM860X_AUDIO_CAL_2 0x33 -#define PM860X_AUDIO_CAL_3 0x34 -#define PM860X_AUDIO_CAL_4 0x35 -#define PM860X_AUDIO_CAL_5 0x36 -#define PM860X_ANA_INPUT_SEL_1 0x37 -#define PM860X_ANA_INPUT_SEL_2 0x38 +#define PM860X_I2S_IFACE_1 0xbb +#define PM860X_I2S_IFACE_2 0xbc +#define PM860X_I2S_IFACE_3 0xbd +#define PM860X_I2S_IFACE_4 0xbe +#define PM860X_EQUALIZER_N0_1 0xbf +#define PM860X_EQUALIZER_N0_2 0xc0 +#define PM860X_EQUALIZER_N1_1 0xc1 +#define PM860X_EQUALIZER_N1_2 0xc2 +#define PM860X_EQUALIZER_D1_1 0xc3 +#define PM860X_EQUALIZER_D1_2 0xc4 +#define PM860X_LOFI_GAIN_LEFT 0xc5 +#define PM860X_LOFI_GAIN_RIGHT 0xc6 +#define PM860X_HIFIL_GAIN_LEFT 0xc7 +#define PM860X_HIFIL_GAIN_RIGHT 0xc8 +#define PM860X_HIFIR_GAIN_LEFT 0xc9 +#define PM860X_HIFIR_GAIN_RIGHT 0xca +#define PM860X_DAC_OFFSET 0xcb +#define PM860X_OFFSET_LEFT_1 0xcc +#define PM860X_OFFSET_LEFT_2 0xcd +#define PM860X_OFFSET_RIGHT_1 0xce +#define PM860X_OFFSET_RIGHT_2 0xcf +#define PM860X_ADC_ANA_1 0xd0 +#define PM860X_ADC_ANA_2 0xd1 +#define PM860X_ADC_ANA_3 0xd2 +#define PM860X_ADC_ANA_4 0xd3 +#define PM860X_ANA_TO_ANA 0xd4 +#define PM860X_HS1_CTRL 0xd5 +#define PM860X_HS2_CTRL 0xd6 +#define PM860X_LO1_CTRL 0xd7 +#define PM860X_LO2_CTRL 0xd8 +#define PM860X_EAR_CTRL_1 0xd9 +#define PM860X_EAR_CTRL_2 0xda +#define PM860X_AUDIO_SUPPLIES_1 0xdb +#define PM860X_AUDIO_SUPPLIES_2 0xdc +#define PM860X_ADC_EN_1 0xdd +#define PM860X_ADC_EN_2 0xde +#define PM860X_DAC_EN_1 0xdf +#define PM860X_DAC_EN_2 0xe1 +#define PM860X_AUDIO_CAL_1 0xe2 +#define PM860X_AUDIO_CAL_2 0xe3 +#define PM860X_AUDIO_CAL_3 0xe4 +#define PM860X_AUDIO_CAL_4 0xe5 +#define PM860X_AUDIO_CAL_5 0xe6 +#define PM860X_ANA_INPUT_SEL_1 0xe7 +#define PM860X_ANA_INPUT_SEL_2 0xe8 -#define PM860X_PCM_IFACE_4 0x39 -#define PM860X_I2S_IFACE_5 0x3a +#define PM860X_PCM_IFACE_4 0xe9 +#define PM860X_I2S_IFACE_5 0xea #define PM860X_SHORTS 0x3b #define PM860X_PLL_ADJ_1 0x3c -- cgit v0.10.2 From 38bfd48b87c44f6958f75bfcd5ae5a53bd3ca07b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 19 Sep 2013 19:17:14 +0100 Subject: ASoC: ab8500: Downgrade noisy log message Signed-off-by: Mark Brown Acked-by: Lee Jones diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index b8ba0ad..7cea5a8 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2601,7 +2601,7 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) static int ab8500_codec_driver_remove(struct platform_device *pdev) { - dev_info(&pdev->dev, "%s Enter.\n", __func__); + dev_dbg(&pdev->dev, "%s Enter.\n", __func__); snd_soc_unregister_codec(&pdev->dev); -- cgit v0.10.2 From 51f20e4cd83e804fb4fd940873763f29616f12a8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 19 Sep 2013 19:25:18 +0100 Subject: ASoC: ab8500: Use ASoC I/O functions In preparation for moving away from implementing the ASoC level register I/O functionality change direct calls to the ab8500 implementation of that to use snd_soc_write() Signed-off-by: Mark Brown Acked-by: Lee Jones diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 7cea5a8..c2b6636 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2527,12 +2527,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) } /* Override HW-defaults */ - ab8500_codec_write_reg(codec, - AB8500_ANACONF5, - BIT(AB8500_ANACONF5_HSAUTOEN)); - ab8500_codec_write_reg(codec, - AB8500_SHORTCIRCONF, - BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); + snd_soc_write(codec, AB8500_ANACONF5, + BIT(AB8500_ANACONF5_HSAUTOEN)); + snd_soc_write(codec, AB8500_SHORTCIRCONF, + BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); /* Add filter controls */ status = snd_soc_add_codec_controls(codec, ab8500_filter_controls, -- cgit v0.10.2 From ff795d614bfa62a3c6fc0bcb75cb8842e5a87892 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 20 Sep 2013 10:38:16 +0100 Subject: ASoC: ab8500: Convert register I/O to regmap As part of a general push to eliminate the duplicated register I/O support in ASoC convert ab8500 to use regmap. Signed-off-by: Mark Brown Acked-by: Lee Jones diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index c2b6636..d5a0fc4 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -126,6 +126,8 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { + struct regmap *regmap; + /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; @@ -166,49 +168,35 @@ static inline const char *amic_type_str(enum amic_type type) */ /* Read a register from the audio-bank of AB8500 */ -static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, - unsigned int reg) +static int ab8500_codec_read_reg(void *context, unsigned int reg, + unsigned int *value) { + struct device *dev = context; int status; - unsigned int value = 0; u8 value8; - status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, - reg, &value8); - if (status < 0) { - dev_err(codec->dev, - "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - } else { - dev_dbg(codec->dev, - "%s: Read 0x%02x from register 0x%02x:0x%02x\n", - __func__, value8, (u8)AB8500_AUDIO, (u8)reg); - value = (unsigned int)value8; - } + status = abx500_get_register_interruptible(dev, AB8500_AUDIO, + reg, &value8); + *value = (unsigned int)value8; - return value; + return status; } /* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static int ab8500_codec_write_reg(void *context, unsigned int reg, + unsigned int value) { - int status; + struct device *dev = context; - status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, - reg, value); - if (status < 0) - dev_err(codec->dev, - "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - else - dev_dbg(codec->dev, - "%s: Wrote 0x%02x into register %02x:%02x\n", - __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); - - return status; + return abx500_set_register_interruptible(dev, AB8500_AUDIO, + reg, value); } +static const struct regmap_config ab8500_codec_regmap = { + .reg_read = ab8500_codec_read_reg, + .reg_write = ab8500_codec_write_reg, +}; + /* * Controls - DAPM */ @@ -2483,6 +2471,8 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) /* Setup AB8500 according to board-settings */ pdata = dev_get_platdata(dev->parent); + codec->control_data = drvdata->regmap; + if (np) { if (!pdata) pdata = devm_kzalloc(dev, @@ -2560,9 +2550,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, - .read = ab8500_codec_read_reg, - .write = ab8500_codec_write_reg, - .reg_word_size = sizeof(u8), .controls = ab8500_ctrls, .num_controls = ARRAY_SIZE(ab8500_ctrls), .dapm_widgets = ab8500_dapm_widgets, @@ -2585,6 +2572,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); + drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, + &ab8500_codec_regmap); + if (IS_ERR(drvdata->regmap)) { + status = PTR_ERR(drvdata->regmap); + dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", + __func__, status); + return status; + } + dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, ab8500_codec_dai, -- cgit v0.10.2 From 84aac6c79bfdcfbcd8541c814b365c3001cdf5e6 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 21 Sep 2013 12:00:36 +0200 Subject: ASoC: kirkwood: fix loss of external clock at probe time At probe time, when the clock driver is not yet initialized, the external clock of the kirkwood sound device will not be usable. This patch fixes this problem defering the device probe. Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 0f3d73d..3e59af9 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -496,7 +496,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) return err; priv->extclk = devm_clk_get(&pdev->dev, "extclk"); - if (!IS_ERR(priv->extclk)) { + if (IS_ERR(priv->extclk)) { + if (PTR_ERR(priv->extclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } else { if (priv->extclk == priv->clk) { devm_clk_put(&pdev->dev, priv->extclk); priv->extclk = ERR_PTR(-EINVAL); -- cgit v0.10.2 From da5feefeda496f003a2e909762e72843cb9837a6 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 20 Sep 2013 18:19:05 +0100 Subject: ASoC: Docs: Update codec documentation Update the codec class driver documentation and bring it up to date with the current code base. This includes API changes, regmap and multi component. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt index bce23a4..db5f9c9 100644 --- a/Documentation/sound/alsa/soc/codec.txt +++ b/Documentation/sound/alsa/soc/codec.txt @@ -1,22 +1,23 @@ -ASoC Codec Driver -================= +ASoC Codec Class Driver +======================= -The codec driver is generic and hardware independent code that configures the -codec to provide audio capture and playback. It should contain no code that is -specific to the target platform or machine. All platform and machine specific -code should be added to the platform and machine drivers respectively. +The codec class driver is generic and hardware independent code that configures +the codec, FM, MODEM, BT or external DSP to provide audio capture and playback. +It should contain no code that is specific to the target platform or machine. +All platform and machine specific code should be added to the platform and +machine drivers respectively. -Each codec driver *must* provide the following features:- +Each codec class driver *must* provide the following features:- 1) Codec DAI and PCM configuration - 2) Codec control IO - using I2C, 3 Wire(SPI) or both APIs + 2) Codec control IO - using RegMap API 3) Mixers and audio controls 4) Codec audio operations + 5) DAPM description. + 6) DAPM event handler. Optionally, codec drivers can also provide:- - 5) DAPM description. - 6) DAPM event handler. 7) DAC Digital mute control. Its probably best to use this guide in conjunction with the existing codec @@ -64,26 +65,9 @@ struct snd_soc_dai_driver wm8731_dai = { 2 - Codec control IO -------------------- The codec can usually be controlled via an I2C or SPI style interface -(AC97 combines control with data in the DAI). The codec drivers provide -functions to read and write the codec registers along with supplying a -register cache:- - - /* IO control data and register cache */ - void *control_data; /* codec control (i2c/3wire) data */ - void *reg_cache; - -Codec read/write should do any data formatting and call the hardware -read write below to perform the IO. These functions are called by the -core and ALSA when performing DAPM or changing the mixer:- - - unsigned int (*read)(struct snd_soc_codec *, unsigned int); - int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); - -Codec hardware IO functions - usually points to either the I2C, SPI or AC97 -read/write:- - - hw_write_t hw_write; - hw_read_t hw_read; +(AC97 combines control with data in the DAI). The codec driver should use the +Regmap API for all codec IO. Please see include/linux/regmap.h and existing +codec drivers for example regmap usage. 3 - Mixers and audio controls @@ -127,7 +111,7 @@ Defines a stereo enumerated control 4 - Codec Audio Operations -------------------------- -The codec driver also supports the following ALSA operations:- +The codec driver also supports the following ALSA PCM operations:- /* SoC audio ops */ struct snd_soc_ops { -- cgit v0.10.2 From 3eb012834b28585a37fe0684182828efc1ab0512 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 20 Sep 2013 18:19:06 +0100 Subject: ASoC: Docs: Platform update Update the platform class driver documentation and bring it up to date with the current code base. This includes multi component and DSP. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt index d57efad..3a08a2c 100644 --- a/Documentation/sound/alsa/soc/platform.txt +++ b/Documentation/sound/alsa/soc/platform.txt @@ -1,9 +1,9 @@ ASoC Platform Driver ==================== -An ASoC platform driver can be divided into audio DMA and SoC DAI configuration -and control. The platform drivers only target the SoC CPU and must have no board -specific code. +An ASoC platform driver class can be divided into audio DMA drivers, SoC DAI +drivers and DSP drivers. The platform drivers only target the SoC CPU and must +have no board specific code. Audio DMA ========= @@ -64,3 +64,16 @@ Each SoC DAI driver must provide the following features:- 5) Suspend and resume (optional) Please see codec.txt for a description of items 1 - 4. + + +SoC DSP Drivers +=============== + +Each SoC DSP driver usually supplies the following features :- + + 1) DAPM graph + 2) Mixer controls + 3) DMA IO to/from DSP buffers (if applicable) + 4) Definition of DSP front end (FE) PCM devices. + +Please see DPCM.txt for a description of item 4. -- cgit v0.10.2 From 630a1b3b4f0bb40c84c1fde4fec0d97de62ccdac Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 20 Sep 2013 18:19:07 +0100 Subject: ASoC: Docs: update DAPM Update the DAPM documentation and bring it up to date with the current code base. This includes API changes and new widgets. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt index 05bf5a0..7dfd88c 100644 --- a/Documentation/sound/alsa/soc/dapm.txt +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -21,7 +21,7 @@ level power systems. There are 4 power domains within DAPM - 1. Codec domain - VREF, VMID (core codec and audio power) + 1. Codec bias domain - VREF, VMID (core codec and audio power) Usually controlled at codec probe/remove and suspend/resume, although can be set at stream time if power is not needed for sidetone, etc. @@ -63,14 +63,22 @@ Audio DAPM widgets fall into a number of types:- o Line - Line Input/Output (and optional Jack) o Speaker - Speaker o Supply - Power or clock supply widget used by other widgets. + o Regulator - External regulator that supplies power to audio components. + o Clock - External clock that supplies clock to audio componnents. + o AIF IN - Audio Interface Input (with TDM slot mask). + o AIF OUT - Audio Interface Output (with TDM slot mask). + o Siggen - Signal Generator. + o DAI IN - Digital Audio Interface Input. + o DAI OUT - Digital Audio Interface Output. + o DAI Link - DAI Link between two DAI structures */ o Pre - Special PRE widget (exec before all others) o Post - Special POST widget (exec after all others) (Widgets are defined in include/sound/soc-dapm.h) -Widgets are usually added in the codec driver and the machine driver. There are -convenience macros defined in soc-dapm.h that can be used to quickly build a -list of widgets of the codecs and machines DAPM widgets. +Widgets can be added to the sound card by any of the component driver types. +There are convenience macros defined in soc-dapm.h that can be used to quickly +build a list of widgets of the codecs and machines DAPM widgets. Most widgets have a name, register, shift and invert. Some widgets have extra parameters for stream name and kcontrols. @@ -80,11 +88,13 @@ parameters for stream name and kcontrols. ------------------------- Stream Widgets relate to the stream power domain and only consist of ADCs -(analog to digital converters) and DACs (digital to analog converters). +(analog to digital converters), DACs (digital to analog converters), +AIF IN and AIF OUT. Stream widgets have the following format:- SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), +SND_SOC_DAPM_AIF_IN(name, stream, slot, reg, shift, invert) NOTE: the stream name must match the corresponding stream name in your codec snd_soc_codec_dai. @@ -94,6 +104,11 @@ e.g. stream widgets for HiFi playback and capture SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), +e.g. stream widgets for AIF + +SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + 2.2 Path Domain Widgets ----------------------- @@ -121,12 +136,14 @@ If you dont want the mixer elements prefixed with the name of the mixer widget, you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same as for SND_SOC_DAPM_MIXER. -2.3 Platform/Machine domain Widgets ------------------------------------ + +2.3 Machine domain Widgets +-------------------------- Machine widgets are different from codec widgets in that they don't have a codec register bit associated with them. A machine widget is assigned to each -machine audio component (non codec) that can be independently powered. e.g. +machine audio component (non codec or DSP) that can be independently +powered. e.g. o Speaker Amp o Microphone Bias @@ -146,12 +163,12 @@ static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), -2.4 Codec Domain ----------------- +2.4 Codec (BIAS) Domain +----------------------- -The codec power domain has no widgets and is handled by the codecs DAPM event -handler. This handler is called when the codec powerstate is changed wrt to any -stream event or by kernel PM events. +The codec bias power domain has no widgets and is handled by the codecs DAPM +event handler. This handler is called when the codec powerstate is changed wrt +to any stream event or by kernel PM events. 2.5 Virtual Widgets @@ -169,15 +186,16 @@ After all the widgets have been defined, they can then be added to the DAPM subsystem individually with a call to snd_soc_dapm_new_control(). -3. Codec Widget Interconnections -================================ +3. Codec/DSP Widget Interconnections +==================================== -Widgets are connected to each other within the codec and machine by audio paths -(called interconnections). Each interconnection must be defined in order to -create a map of all audio paths between widgets. +Widgets are connected to each other within the codec, platform and machine by +audio paths (called interconnections). Each interconnection must be defined in +order to create a map of all audio paths between widgets. -This is easiest with a diagram of the codec (and schematic of the machine audio -system), as it requires joining widgets together via their audio signal paths. +This is easiest with a diagram of the codec or DSP (and schematic of the machine +audio system), as it requires joining widgets together via their audio signal +paths. e.g., from the WM8731 output mixer (wm8731.c) @@ -247,16 +265,9 @@ machine and includes the codec. e.g. o Mic Jack o Codec Pins -When a codec pin is NC it can be marked as not used with a call to - -snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); - -The last argument is 0 for inactive and 1 for active. This way the pin and its -input widget will never be powered up and consume power. - -This also applies to machine widgets. e.g. if a headphone is connected to a -jack then the jack can be marked active. If the headphone is removed, then -the headphone jack can be marked inactive. +Endpoints are added to the DAPM graph so that their usage can be determined in +order to save power. e.g. NC codecs pins will be switched OFF, unconnected +jacks can also be switched OFF. 5 DAPM Widget Events -- cgit v0.10.2 From b5c47df974ddae44d4a1ff935cdda30b0795bc00 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 20 Sep 2013 18:19:08 +0100 Subject: ASoC: Docs: Machine update Update the machine driver documentation and bring it up to date with the current code base. This includes multi component. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index d50c14d..74056db 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -1,8 +1,10 @@ ASoC Machine Driver =================== -The ASoC machine (or board) driver is the code that glues together the platform -and codec drivers. +The ASoC machine (or board) driver is the code that glues together all the +component drivers (e.g. codecs, platforms and DAIs). It also describes the +relationships between each componnent which include audio paths, GPIOs, +interrupts, clocking, jacks and voltage regulators. The machine driver can contain codec and platform specific code. It registers the audio subsystem with the kernel as a platform device and is represented by -- cgit v0.10.2 From 469b7bc4e6dbfdb173f0901f746e9277f6740ba7 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 20 Sep 2013 18:19:09 +0100 Subject: ASoC: Docs: Add documentation for Dynamic PCM Add documentation describing DPCM with examples of a DSP based smart phone. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/Documentation/sound/alsa/soc/DPCM.txt b/Documentation/sound/alsa/soc/DPCM.txt new file mode 100644 index 0000000..aa8546f --- /dev/null +++ b/Documentation/sound/alsa/soc/DPCM.txt @@ -0,0 +1,380 @@ +Dynamic PCM +=========== + +1. Description +============== + +Dynamic PCM allows an ALSA PCM device to digitally route its PCM audio to +various digital endpoints during the PCM stream runtime. e.g. PCM0 can route +digital audio to I2S DAI0, I2S DAI1 or PDM DAI2. This is useful for on SoC DSP +drivers that expose several ALSA PCMs and can route to multiple DAIs. + +The DPCM runtime routing is determined by the ALSA mixer settings in the same +way as the analog signal is routed in an ASoC codec driver. DPCM uses a DAPM +graph representing the DSP internal audio paths and uses the mixer settings to +determine the patch used by each ALSA PCM. + +DPCM re-uses all the existing component codec, platform and DAI drivers without +any modifications. + + +Phone Audio System with SoC based DSP +------------------------------------- + +Consider the following phone audio subsystem. This will be used in this +document for all examples :- + +| Front End PCMs | SoC DSP | Back End DAIs | Audio devices | + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +This diagram shows a simple smart phone audio subsystem. It supports Bluetooth, +FM digital radio, Speakers, Headset Jack, digital microphones and cellular +modem. This sound card exposes 4 DSP front end (FE) ALSA PCM devices and +supports 6 back end (BE) DAIs. Each FE PCM can digitally route audio data to any +of the BE DAIs. The FE PCM devices can also route audio to more than 1 BE DAI. + + + +Example - DPCM Switching playback from DAI0 to DAI1 +--------------------------------------------------- + +Audio is being played to the Headset. After a while the user removes the headset +and audio continues playing on the speakers. + +Playback on PCM0 to Headset would look like :- + + ************* +PCM0 <============> * * <====DAI0=====> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +The headset is removed from the jack by user so the speakers must now be used :- + + ************* +PCM0 <============> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <====DAI1=====> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +The audio driver processes this as follows :- + + 1) Machine driver receives Jack removal event. + + 2) Machine driver OR audio HAL disables the Headset path. + + 3) DPCM runs the PCM trigger(stop), hw_free(), shutdown() operations on DAI0 + for headset since the path is now disabled. + + 4) Machine driver or audio HAL enables the speaker path. + + 5) DPCM runs the PCM ops for startup(), hw_params(), prepapre() and + trigger(start) for DAI1 Speakers since the path is enabled. + +In this example, the machine driver or userspace audio HAL can alter the routing +and then DPCM will take care of managing the DAI PCM operations to either bring +the link up or down. Audio playback does not stop during this transition. + + + +DPCM machine driver +=================== + +The DPCM enabled ASoC machine driver is similar to normal machine drivers +except that we also have to :- + + 1) Define the FE and BE DAI links. + + 2) Define any FE/BE PCM operations. + + 3) Define widget graph connections. + + +1 FE and BE DAI links +--------------------- + +| Front End PCMs | SoC DSP | Back End DAIs | Audio devices | + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <----DAI2-----> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +For the example above we have to define 4 FE DAI links and 6 BE DAI links. The +FE DAI links are defined as follows :- + +static struct snd_soc_dai_link machine_dais[] = { + { + .name = "PCM0 System", + .stream_name = "System Playback", + .cpu_dai_name = "System Pin", + .platform_name = "dsp-audio", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + }, + .....< other FE and BE DAI links here > +}; + +This FE DAI link is pretty similar to a regular DAI link except that we also +set the DAI link to a DPCM FE with the "dynamic = 1". The supported FE stream +directions should also be set with the "dpcm_playback" and "dpcm_capture" +flags. There is also an option to specify the ordering of the trigger call for +each FE. This allows the ASoC core to trigger the DSP before or after the other +components (as some DSPs have strong requirements for the ordering DAI/DSP +start and stop sequences). + +The FE DAI above sets the codec and code DAIs to dummy devices since the BE is +dynamic and will change depending on runtime config. + +The BE DAIs are configured as follows :- + +static struct snd_soc_dai_link machine_dais[] = { + .....< FE DAI links here > + { + .name = "Codec Headset", + .cpu_dai_name = "ssp-dai.0", + .platform_name = "snd-soc-dummy", + .no_pcm = 1, + .codec_name = "rt5640.0-001c", + .codec_dai_name = "rt5640-aif1", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = hswult_ssp0_fixup, + .ops = &haswell_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + .....< other BE DAI links here > +}; + +This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets +the "no_pcm" flag to mark it has a BE and sets flags for supported stream +directions using "dpcm_playback" and "dpcm_capture" above. + +The BE has also flags set for ignoreing suspend and PM down time. This allows +the BE to work in a hostless mode where the host CPU is not transferring data +like a BT phone call :- + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * +PCM2 <------------> * * <====DAI2=====> MODEM + * * +PCM3 <------------> * * <====DAI3=====> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +This allows the host CPU to sleep whilst the DSP, MODEM DAI and the BT DAI are +still in operation. + +A BE DAI link can also set the codec to a dummy device if the code is a device +that is managed externally. + +Likewise a BE DAI can also set a dummy cpu DAI if the CPU DAI is managed by the +DSP firmware. + + +2 FE/BE PCM operations +---------------------- + +The BE above also exports some PCM operations and a "fixup" callback. The fixup +callback is used by the machine driver to (re)configure the DAI based upon the +FE hw params. i.e. the DSP may perform SRC or ASRC from the FE to BE. + +e.g. DSP converts all FE hw params to run at fixed rate of 48k, 16bit, stereo for +DAI0. This means all FE hw_params have to be fixed in the machine driver for +DAI0 so that the DAI is running at desired configuration regardless of the FE +configuration. + +static int dai0_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* The DSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set DAI0 to 16 bit */ + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + SNDRV_PCM_FORMAT_S16_LE); + return 0; +} + +The other PCM operation are the same as for regular DAI links. Use as necessary. + + +3 Widget graph connections +-------------------------- + +The BE DAI links will normally be connected to the graph at initialisation time +by the ASoC DAPM core. However, if the BE codec or BE DAI is a dummy then this +has to be set explicitly in the driver :- + +/* BE for codec Headset - DAI0 is dummy and managed by DSP FW */ +{"DAI0 CODEC IN", NULL, "AIF1 Capture"}, +{"AIF1 Playback", NULL, "DAI0 CODEC OUT"}, + + +Writing a DPCM DSP driver +========================= + +The DPCM DSP driver looks much like a standard platform class ASoC driver +combined with elements from a codec class driver. A DSP platform driver must +implement :- + + 1) Front End PCM DAIs - i.e. struct snd_soc_dai_driver. + + 2) DAPM graph showing DSP audio routing from FE DAIs to BEs. + + 3) DAPM widgets from DSP graph. + + 4) Mixers for gains, routing, etc. + + 5) DMA configuration. + + 6) BE AIF widgets. + +Items 6 is important for routing the audio outside of the DSP. AIF need to be +defined for each BE and each stream direction. e.g for BE DAI0 above we would +have :- + +SND_SOC_DAPM_AIF_IN("DAI0 RX", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("DAI0 TX", NULL, 0, SND_SOC_NOPM, 0, 0), + +The BE AIF are used to connect the DSP graph to the graphs for the other +component drivers (e.g. codec graph). + + +Hostless PCM streams +==================== + +A hostless PCM stream is a stream that is not routed through the host CPU. An +example of this would be a phone call from handset to modem. + + + ************* +PCM0 <------------> * * <----DAI0-----> Codec Headset + * * +PCM1 <------------> * * <====DAI1=====> Codec Speakers/Mic + * DSP * +PCM2 <------------> * * <====DAI2=====> MODEM + * * +PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +In this case the PCM data is routed via the DSP. The host CPU in this use case +is only used for control and can sleep during the runtime of the stream. + +The host can control the hostless link either by :- + + 1) Configuring the link as a CODEC <-> CODEC style link. In this case the link + is enabled or disabled by the state of the DAPM graph. This usually means + there is a mixer control that can be used to connect or disconnect the path + between both DAIs. + + 2) Hostless FE. This FE has a virtual connection to the BE DAI links on the DAPM + graph. Control is then carried out by the FE as regualar PCM operations. + This method gives more control over the DAI links, but requires much more + userspace code to control the link. Its recommended to use CODEC<->CODEC + unless your HW needs more fine grained sequencing of the PCM ops. + + +CODEC <-> CODEC link +-------------------- + +This DAI link is enabled when DAPM detects a valid path within the DAPM graph. +The machine driver sets some additional parameters to the DAI link i.e. + +static const struct snd_soc_pcm_stream dai_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 2, + .channels_max = 2, +}; + +static struct snd_soc_dai_link dais[] = { + < ... more DAI links above ... > + { + .name = "MODEM", + .stream_name = "MODEM", + .cpu_dai_name = "dai2", + .codec_dai_name = "modem-aif1", + .codec_name = "modem", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &dai_params, + } + < ... more DAI links here ... > + +These parameters are used to configure the DAI hw_params() when DAPM detects a +valid path and then calls the PCM operations to start the link. DAPM will also +call the appropriate PCM operations to disable the DAI when the path is no +longer valid. + + +Hostless FE +----------- + +The DAI link(s) are enabled by a FE that does not read or write any PCM data. +This means creating a new FE that is connected with a virtual path to both +DAI links. The DAI links will be started when the FE PCM is started and stopped +when the FE PCM is stopped. Note that the FE PCM cannot read or write data in +this configuration. + + -- cgit v0.10.2 From 64d2307c3b7daa03dbc0c3a6b514709dd7b6eaee Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 23 Sep 2013 01:08:25 -0300 Subject: ASoC: fsl: fsl_ssi: Fix simultaneous capture and playback When doing simultaneous capture and playback on a mx6 board we get the following error: $ arecord -f cd | aplay -f cd imx-sgtl5000 sound.13: set sample size in capture stream first fsl-ssi-dai 2028000.ssi: ASoC: can't open interface 2028000.ssi: -11 ALSA lib pcm_dmix.c:1018:(snd_pcm_dmix_ open) unable to open slave aplay: main:660: audio open error: Device or resource busy Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo The 'arecord -f cd | aplay -f cd' always trigger cause the 'if (!first_runtime->sample_bits)' block to be true which returns an error. Adjust the logic inside fsl_ssi_startup(), so that we do not always hit the error when playing 'arecord | aplay' line for the first time. Reported-by: Chris Clepper Suggested-by: Nicolin Chen Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 6ac8730..cdbb641 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -469,19 +469,12 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, * parameters, then the second stream may be * constrained to the wrong sample rate or size. */ - if (!first_runtime->sample_bits) { - dev_err(substream->pcm->card->dev, - "set sample size in %s stream first\n", - substream->stream == - SNDRV_PCM_STREAM_PLAYBACK - ? "capture" : "playback"); - return -EAGAIN; - } - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + if (first_runtime->sample_bits) { + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, first_runtime->sample_bits, first_runtime->sample_bits); + } } ssi_private->second_stream = substream; -- cgit v0.10.2 From d3be689e6a07c00123786659b4429b07cf4272ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 24 Sep 2013 01:25:08 -0700 Subject: ASoC: rcar: remove unnecessary mach/clock.h ${LINUX}/sound/soc/sh driver can be compiled from SuperH and ARM. but, ${LINUX}/sound/soc/sh/rcar driver included SH-ARM specific header. This patch removes it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index d80deb7..2935bbf 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -8,7 +8,6 @@ * for more details. */ #include -#include #include "rsnd.h" #define CLKA 0 -- cgit v0.10.2 From 356d86e24850cdc353602b90be73e627f86707c7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 17:22:17 +0100 Subject: ASoC: max98088: Fix indentation Tested-by: Dylan Reid Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 566a367..391f669 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -38,20 +38,20 @@ struct max98088_cdata { }; struct max98088_priv { - enum max98088_type devtype; - struct max98088_pdata *pdata; - unsigned int sysclk; - struct max98088_cdata dai[2]; - int eq_textcnt; - const char **eq_texts; - struct soc_enum eq_enum; - u8 ina_state; - u8 inb_state; - unsigned int ex_mode; - unsigned int digmic; - unsigned int mic1pre; - unsigned int mic2pre; - unsigned int extmic_mode; + enum max98088_type devtype; + struct max98088_pdata *pdata; + unsigned int sysclk; + struct max98088_cdata dai[2]; + int eq_textcnt; + const char **eq_texts; + struct soc_enum eq_enum; + u8 ina_state; + u8 inb_state; + unsigned int ex_mode; + unsigned int digmic; + unsigned int mic1pre; + unsigned int mic2pre; + unsigned int extmic_mode; }; static const u8 max98088_reg[M98088_REG_CNT] = { @@ -2066,15 +2066,15 @@ static int max98088_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_max98088 = { - .probe = max98088_probe, - .remove = max98088_remove, - .suspend = max98088_suspend, - .resume = max98088_resume, - .set_bias_level = max98088_set_bias_level, - .reg_cache_size = ARRAY_SIZE(max98088_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = max98088_reg, - .volatile_register = max98088_volatile_register, + .probe = max98088_probe, + .remove = max98088_remove, + .suspend = max98088_suspend, + .resume = max98088_resume, + .set_bias_level = max98088_set_bias_level, + .reg_cache_size = ARRAY_SIZE(max98088_reg), + .reg_word_size = sizeof(u8), + .reg_cache_default = max98088_reg, + .volatile_register = max98088_volatile_register, .dapm_widgets = max98088_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets), .dapm_routes = max98088_audio_map, -- cgit v0.10.2 From ad65adf4a3039ecd93d4712ac6524dbd9e0e848a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 17:54:02 +0100 Subject: ASoC: max98088: Use table based control init Tested-by: Dylan Reid Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 391f669..8896d5e 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2048,9 +2048,6 @@ static int max98088_probe(struct snd_soc_codec *codec) max98088_handle_pdata(codec); - snd_soc_add_codec_controls(codec, max98088_snd_controls, - ARRAY_SIZE(max98088_snd_controls)); - err_access: return ret; } @@ -2071,6 +2068,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = { .suspend = max98088_suspend, .resume = max98088_resume, .set_bias_level = max98088_set_bias_level, + .controls = max98088_snd_controls, + .num_controls = ARRAY_SIZE(max98088_snd_controls), .reg_cache_size = ARRAY_SIZE(max98088_reg), .reg_word_size = sizeof(u8), .reg_cache_default = max98088_reg, -- cgit v0.10.2 From 4127d5d59f8135e3c187b8daa2540691761938ce Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 17:56:17 +0100 Subject: ASoC: max98088: Convert to direct regmap API usage This saves code and moves us towards removing the redundant register I/O implementation in ASoC. Tested-by: Dylan Reid Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 8896d5e..31912d5 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ struct max98088_cdata { }; struct max98088_priv { + struct regmap *regmap; enum max98088_type devtype; struct max98088_pdata *pdata; unsigned int sysclk; @@ -54,278 +56,206 @@ struct max98088_priv { unsigned int extmic_mode; }; -static const u8 max98088_reg[M98088_REG_CNT] = { - 0x00, /* 00 IRQ status */ - 0x00, /* 01 MIC status */ - 0x00, /* 02 jack status */ - 0x00, /* 03 battery voltage */ - 0x00, /* 04 */ - 0x00, /* 05 */ - 0x00, /* 06 */ - 0x00, /* 07 */ - 0x00, /* 08 */ - 0x00, /* 09 */ - 0x00, /* 0A */ - 0x00, /* 0B */ - 0x00, /* 0C */ - 0x00, /* 0D */ - 0x00, /* 0E */ - 0x00, /* 0F interrupt enable */ - - 0x00, /* 10 master clock */ - 0x00, /* 11 DAI1 clock mode */ - 0x00, /* 12 DAI1 clock control */ - 0x00, /* 13 DAI1 clock control */ - 0x00, /* 14 DAI1 format */ - 0x00, /* 15 DAI1 clock */ - 0x00, /* 16 DAI1 config */ - 0x00, /* 17 DAI1 TDM */ - 0x00, /* 18 DAI1 filters */ - 0x00, /* 19 DAI2 clock mode */ - 0x00, /* 1A DAI2 clock control */ - 0x00, /* 1B DAI2 clock control */ - 0x00, /* 1C DAI2 format */ - 0x00, /* 1D DAI2 clock */ - 0x00, /* 1E DAI2 config */ - 0x00, /* 1F DAI2 TDM */ - - 0x00, /* 20 DAI2 filters */ - 0x00, /* 21 data config */ - 0x00, /* 22 DAC mixer */ - 0x00, /* 23 left ADC mixer */ - 0x00, /* 24 right ADC mixer */ - 0x00, /* 25 left HP mixer */ - 0x00, /* 26 right HP mixer */ - 0x00, /* 27 HP control */ - 0x00, /* 28 left REC mixer */ - 0x00, /* 29 right REC mixer */ - 0x00, /* 2A REC control */ - 0x00, /* 2B left SPK mixer */ - 0x00, /* 2C right SPK mixer */ - 0x00, /* 2D SPK control */ - 0x00, /* 2E sidetone */ - 0x00, /* 2F DAI1 playback level */ - - 0x00, /* 30 DAI1 playback level */ - 0x00, /* 31 DAI2 playback level */ - 0x00, /* 32 DAI2 playbakc level */ - 0x00, /* 33 left ADC level */ - 0x00, /* 34 right ADC level */ - 0x00, /* 35 MIC1 level */ - 0x00, /* 36 MIC2 level */ - 0x00, /* 37 INA level */ - 0x00, /* 38 INB level */ - 0x00, /* 39 left HP volume */ - 0x00, /* 3A right HP volume */ - 0x00, /* 3B left REC volume */ - 0x00, /* 3C right REC volume */ - 0x00, /* 3D left SPK volume */ - 0x00, /* 3E right SPK volume */ - 0x00, /* 3F MIC config */ - - 0x00, /* 40 MIC threshold */ - 0x00, /* 41 excursion limiter filter */ - 0x00, /* 42 excursion limiter threshold */ - 0x00, /* 43 ALC */ - 0x00, /* 44 power limiter threshold */ - 0x00, /* 45 power limiter config */ - 0x00, /* 46 distortion limiter config */ - 0x00, /* 47 audio input */ - 0x00, /* 48 microphone */ - 0x00, /* 49 level control */ - 0x00, /* 4A bypass switches */ - 0x00, /* 4B jack detect */ - 0x00, /* 4C input enable */ - 0x00, /* 4D output enable */ - 0xF0, /* 4E bias control */ - 0x00, /* 4F DAC power */ - - 0x0F, /* 50 DAC power */ - 0x00, /* 51 system */ - 0x00, /* 52 DAI1 EQ1 */ - 0x00, /* 53 DAI1 EQ1 */ - 0x00, /* 54 DAI1 EQ1 */ - 0x00, /* 55 DAI1 EQ1 */ - 0x00, /* 56 DAI1 EQ1 */ - 0x00, /* 57 DAI1 EQ1 */ - 0x00, /* 58 DAI1 EQ1 */ - 0x00, /* 59 DAI1 EQ1 */ - 0x00, /* 5A DAI1 EQ1 */ - 0x00, /* 5B DAI1 EQ1 */ - 0x00, /* 5C DAI1 EQ2 */ - 0x00, /* 5D DAI1 EQ2 */ - 0x00, /* 5E DAI1 EQ2 */ - 0x00, /* 5F DAI1 EQ2 */ - - 0x00, /* 60 DAI1 EQ2 */ - 0x00, /* 61 DAI1 EQ2 */ - 0x00, /* 62 DAI1 EQ2 */ - 0x00, /* 63 DAI1 EQ2 */ - 0x00, /* 64 DAI1 EQ2 */ - 0x00, /* 65 DAI1 EQ2 */ - 0x00, /* 66 DAI1 EQ3 */ - 0x00, /* 67 DAI1 EQ3 */ - 0x00, /* 68 DAI1 EQ3 */ - 0x00, /* 69 DAI1 EQ3 */ - 0x00, /* 6A DAI1 EQ3 */ - 0x00, /* 6B DAI1 EQ3 */ - 0x00, /* 6C DAI1 EQ3 */ - 0x00, /* 6D DAI1 EQ3 */ - 0x00, /* 6E DAI1 EQ3 */ - 0x00, /* 6F DAI1 EQ3 */ - - 0x00, /* 70 DAI1 EQ4 */ - 0x00, /* 71 DAI1 EQ4 */ - 0x00, /* 72 DAI1 EQ4 */ - 0x00, /* 73 DAI1 EQ4 */ - 0x00, /* 74 DAI1 EQ4 */ - 0x00, /* 75 DAI1 EQ4 */ - 0x00, /* 76 DAI1 EQ4 */ - 0x00, /* 77 DAI1 EQ4 */ - 0x00, /* 78 DAI1 EQ4 */ - 0x00, /* 79 DAI1 EQ4 */ - 0x00, /* 7A DAI1 EQ5 */ - 0x00, /* 7B DAI1 EQ5 */ - 0x00, /* 7C DAI1 EQ5 */ - 0x00, /* 7D DAI1 EQ5 */ - 0x00, /* 7E DAI1 EQ5 */ - 0x00, /* 7F DAI1 EQ5 */ - - 0x00, /* 80 DAI1 EQ5 */ - 0x00, /* 81 DAI1 EQ5 */ - 0x00, /* 82 DAI1 EQ5 */ - 0x00, /* 83 DAI1 EQ5 */ - 0x00, /* 84 DAI2 EQ1 */ - 0x00, /* 85 DAI2 EQ1 */ - 0x00, /* 86 DAI2 EQ1 */ - 0x00, /* 87 DAI2 EQ1 */ - 0x00, /* 88 DAI2 EQ1 */ - 0x00, /* 89 DAI2 EQ1 */ - 0x00, /* 8A DAI2 EQ1 */ - 0x00, /* 8B DAI2 EQ1 */ - 0x00, /* 8C DAI2 EQ1 */ - 0x00, /* 8D DAI2 EQ1 */ - 0x00, /* 8E DAI2 EQ2 */ - 0x00, /* 8F DAI2 EQ2 */ - - 0x00, /* 90 DAI2 EQ2 */ - 0x00, /* 91 DAI2 EQ2 */ - 0x00, /* 92 DAI2 EQ2 */ - 0x00, /* 93 DAI2 EQ2 */ - 0x00, /* 94 DAI2 EQ2 */ - 0x00, /* 95 DAI2 EQ2 */ - 0x00, /* 96 DAI2 EQ2 */ - 0x00, /* 97 DAI2 EQ2 */ - 0x00, /* 98 DAI2 EQ3 */ - 0x00, /* 99 DAI2 EQ3 */ - 0x00, /* 9A DAI2 EQ3 */ - 0x00, /* 9B DAI2 EQ3 */ - 0x00, /* 9C DAI2 EQ3 */ - 0x00, /* 9D DAI2 EQ3 */ - 0x00, /* 9E DAI2 EQ3 */ - 0x00, /* 9F DAI2 EQ3 */ - - 0x00, /* A0 DAI2 EQ3 */ - 0x00, /* A1 DAI2 EQ3 */ - 0x00, /* A2 DAI2 EQ4 */ - 0x00, /* A3 DAI2 EQ4 */ - 0x00, /* A4 DAI2 EQ4 */ - 0x00, /* A5 DAI2 EQ4 */ - 0x00, /* A6 DAI2 EQ4 */ - 0x00, /* A7 DAI2 EQ4 */ - 0x00, /* A8 DAI2 EQ4 */ - 0x00, /* A9 DAI2 EQ4 */ - 0x00, /* AA DAI2 EQ4 */ - 0x00, /* AB DAI2 EQ4 */ - 0x00, /* AC DAI2 EQ5 */ - 0x00, /* AD DAI2 EQ5 */ - 0x00, /* AE DAI2 EQ5 */ - 0x00, /* AF DAI2 EQ5 */ - - 0x00, /* B0 DAI2 EQ5 */ - 0x00, /* B1 DAI2 EQ5 */ - 0x00, /* B2 DAI2 EQ5 */ - 0x00, /* B3 DAI2 EQ5 */ - 0x00, /* B4 DAI2 EQ5 */ - 0x00, /* B5 DAI2 EQ5 */ - 0x00, /* B6 DAI1 biquad */ - 0x00, /* B7 DAI1 biquad */ - 0x00, /* B8 DAI1 biquad */ - 0x00, /* B9 DAI1 biquad */ - 0x00, /* BA DAI1 biquad */ - 0x00, /* BB DAI1 biquad */ - 0x00, /* BC DAI1 biquad */ - 0x00, /* BD DAI1 biquad */ - 0x00, /* BE DAI1 biquad */ - 0x00, /* BF DAI1 biquad */ - - 0x00, /* C0 DAI2 biquad */ - 0x00, /* C1 DAI2 biquad */ - 0x00, /* C2 DAI2 biquad */ - 0x00, /* C3 DAI2 biquad */ - 0x00, /* C4 DAI2 biquad */ - 0x00, /* C5 DAI2 biquad */ - 0x00, /* C6 DAI2 biquad */ - 0x00, /* C7 DAI2 biquad */ - 0x00, /* C8 DAI2 biquad */ - 0x00, /* C9 DAI2 biquad */ - 0x00, /* CA */ - 0x00, /* CB */ - 0x00, /* CC */ - 0x00, /* CD */ - 0x00, /* CE */ - 0x00, /* CF */ - - 0x00, /* D0 */ - 0x00, /* D1 */ - 0x00, /* D2 */ - 0x00, /* D3 */ - 0x00, /* D4 */ - 0x00, /* D5 */ - 0x00, /* D6 */ - 0x00, /* D7 */ - 0x00, /* D8 */ - 0x00, /* D9 */ - 0x00, /* DA */ - 0x70, /* DB */ - 0x00, /* DC */ - 0x00, /* DD */ - 0x00, /* DE */ - 0x00, /* DF */ - - 0x00, /* E0 */ - 0x00, /* E1 */ - 0x00, /* E2 */ - 0x00, /* E3 */ - 0x00, /* E4 */ - 0x00, /* E5 */ - 0x00, /* E6 */ - 0x00, /* E7 */ - 0x00, /* E8 */ - 0x00, /* E9 */ - 0x00, /* EA */ - 0x00, /* EB */ - 0x00, /* EC */ - 0x00, /* ED */ - 0x00, /* EE */ - 0x00, /* EF */ - - 0x00, /* F0 */ - 0x00, /* F1 */ - 0x00, /* F2 */ - 0x00, /* F3 */ - 0x00, /* F4 */ - 0x00, /* F5 */ - 0x00, /* F6 */ - 0x00, /* F7 */ - 0x00, /* F8 */ - 0x00, /* F9 */ - 0x00, /* FA */ - 0x00, /* FB */ - 0x00, /* FC */ - 0x00, /* FD */ - 0x00, /* FE */ - 0x00, /* FF */ +static const struct reg_default max98088_reg[] = { + { 0xf, 0x00 }, /* 0F interrupt enable */ + + { 0x10, 0x00 }, /* 10 master clock */ + { 0x11, 0x00 }, /* 11 DAI1 clock mode */ + { 0x12, 0x00 }, /* 12 DAI1 clock control */ + { 0x13, 0x00 }, /* 13 DAI1 clock control */ + { 0x14, 0x00 }, /* 14 DAI1 format */ + { 0x15, 0x00 }, /* 15 DAI1 clock */ + { 0x16, 0x00 }, /* 16 DAI1 config */ + { 0x17, 0x00 }, /* 17 DAI1 TDM */ + { 0x18, 0x00 }, /* 18 DAI1 filters */ + { 0x19, 0x00 }, /* 19 DAI2 clock mode */ + { 0x1a, 0x00 }, /* 1A DAI2 clock control */ + { 0x1b, 0x00 }, /* 1B DAI2 clock control */ + { 0x1c, 0x00 }, /* 1C DAI2 format */ + { 0x1d, 0x00 }, /* 1D DAI2 clock */ + { 0x1e, 0x00 }, /* 1E DAI2 config */ + { 0x1f, 0x00 }, /* 1F DAI2 TDM */ + + { 0x20, 0x00 }, /* 20 DAI2 filters */ + { 0x21, 0x00 }, /* 21 data config */ + { 0x22, 0x00 }, /* 22 DAC mixer */ + { 0x23, 0x00 }, /* 23 left ADC mixer */ + { 0x24, 0x00 }, /* 24 right ADC mixer */ + { 0x25, 0x00 }, /* 25 left HP mixer */ + { 0x26, 0x00 }, /* 26 right HP mixer */ + { 0x27, 0x00 }, /* 27 HP control */ + { 0x28, 0x00 }, /* 28 left REC mixer */ + { 0x29, 0x00 }, /* 29 right REC mixer */ + { 0x2a, 0x00 }, /* 2A REC control */ + { 0x2b, 0x00 }, /* 2B left SPK mixer */ + { 0x2c, 0x00 }, /* 2C right SPK mixer */ + { 0x2d, 0x00 }, /* 2D SPK control */ + { 0x2e, 0x00 }, /* 2E sidetone */ + { 0x2f, 0x00 }, /* 2F DAI1 playback level */ + + { 0x30, 0x00 }, /* 30 DAI1 playback level */ + { 0x31, 0x00 }, /* 31 DAI2 playback level */ + { 0x32, 0x00 }, /* 32 DAI2 playbakc level */ + { 0x33, 0x00 }, /* 33 left ADC level */ + { 0x34, 0x00 }, /* 34 right ADC level */ + { 0x35, 0x00 }, /* 35 MIC1 level */ + { 0x36, 0x00 }, /* 36 MIC2 level */ + { 0x37, 0x00 }, /* 37 INA level */ + { 0x38, 0x00 }, /* 38 INB level */ + { 0x39, 0x00 }, /* 39 left HP volume */ + { 0x3a, 0x00 }, /* 3A right HP volume */ + { 0x3b, 0x00 }, /* 3B left REC volume */ + { 0x3c, 0x00 }, /* 3C right REC volume */ + { 0x3d, 0x00 }, /* 3D left SPK volume */ + { 0x3e, 0x00 }, /* 3E right SPK volume */ + { 0x3f, 0x00 }, /* 3F MIC config */ + + { 0x40, 0x00 }, /* 40 MIC threshold */ + { 0x41, 0x00 }, /* 41 excursion limiter filter */ + { 0x42, 0x00 }, /* 42 excursion limiter threshold */ + { 0x43, 0x00 }, /* 43 ALC */ + { 0x44, 0x00 }, /* 44 power limiter threshold */ + { 0x45, 0x00 }, /* 45 power limiter config */ + { 0x46, 0x00 }, /* 46 distortion limiter config */ + { 0x47, 0x00 }, /* 47 audio input */ + { 0x48, 0x00 }, /* 48 microphone */ + { 0x49, 0x00 }, /* 49 level control */ + { 0x4a, 0x00 }, /* 4A bypass switches */ + { 0x4b, 0x00 }, /* 4B jack detect */ + { 0x4c, 0x00 }, /* 4C input enable */ + { 0x4d, 0x00 }, /* 4D output enable */ + { 0x4e, 0xF0 }, /* 4E bias control */ + { 0x4f, 0x00 }, /* 4F DAC power */ + + { 0x50, 0x0F }, /* 50 DAC power */ + { 0x51, 0x00 }, /* 51 system */ + { 0x52, 0x00 }, /* 52 DAI1 EQ1 */ + { 0x53, 0x00 }, /* 53 DAI1 EQ1 */ + { 0x54, 0x00 }, /* 54 DAI1 EQ1 */ + { 0x55, 0x00 }, /* 55 DAI1 EQ1 */ + { 0x56, 0x00 }, /* 56 DAI1 EQ1 */ + { 0x57, 0x00 }, /* 57 DAI1 EQ1 */ + { 0x58, 0x00 }, /* 58 DAI1 EQ1 */ + { 0x59, 0x00 }, /* 59 DAI1 EQ1 */ + { 0x5a, 0x00 }, /* 5A DAI1 EQ1 */ + { 0x5b, 0x00 }, /* 5B DAI1 EQ1 */ + { 0x5c, 0x00 }, /* 5C DAI1 EQ2 */ + { 0x5d, 0x00 }, /* 5D DAI1 EQ2 */ + { 0x5e, 0x00 }, /* 5E DAI1 EQ2 */ + { 0x5f, 0x00 }, /* 5F DAI1 EQ2 */ + + { 0x60, 0x00 }, /* 60 DAI1 EQ2 */ + { 0x61, 0x00 }, /* 61 DAI1 EQ2 */ + { 0x62, 0x00 }, /* 62 DAI1 EQ2 */ + { 0x63, 0x00 }, /* 63 DAI1 EQ2 */ + { 0x64, 0x00 }, /* 64 DAI1 EQ2 */ + { 0x65, 0x00 }, /* 65 DAI1 EQ2 */ + { 0x66, 0x00 }, /* 66 DAI1 EQ3 */ + { 0x67, 0x00 }, /* 67 DAI1 EQ3 */ + { 0x68, 0x00 }, /* 68 DAI1 EQ3 */ + { 0x69, 0x00 }, /* 69 DAI1 EQ3 */ + { 0x6a, 0x00 }, /* 6A DAI1 EQ3 */ + { 0x6b, 0x00 }, /* 6B DAI1 EQ3 */ + { 0x6c, 0x00 }, /* 6C DAI1 EQ3 */ + { 0x6d, 0x00 }, /* 6D DAI1 EQ3 */ + { 0x6e, 0x00 }, /* 6E DAI1 EQ3 */ + { 0x6f, 0x00 }, /* 6F DAI1 EQ3 */ + + { 0x70, 0x00 }, /* 70 DAI1 EQ4 */ + { 0x71, 0x00 }, /* 71 DAI1 EQ4 */ + { 0x72, 0x00 }, /* 72 DAI1 EQ4 */ + { 0x73, 0x00 }, /* 73 DAI1 EQ4 */ + { 0x74, 0x00 }, /* 74 DAI1 EQ4 */ + { 0x75, 0x00 }, /* 75 DAI1 EQ4 */ + { 0x76, 0x00 }, /* 76 DAI1 EQ4 */ + { 0x77, 0x00 }, /* 77 DAI1 EQ4 */ + { 0x78, 0x00 }, /* 78 DAI1 EQ4 */ + { 0x79, 0x00 }, /* 79 DAI1 EQ4 */ + { 0x7a, 0x00 }, /* 7A DAI1 EQ5 */ + { 0x7b, 0x00 }, /* 7B DAI1 EQ5 */ + { 0x7c, 0x00 }, /* 7C DAI1 EQ5 */ + { 0x7d, 0x00 }, /* 7D DAI1 EQ5 */ + { 0x7e, 0x00 }, /* 7E DAI1 EQ5 */ + { 0x7f, 0x00 }, /* 7F DAI1 EQ5 */ + + { 0x80, 0x00 }, /* 80 DAI1 EQ5 */ + { 0x81, 0x00 }, /* 81 DAI1 EQ5 */ + { 0x82, 0x00 }, /* 82 DAI1 EQ5 */ + { 0x83, 0x00 }, /* 83 DAI1 EQ5 */ + { 0x84, 0x00 }, /* 84 DAI2 EQ1 */ + { 0x85, 0x00 }, /* 85 DAI2 EQ1 */ + { 0x86, 0x00 }, /* 86 DAI2 EQ1 */ + { 0x87, 0x00 }, /* 87 DAI2 EQ1 */ + { 0x88, 0x00 }, /* 88 DAI2 EQ1 */ + { 0x89, 0x00 }, /* 89 DAI2 EQ1 */ + { 0x8a, 0x00 }, /* 8A DAI2 EQ1 */ + { 0x8b, 0x00 }, /* 8B DAI2 EQ1 */ + { 0x8c, 0x00 }, /* 8C DAI2 EQ1 */ + { 0x8d, 0x00 }, /* 8D DAI2 EQ1 */ + { 0x8e, 0x00 }, /* 8E DAI2 EQ2 */ + { 0x8f, 0x00 }, /* 8F DAI2 EQ2 */ + + { 0x90, 0x00 }, /* 90 DAI2 EQ2 */ + { 0x91, 0x00 }, /* 91 DAI2 EQ2 */ + { 0x92, 0x00 }, /* 92 DAI2 EQ2 */ + { 0x93, 0x00 }, /* 93 DAI2 EQ2 */ + { 0x94, 0x00 }, /* 94 DAI2 EQ2 */ + { 0x95, 0x00 }, /* 95 DAI2 EQ2 */ + { 0x96, 0x00 }, /* 96 DAI2 EQ2 */ + { 0x97, 0x00 }, /* 97 DAI2 EQ2 */ + { 0x98, 0x00 }, /* 98 DAI2 EQ3 */ + { 0x99, 0x00 }, /* 99 DAI2 EQ3 */ + { 0x9a, 0x00 }, /* 9A DAI2 EQ3 */ + { 0x9b, 0x00 }, /* 9B DAI2 EQ3 */ + { 0x9c, 0x00 }, /* 9C DAI2 EQ3 */ + { 0x9d, 0x00 }, /* 9D DAI2 EQ3 */ + { 0x9e, 0x00 }, /* 9E DAI2 EQ3 */ + { 0x9f, 0x00 }, /* 9F DAI2 EQ3 */ + + { 0xa0, 0x00 }, /* A0 DAI2 EQ3 */ + { 0xa1, 0x00 }, /* A1 DAI2 EQ3 */ + { 0xa2, 0x00 }, /* A2 DAI2 EQ4 */ + { 0xa3, 0x00 }, /* A3 DAI2 EQ4 */ + { 0xa4, 0x00 }, /* A4 DAI2 EQ4 */ + { 0xa5, 0x00 }, /* A5 DAI2 EQ4 */ + { 0xa6, 0x00 }, /* A6 DAI2 EQ4 */ + { 0xa7, 0x00 }, /* A7 DAI2 EQ4 */ + { 0xa8, 0x00 }, /* A8 DAI2 EQ4 */ + { 0xa9, 0x00 }, /* A9 DAI2 EQ4 */ + { 0xaa, 0x00 }, /* AA DAI2 EQ4 */ + { 0xab, 0x00 }, /* AB DAI2 EQ4 */ + { 0xac, 0x00 }, /* AC DAI2 EQ5 */ + { 0xad, 0x00 }, /* AD DAI2 EQ5 */ + { 0xae, 0x00 }, /* AE DAI2 EQ5 */ + { 0xaf, 0x00 }, /* AF DAI2 EQ5 */ + + { 0xb0, 0x00 }, /* B0 DAI2 EQ5 */ + { 0xb1, 0x00 }, /* B1 DAI2 EQ5 */ + { 0xb2, 0x00 }, /* B2 DAI2 EQ5 */ + { 0xb3, 0x00 }, /* B3 DAI2 EQ5 */ + { 0xb4, 0x00 }, /* B4 DAI2 EQ5 */ + { 0xb5, 0x00 }, /* B5 DAI2 EQ5 */ + { 0xb6, 0x00 }, /* B6 DAI1 biquad */ + { 0xb7, 0x00 }, /* B7 DAI1 biquad */ + { 0xb8 ,0x00 }, /* B8 DAI1 biquad */ + { 0xb9, 0x00 }, /* B9 DAI1 biquad */ + { 0xba, 0x00 }, /* BA DAI1 biquad */ + { 0xbb, 0x00 }, /* BB DAI1 biquad */ + { 0xbc, 0x00 }, /* BC DAI1 biquad */ + { 0xbd, 0x00 }, /* BD DAI1 biquad */ + { 0xbe, 0x00 }, /* BE DAI1 biquad */ + { 0xbf, 0x00 }, /* BF DAI1 biquad */ + + { 0xc0, 0x00 }, /* C0 DAI2 biquad */ + { 0xc1, 0x00 }, /* C1 DAI2 biquad */ + { 0xc2, 0x00 }, /* C2 DAI2 biquad */ + { 0xc3, 0x00 }, /* C3 DAI2 biquad */ + { 0xc4, 0x00 }, /* C4 DAI2 biquad */ + { 0xc5, 0x00 }, /* C5 DAI2 biquad */ + { 0xc6, 0x00 }, /* C6 DAI2 biquad */ + { 0xc7, 0x00 }, /* C7 DAI2 biquad */ + { 0xc8, 0x00 }, /* C8 DAI2 biquad */ + { 0xc9, 0x00 }, /* C9 DAI2 biquad */ }; static struct { @@ -606,11 +536,27 @@ static struct { { 0xFF, 0x00, 1 }, /* FF */ }; -static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool max98088_readable_register(struct device *dev, unsigned int reg) +{ + return max98088_access[reg].readable; +} + +static bool max98088_volatile_register(struct device *dev, unsigned int reg) { return max98088_access[reg].vol; } +static const struct regmap_config max98088_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = max98088_readable_register, + .volatile_reg = max98088_volatile_register, + + .reg_defaults = max98088_reg, + .num_reg_defaults = ARRAY_SIZE(max98088_reg), + .cache_type = REGCACHE_RBTREE, +}; /* * Load equalizer DSP coefficient configurations registers @@ -1610,58 +1556,34 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } -static void max98088_sync_cache(struct snd_soc_codec *codec) -{ - u8 *reg_cache = codec->reg_cache; - int i; - - if (!codec->cache_sync) - return; - - codec->cache_only = 0; - - /* write back cached values if they're writeable and - * different from the hardware default. - */ - for (i = 1; i < codec->driver->reg_cache_size; i++) { - if (!max98088_access[i].writable) - continue; - - if (reg_cache[i] == max98088_reg[i]) - continue; - - snd_soc_write(codec, i, reg_cache[i]); - } - - codec->cache_sync = 0; -} - static int max98088_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) - max98088_sync_cache(codec); - - snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, - M98088_MBEN, M98088_MBEN); - break; - - case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, - M98088_MBEN, 0); - codec->cache_sync = 1; - break; - } - codec->dapm.bias_level = level; - return 0; + struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + regcache_sync(max98088->regmap); + + snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, + M98088_MBEN, M98088_MBEN); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, + M98088_MBEN, 0); + regcache_mark_dirty(max98088->regmap); + break; + } + codec->dapm.bias_level = level; + return 0; } #define MAX98088_RATES SNDRV_PCM_RATE_8000_96000 @@ -1988,9 +1910,9 @@ static int max98088_probe(struct snd_soc_codec *codec) struct max98088_cdata *cdata; int ret = 0; - codec->cache_sync = 1; + regcache_mark_dirty(max98088->regmap); - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -2070,10 +1992,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = { .set_bias_level = max98088_set_bias_level, .controls = max98088_snd_controls, .num_controls = ARRAY_SIZE(max98088_snd_controls), - .reg_cache_size = ARRAY_SIZE(max98088_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = max98088_reg, - .volatile_register = max98088_volatile_register, .dapm_widgets = max98088_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets), .dapm_routes = max98088_audio_map, @@ -2081,7 +1999,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = { }; static int max98088_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct max98088_priv *max98088; int ret; @@ -2091,6 +2009,10 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (max98088 == NULL) return -ENOMEM; + max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); + if (IS_ERR(max98088->regmap)) + return PTR_ERR(max98088->regmap); + max98088->devtype = id->driver_data; i2c_set_clientdata(i2c, max98088); -- cgit v0.10.2 From 2245e3c31c15c2d2a26926c4b734f4d3a37ae252 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Sep 2013 11:50:10 +0100 Subject: ASoC: ab8500: Explicitly set I/O up We do some I/O in probe so we need to ensure the I/O operations are fully set up then. Reported-by: Olof Johansson Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index d5a0fc4..7f6ca11 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2468,6 +2468,8 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) dev_dbg(dev, "%s: Enter.\n", __func__); + snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); + /* Setup AB8500 according to board-settings */ pdata = dev_get_platdata(dev->parent); -- cgit v0.10.2 From d36126ac5674a83e1d426877709437b24f058f47 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 18:58:59 +0100 Subject: ASoC: max98095: Remove custom hw_write() implementation The registers that are being kept uncached are marked as volatile anyway so the call has no practical impact. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 41cdd16..65aba5e 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -612,23 +612,6 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) } /* - * Filter coefficients are in a separate register segment - * and they share the address space of the normal registers. - * The coefficient registers do not need or share the cache. - */ -static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - int ret; - - codec->cache_bypass = 1; - ret = snd_soc_write(codec, reg, value); - codec->cache_bypass = 0; - - return ret ? -EIO : 0; -} - -/* * Load equalizer DSP coefficient configurations registers */ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai, @@ -648,8 +631,8 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai, /* Step through the registers and coefs */ for (i = 0; i < M98095_COEFS_PER_BAND; i++) { - max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); - max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i])); + snd_soc_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); + snd_soc_write(codec, eq_reg++, M98095_BYTE0(coefs[i])); } } @@ -673,8 +656,8 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai, /* Step through the registers and coefs */ for (i = 0; i < M98095_COEFS_PER_BAND; i++) { - max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); - max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i])); + snd_soc_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); + snd_soc_write(codec, bq_reg++, M98095_BYTE0(coefs[i])); } } -- cgit v0.10.2 From c6b3283f6d8818177349eb7cc0549286a55140c7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 19:05:16 +0100 Subject: ASoC: max90895: Convert to table based control init Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 65aba5e..1a4585a 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1268,14 +1268,6 @@ static const struct snd_soc_dapm_route max98095_audio_map[] = { {"MIC2 Input", NULL, "MIC2"}, }; -static int max98095_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_add_codec_controls(codec, max98095_snd_controls, - ARRAY_SIZE(max98095_snd_controls)); - - return 0; -} - /* codec mclk clock divider coefficients */ static const struct { u32 rate; @@ -2430,8 +2422,6 @@ static int max98095_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN, M98095_SHDNRUN); - max98095_add_widgets(codec); - return 0; err_irq: @@ -2463,6 +2453,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = { .suspend = max98095_suspend, .resume = max98095_resume, .set_bias_level = max98095_set_bias_level, + .controls = max98095_snd_controls, + .num_controls = ARRAY_SIZE(max98095_snd_controls), .reg_cache_size = ARRAY_SIZE(max98095_reg_def), .reg_word_size = sizeof(u8), .reg_cache_default = max98095_reg_def, -- cgit v0.10.2 From 14acbbbbc649c4c6057f601396b8000cd616d9ad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 19:08:35 +0100 Subject: ASoC: max98095: Convert to direct regmap API usage Saves code and moves us towards being able to remove the duplicate ASoC level register I/O functionality. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 1a4585a..5c9f6b5 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -39,6 +39,7 @@ struct max98095_cdata { }; struct max98095_priv { + struct regmap *regmap; enum max98095_type devtype; struct max98095_pdata *pdata; unsigned int sysclk; @@ -56,263 +57,145 @@ struct max98095_priv { struct snd_soc_jack *mic_jack; }; -static const u8 max98095_reg_def[M98095_REG_CNT] = { - 0x00, /* 00 */ - 0x00, /* 01 */ - 0x00, /* 02 */ - 0x00, /* 03 */ - 0x00, /* 04 */ - 0x00, /* 05 */ - 0x00, /* 06 */ - 0x00, /* 07 */ - 0x00, /* 08 */ - 0x00, /* 09 */ - 0x00, /* 0A */ - 0x00, /* 0B */ - 0x00, /* 0C */ - 0x00, /* 0D */ - 0x00, /* 0E */ - 0x00, /* 0F */ - 0x00, /* 10 */ - 0x00, /* 11 */ - 0x00, /* 12 */ - 0x00, /* 13 */ - 0x00, /* 14 */ - 0x00, /* 15 */ - 0x00, /* 16 */ - 0x00, /* 17 */ - 0x00, /* 18 */ - 0x00, /* 19 */ - 0x00, /* 1A */ - 0x00, /* 1B */ - 0x00, /* 1C */ - 0x00, /* 1D */ - 0x00, /* 1E */ - 0x00, /* 1F */ - 0x00, /* 20 */ - 0x00, /* 21 */ - 0x00, /* 22 */ - 0x00, /* 23 */ - 0x00, /* 24 */ - 0x00, /* 25 */ - 0x00, /* 26 */ - 0x00, /* 27 */ - 0x00, /* 28 */ - 0x00, /* 29 */ - 0x00, /* 2A */ - 0x00, /* 2B */ - 0x00, /* 2C */ - 0x00, /* 2D */ - 0x00, /* 2E */ - 0x00, /* 2F */ - 0x00, /* 30 */ - 0x00, /* 31 */ - 0x00, /* 32 */ - 0x00, /* 33 */ - 0x00, /* 34 */ - 0x00, /* 35 */ - 0x00, /* 36 */ - 0x00, /* 37 */ - 0x00, /* 38 */ - 0x00, /* 39 */ - 0x00, /* 3A */ - 0x00, /* 3B */ - 0x00, /* 3C */ - 0x00, /* 3D */ - 0x00, /* 3E */ - 0x00, /* 3F */ - 0x00, /* 40 */ - 0x00, /* 41 */ - 0x00, /* 42 */ - 0x00, /* 43 */ - 0x00, /* 44 */ - 0x00, /* 45 */ - 0x00, /* 46 */ - 0x00, /* 47 */ - 0x00, /* 48 */ - 0x00, /* 49 */ - 0x00, /* 4A */ - 0x00, /* 4B */ - 0x00, /* 4C */ - 0x00, /* 4D */ - 0x00, /* 4E */ - 0x00, /* 4F */ - 0x00, /* 50 */ - 0x00, /* 51 */ - 0x00, /* 52 */ - 0x00, /* 53 */ - 0x00, /* 54 */ - 0x00, /* 55 */ - 0x00, /* 56 */ - 0x00, /* 57 */ - 0x00, /* 58 */ - 0x00, /* 59 */ - 0x00, /* 5A */ - 0x00, /* 5B */ - 0x00, /* 5C */ - 0x00, /* 5D */ - 0x00, /* 5E */ - 0x00, /* 5F */ - 0x00, /* 60 */ - 0x00, /* 61 */ - 0x00, /* 62 */ - 0x00, /* 63 */ - 0x00, /* 64 */ - 0x00, /* 65 */ - 0x00, /* 66 */ - 0x00, /* 67 */ - 0x00, /* 68 */ - 0x00, /* 69 */ - 0x00, /* 6A */ - 0x00, /* 6B */ - 0x00, /* 6C */ - 0x00, /* 6D */ - 0x00, /* 6E */ - 0x00, /* 6F */ - 0x00, /* 70 */ - 0x00, /* 71 */ - 0x00, /* 72 */ - 0x00, /* 73 */ - 0x00, /* 74 */ - 0x00, /* 75 */ - 0x00, /* 76 */ - 0x00, /* 77 */ - 0x00, /* 78 */ - 0x00, /* 79 */ - 0x00, /* 7A */ - 0x00, /* 7B */ - 0x00, /* 7C */ - 0x00, /* 7D */ - 0x00, /* 7E */ - 0x00, /* 7F */ - 0x00, /* 80 */ - 0x00, /* 81 */ - 0x00, /* 82 */ - 0x00, /* 83 */ - 0x00, /* 84 */ - 0x00, /* 85 */ - 0x00, /* 86 */ - 0x00, /* 87 */ - 0x00, /* 88 */ - 0x00, /* 89 */ - 0x00, /* 8A */ - 0x00, /* 8B */ - 0x00, /* 8C */ - 0x00, /* 8D */ - 0x00, /* 8E */ - 0x00, /* 8F */ - 0x00, /* 90 */ - 0x00, /* 91 */ - 0x30, /* 92 */ - 0xF0, /* 93 */ - 0x00, /* 94 */ - 0x00, /* 95 */ - 0x3F, /* 96 */ - 0x00, /* 97 */ - 0x00, /* 98 */ - 0x00, /* 99 */ - 0x00, /* 9A */ - 0x00, /* 9B */ - 0x00, /* 9C */ - 0x00, /* 9D */ - 0x00, /* 9E */ - 0x00, /* 9F */ - 0x00, /* A0 */ - 0x00, /* A1 */ - 0x00, /* A2 */ - 0x00, /* A3 */ - 0x00, /* A4 */ - 0x00, /* A5 */ - 0x00, /* A6 */ - 0x00, /* A7 */ - 0x00, /* A8 */ - 0x00, /* A9 */ - 0x00, /* AA */ - 0x00, /* AB */ - 0x00, /* AC */ - 0x00, /* AD */ - 0x00, /* AE */ - 0x00, /* AF */ - 0x00, /* B0 */ - 0x00, /* B1 */ - 0x00, /* B2 */ - 0x00, /* B3 */ - 0x00, /* B4 */ - 0x00, /* B5 */ - 0x00, /* B6 */ - 0x00, /* B7 */ - 0x00, /* B8 */ - 0x00, /* B9 */ - 0x00, /* BA */ - 0x00, /* BB */ - 0x00, /* BC */ - 0x00, /* BD */ - 0x00, /* BE */ - 0x00, /* BF */ - 0x00, /* C0 */ - 0x00, /* C1 */ - 0x00, /* C2 */ - 0x00, /* C3 */ - 0x00, /* C4 */ - 0x00, /* C5 */ - 0x00, /* C6 */ - 0x00, /* C7 */ - 0x00, /* C8 */ - 0x00, /* C9 */ - 0x00, /* CA */ - 0x00, /* CB */ - 0x00, /* CC */ - 0x00, /* CD */ - 0x00, /* CE */ - 0x00, /* CF */ - 0x00, /* D0 */ - 0x00, /* D1 */ - 0x00, /* D2 */ - 0x00, /* D3 */ - 0x00, /* D4 */ - 0x00, /* D5 */ - 0x00, /* D6 */ - 0x00, /* D7 */ - 0x00, /* D8 */ - 0x00, /* D9 */ - 0x00, /* DA */ - 0x00, /* DB */ - 0x00, /* DC */ - 0x00, /* DD */ - 0x00, /* DE */ - 0x00, /* DF */ - 0x00, /* E0 */ - 0x00, /* E1 */ - 0x00, /* E2 */ - 0x00, /* E3 */ - 0x00, /* E4 */ - 0x00, /* E5 */ - 0x00, /* E6 */ - 0x00, /* E7 */ - 0x00, /* E8 */ - 0x00, /* E9 */ - 0x00, /* EA */ - 0x00, /* EB */ - 0x00, /* EC */ - 0x00, /* ED */ - 0x00, /* EE */ - 0x00, /* EF */ - 0x00, /* F0 */ - 0x00, /* F1 */ - 0x00, /* F2 */ - 0x00, /* F3 */ - 0x00, /* F4 */ - 0x00, /* F5 */ - 0x00, /* F6 */ - 0x00, /* F7 */ - 0x00, /* F8 */ - 0x00, /* F9 */ - 0x00, /* FA */ - 0x00, /* FB */ - 0x00, /* FC */ - 0x00, /* FD */ - 0x00, /* FE */ - 0x00, /* FF */ +static const struct reg_default max98095_reg_def[] = { + { 0xf, 0x00 }, /* 0F */ + { 0x10, 0x00 }, /* 10 */ + { 0x11, 0x00 }, /* 11 */ + { 0x12, 0x00 }, /* 12 */ + { 0x13, 0x00 }, /* 13 */ + { 0x14, 0x00 }, /* 14 */ + { 0x15, 0x00 }, /* 15 */ + { 0x16, 0x00 }, /* 16 */ + { 0x17, 0x00 }, /* 17 */ + { 0x18, 0x00 }, /* 18 */ + { 0x19, 0x00 }, /* 19 */ + { 0x1a, 0x00 }, /* 1A */ + { 0x1b, 0x00 }, /* 1B */ + { 0x1c, 0x00 }, /* 1C */ + { 0x1d, 0x00 }, /* 1D */ + { 0x1e, 0x00 }, /* 1E */ + { 0x1f, 0x00 }, /* 1F */ + { 0x20, 0x00 }, /* 20 */ + { 0x21, 0x00 }, /* 21 */ + { 0x22, 0x00 }, /* 22 */ + { 0x23, 0x00 }, /* 23 */ + { 0x24, 0x00 }, /* 24 */ + { 0x25, 0x00 }, /* 25 */ + { 0x26, 0x00 }, /* 26 */ + { 0x27, 0x00 }, /* 27 */ + { 0x28, 0x00 }, /* 28 */ + { 0x29, 0x00 }, /* 29 */ + { 0x2a, 0x00 }, /* 2A */ + { 0x2b, 0x00 }, /* 2B */ + { 0x2c, 0x00 }, /* 2C */ + { 0x2d, 0x00 }, /* 2D */ + { 0x2e, 0x00 }, /* 2E */ + { 0x2f, 0x00 }, /* 2F */ + { 0x30, 0x00 }, /* 30 */ + { 0x31, 0x00 }, /* 31 */ + { 0x32, 0x00 }, /* 32 */ + { 0x33, 0x00 }, /* 33 */ + { 0x34, 0x00 }, /* 34 */ + { 0x35, 0x00 }, /* 35 */ + { 0x36, 0x00 }, /* 36 */ + { 0x37, 0x00 }, /* 37 */ + { 0x38, 0x00 }, /* 38 */ + { 0x39, 0x00 }, /* 39 */ + { 0x3a, 0x00 }, /* 3A */ + { 0x3b, 0x00 }, /* 3B */ + { 0x3c, 0x00 }, /* 3C */ + { 0x3d, 0x00 }, /* 3D */ + { 0x3e, 0x00 }, /* 3E */ + { 0x3f, 0x00 }, /* 3F */ + { 0x40, 0x00 }, /* 40 */ + { 0x41, 0x00 }, /* 41 */ + { 0x42, 0x00 }, /* 42 */ + { 0x43, 0x00 }, /* 43 */ + { 0x44, 0x00 }, /* 44 */ + { 0x45, 0x00 }, /* 45 */ + { 0x46, 0x00 }, /* 46 */ + { 0x47, 0x00 }, /* 47 */ + { 0x48, 0x00 }, /* 48 */ + { 0x49, 0x00 }, /* 49 */ + { 0x4a, 0x00 }, /* 4A */ + { 0x4b, 0x00 }, /* 4B */ + { 0x4c, 0x00 }, /* 4C */ + { 0x4d, 0x00 }, /* 4D */ + { 0x4e, 0x00 }, /* 4E */ + { 0x4f, 0x00 }, /* 4F */ + { 0x50, 0x00 }, /* 50 */ + { 0x51, 0x00 }, /* 51 */ + { 0x52, 0x00 }, /* 52 */ + { 0x53, 0x00 }, /* 53 */ + { 0x54, 0x00 }, /* 54 */ + { 0x55, 0x00 }, /* 55 */ + { 0x56, 0x00 }, /* 56 */ + { 0x57, 0x00 }, /* 57 */ + { 0x58, 0x00 }, /* 58 */ + { 0x59, 0x00 }, /* 59 */ + { 0x5a, 0x00 }, /* 5A */ + { 0x5b, 0x00 }, /* 5B */ + { 0x5c, 0x00 }, /* 5C */ + { 0x5d, 0x00 }, /* 5D */ + { 0x5e, 0x00 }, /* 5E */ + { 0x5f, 0x00 }, /* 5F */ + { 0x60, 0x00 }, /* 60 */ + { 0x61, 0x00 }, /* 61 */ + { 0x62, 0x00 }, /* 62 */ + { 0x63, 0x00 }, /* 63 */ + { 0x64, 0x00 }, /* 64 */ + { 0x65, 0x00 }, /* 65 */ + { 0x66, 0x00 }, /* 66 */ + { 0x67, 0x00 }, /* 67 */ + { 0x68, 0x00 }, /* 68 */ + { 0x69, 0x00 }, /* 69 */ + { 0x6a, 0x00 }, /* 6A */ + { 0x6b, 0x00 }, /* 6B */ + { 0x6c, 0x00 }, /* 6C */ + { 0x6d, 0x00 }, /* 6D */ + { 0x6e, 0x00 }, /* 6E */ + { 0x6f, 0x00 }, /* 6F */ + { 0x70, 0x00 }, /* 70 */ + { 0x71, 0x00 }, /* 71 */ + { 0x72, 0x00 }, /* 72 */ + { 0x73, 0x00 }, /* 73 */ + { 0x74, 0x00 }, /* 74 */ + { 0x75, 0x00 }, /* 75 */ + { 0x76, 0x00 }, /* 76 */ + { 0x77, 0x00 }, /* 77 */ + { 0x78, 0x00 }, /* 78 */ + { 0x79, 0x00 }, /* 79 */ + { 0x7a, 0x00 }, /* 7A */ + { 0x7b, 0x00 }, /* 7B */ + { 0x7c, 0x00 }, /* 7C */ + { 0x7d, 0x00 }, /* 7D */ + { 0x7e, 0x00 }, /* 7E */ + { 0x7f, 0x00 }, /* 7F */ + { 0x80, 0x00 }, /* 80 */ + { 0x81, 0x00 }, /* 81 */ + { 0x82, 0x00 }, /* 82 */ + { 0x83, 0x00 }, /* 83 */ + { 0x84, 0x00 }, /* 84 */ + { 0x85, 0x00 }, /* 85 */ + { 0x86, 0x00 }, /* 86 */ + { 0x87, 0x00 }, /* 87 */ + { 0x88, 0x00 }, /* 88 */ + { 0x89, 0x00 }, /* 89 */ + { 0x8a, 0x00 }, /* 8A */ + { 0x8b, 0x00 }, /* 8B */ + { 0x8c, 0x00 }, /* 8C */ + { 0x8d, 0x00 }, /* 8D */ + { 0x8e, 0x00 }, /* 8E */ + { 0x8f, 0x00 }, /* 8F */ + { 0x90, 0x00 }, /* 90 */ + { 0x91, 0x00 }, /* 91 */ + { 0x92, 0x30 }, /* 92 */ + { 0x93, 0xF0 }, /* 93 */ + { 0x94, 0x00 }, /* 94 */ + { 0x95, 0x00 }, /* 95 */ + { 0x96, 0x3F }, /* 96 */ + { 0x97, 0x00 }, /* 97 */ + { 0xff, 0x00 }, /* FF */ }; static struct { @@ -577,14 +460,14 @@ static struct { { 0xFF, 0x00 }, /* FF */ }; -static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg) +static bool max98095_readable(struct device *dev, unsigned int reg) { if (reg >= M98095_REG_CNT) return 0; return max98095_access[reg].readable != 0; } -static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool max98095_volatile(struct device *dev, unsigned int reg) { if (reg > M98095_REG_MAX_CACHED) return 1; @@ -611,6 +494,19 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) return 0; } +static const struct regmap_config max98095_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = max98095_reg_def, + .num_reg_defaults = ARRAY_SIZE(max98095_reg_def), + .max_register = M98095_0FF_REV_ID, + .cache_type = REGCACHE_RBTREE, + + .readable_reg = max98095_readable, + .volatile_reg = max98095_volatile, +}; + /* * Load equalizer DSP coefficient configurations registers */ @@ -1723,6 +1619,7 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai, static int max98095_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int ret; switch (level) { @@ -1734,7 +1631,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_cache_sync(codec); + ret = regcache_sync(max98095->regmap); if (ret != 0) { dev_err(codec->dev, "Failed to sync cache: %d\n", ret); @@ -1749,7 +1646,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, M98095_090_PWR_EN_IN, M98095_MBEN, 0); - codec->cache_sync = 1; + regcache_mark_dirty(max98095->regmap); break; } codec->dapm.bias_level = level; @@ -2316,7 +2213,7 @@ static int max98095_reset(struct snd_soc_codec *codec) /* Reset to hardware default for registers, as there is not * a soft reset hardware control register */ for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) { - ret = snd_soc_write(codec, i, max98095_reg_def[i]); + ret = snd_soc_write(codec, i, snd_soc_read(codec, i)); if (ret < 0) { dev_err(codec->dev, "Failed to reset: %d\n", ret); return ret; @@ -2333,7 +2230,7 @@ static int max98095_probe(struct snd_soc_codec *codec) struct i2c_client *client; int ret = 0; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -2455,11 +2352,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = { .set_bias_level = max98095_set_bias_level, .controls = max98095_snd_controls, .num_controls = ARRAY_SIZE(max98095_snd_controls), - .reg_cache_size = ARRAY_SIZE(max98095_reg_def), - .reg_word_size = sizeof(u8), - .reg_cache_default = max98095_reg_def, - .readable_register = max98095_readable, - .volatile_register = max98095_volatile, .dapm_widgets = max98095_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets), .dapm_routes = max98095_audio_map, @@ -2477,6 +2369,13 @@ static int max98095_i2c_probe(struct i2c_client *i2c, if (max98095 == NULL) return -ENOMEM; + max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); + if (IS_ERR(max98095->regmap)) { + ret = PTR_ERR(max98095->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + max98095->devtype = id->driver_data; i2c_set_clientdata(i2c, max98095); max98095->pdata = i2c->dev.platform_data; -- cgit v0.10.2 From 2c142c61f79c14a120c0f4d2954e35b6404b2d0d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Sep 2013 18:49:54 +0100 Subject: ASoC: tlv320aic23: Remove #defines for I2C The only control interface supported by this driver is I2C so there is no need for conditional compilation around the control interface. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 31762eb..3299459 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -613,7 +613,6 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* * If the i2c layer weren't so broken, we could pass this kind of data * around @@ -660,29 +659,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = { .id_table = tlv320aic23_id, }; -#endif - -static int __init tlv320aic23_modinit(void) -{ - int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&tlv320aic23_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(tlv320aic23_modinit); - -static void __exit tlv320aic23_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&tlv320aic23_i2c_driver); -#endif -} -module_exit(tlv320aic23_exit); +module_i2c_driver(tlv320aic23_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); MODULE_AUTHOR("Arun KS "); -- cgit v0.10.2 From b07c443fabb97f909c8cc406bfd2d0ecc002bc3b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Sep 2013 18:51:26 +0100 Subject: ASoC: tlv320aic23: Convert to table based control init Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 3299459..3a6be8c 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -586,9 +586,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec) snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1); - snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls, - ARRAY_SIZE(tlv320aic23_snd_controls)); - return 0; } @@ -607,6 +604,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .suspend = tlv320aic23_suspend, .resume = tlv320aic23_resume, .set_bias_level = tlv320aic23_set_bias_level, + .controls = tlv320aic23_snd_controls, + .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), .dapm_widgets = tlv320aic23_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), .dapm_routes = tlv320aic23_intercon, -- cgit v0.10.2 From a16bbe4d685c1465b98d3fabdb95310eafcd383e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 20:07:12 +0100 Subject: ASoC: tlv320aic3x: Remove nonsense comment for register cache Every statement in this comment is incorrect either through bitrot or (mostly) through never having corresponded to reality in the first place. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6e3f269..3abbff3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -90,12 +90,6 @@ struct aic3x_priv { enum aic3x_micbias_voltage micbias_vg; }; -/* - * AIC3X register cache - * We can't read the AIC3X register space when we are - * using 2 wire for device control, so we cache them instead. - * There is no point in caching the reset register - */ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { 0x00, 0x00, 0x00, 0x10, /* 0 */ 0x04, 0x00, 0x00, 0x00, /* 4 */ -- cgit v0.10.2 From 6f818e04fc8d3d413eeb3a689c7607f2a89ab568 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 19:48:45 +0100 Subject: ASoC: tlv320aic3x: Move resource acquisition to I2C probe This is more idiomatic and interacts better with deferred probing. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 3abbff3..de17a36 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1345,23 +1345,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) return ret; } - if (gpio_is_valid(aic3x->gpio_reset) && - !aic3x_is_shared_reset(aic3x)) { - ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); - if (ret != 0) - goto err_gpio; - gpio_direction_output(aic3x->gpio_reset, 0); - } - - for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) - aic3x->supplies[i].supply = aic3x_supply_names[i]; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), - aic3x->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - goto err_get; - } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; @@ -1418,12 +1401,6 @@ err_notif: while (i--) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); - regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); -err_get: - if (gpio_is_valid(aic3x->gpio_reset) && - !aic3x_is_shared_reset(aic3x)) - gpio_free(aic3x->gpio_reset); -err_gpio: return ret; } @@ -1434,15 +1411,9 @@ static int aic3x_remove(struct snd_soc_codec *codec) aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); list_del(&aic3x->list); - if (gpio_is_valid(aic3x->gpio_reset) && - !aic3x_is_shared_reset(aic3x)) { - gpio_set_value(aic3x->gpio_reset, 0); - gpio_free(aic3x->gpio_reset); - } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); - regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); return 0; } @@ -1484,7 +1455,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, struct aic3x_priv *aic3x; struct aic3x_setup_data *ai3x_setup; struct device_node *np = i2c->dev.of_node; - int ret; + int ret, i; u32 value; aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); @@ -1545,14 +1516,46 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, aic3x->model = id->driver_data; + if (gpio_is_valid(aic3x->gpio_reset) && + !aic3x_is_shared_reset(aic3x)) { + ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); + if (ret != 0) + goto err; + gpio_direction_output(aic3x->gpio_reset, 0); + } + + for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) + aic3x->supplies[i].supply = aic3x_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), + aic3x->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + goto err_gpio; + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); return ret; + +err_gpio: + if (gpio_is_valid(aic3x->gpio_reset) && + !aic3x_is_shared_reset(aic3x)) + gpio_free(aic3x->gpio_reset); +err: + return ret; } static int aic3x_i2c_remove(struct i2c_client *client) { + struct aic3x_priv *aic3x = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); + if (gpio_is_valid(aic3x->gpio_reset) && + !aic3x_is_shared_reset(aic3x)) { + gpio_set_value(aic3x->gpio_reset, 0); + gpio_free(aic3x->gpio_reset); + } return 0; } -- cgit v0.10.2 From f9df1ae6b59e5bb16d3094e9c1c8b6feeaf32aae Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 23:53:16 +0100 Subject: ASoC: tlv320aic3x: Move to table based control init Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index de17a36..397a213 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1369,8 +1369,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) (aic3x->setup->gpio_func[1] & 0xf) << 4); } - snd_soc_add_codec_controls(codec, aic3x_snd_controls, - ARRAY_SIZE(aic3x_snd_controls)); if (aic3x->model == AIC3X_MODEL_3007) snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); @@ -1428,6 +1426,8 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .remove = aic3x_remove, .suspend = aic3x_suspend, .resume = aic3x_resume, + .controls = aic3x_snd_controls, + .num_controls = ARRAY_SIZE(aic3x_snd_controls), }; /* -- cgit v0.10.2 From 58a63fbd7c80510140a94442b2ca9199bb6d51c3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 23:57:36 +0100 Subject: ASoC: tlv320aic3x: Move to table based DAPM init Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 397a213..16fc74c 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -818,12 +818,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, - ARRAY_SIZE(aic3x_dapm_widgets)); - - /* set up audio path interconnects */ - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - if (aic3x->model == AIC3X_MODEL_3007) { snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets, ARRAY_SIZE(aic3007_dapm_widgets)); @@ -1428,6 +1422,10 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .resume = aic3x_resume, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), + .dapm_widgets = aic3x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), }; /* -- cgit v0.10.2 From 2677b4bb7316c07dd53535e01bd9b2ec699d0314 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 19:55:39 +0100 Subject: ASoC: tlv320aic3x: Don't reference cache datastructure directly Rather than referencing the cache directly read back the values we are going to restore, supporting refactoring to use regmap. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 16fc74c..83e7d85 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1068,14 +1068,14 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, static int aic3x_init_3007(struct snd_soc_codec *codec) { - u8 tmp1, tmp2, *cache = codec->reg_cache; + unsigned int tmp1, tmp2; /* * There is no need to cache writes to undocumented page 0xD but * respective page 0 register cache entries must be preserved */ - tmp1 = cache[0xD]; - tmp2 = cache[0x8]; + tmp1 = snd_soc_read(codec, 0xD); + tmp2 = snd_soc_read(codec, 0x8); /* Class-D speaker driver init; datasheet p. 46 */ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); snd_soc_write(codec, 0xD, 0x0D); @@ -1083,8 +1083,9 @@ static int aic3x_init_3007(struct snd_soc_codec *codec) snd_soc_write(codec, 0x8, 0x5D); snd_soc_write(codec, 0x8, 0x5C); snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); - cache[0xD] = tmp1; - cache[0x8] = tmp2; + + snd_soc_write(codec, 0xD, tmp1); + snd_soc_write(codec, 0x8, tmp2); return 0; } -- cgit v0.10.2 From 2a6fedec195b9bd20e60f9825ba7cc6315e54652 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Sep 2013 00:07:13 +0100 Subject: ASoC: tlv320aic3x: Convert to direct regmap API usage This is slightly more complex than a standard regmap conversion due to the moderately detailed cache control and the open coding of a register patch for the class D speaker on the TLV320AIC3007. Although the device supports paging this is not currently implemented as the additional pages are only used during the application of the patch for the TLV320AIC3007. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 83e7d85..892c108 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -72,9 +72,9 @@ struct aic3x_disable_nb { /* codec private data */ struct aic3x_priv { struct snd_soc_codec *codec; + struct regmap *regmap; struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; - enum snd_soc_control_type control_type; struct aic3x_setup_data *setup; unsigned int sysclk; struct list_head list; @@ -90,35 +90,45 @@ struct aic3x_priv { enum aic3x_micbias_voltage micbias_vg; }; -static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { - 0x00, 0x00, 0x00, 0x10, /* 0 */ - 0x04, 0x00, 0x00, 0x00, /* 4 */ - 0x00, 0x00, 0x00, 0x01, /* 8 */ - 0x00, 0x00, 0x00, 0x80, /* 12 */ - 0x80, 0xff, 0xff, 0x78, /* 16 */ - 0x78, 0x78, 0x78, 0x78, /* 20 */ - 0x78, 0x00, 0x00, 0xfe, /* 24 */ - 0x00, 0x00, 0xfe, 0x00, /* 28 */ - 0x18, 0x18, 0x00, 0x00, /* 32 */ - 0x00, 0x00, 0x00, 0x00, /* 36 */ - 0x00, 0x00, 0x00, 0x80, /* 40 */ - 0x80, 0x00, 0x00, 0x00, /* 44 */ - 0x00, 0x00, 0x00, 0x04, /* 48 */ - 0x00, 0x00, 0x00, 0x00, /* 52 */ - 0x00, 0x00, 0x04, 0x00, /* 56 */ - 0x00, 0x00, 0x00, 0x00, /* 60 */ - 0x00, 0x04, 0x00, 0x00, /* 64 */ - 0x00, 0x00, 0x00, 0x00, /* 68 */ - 0x04, 0x00, 0x00, 0x00, /* 72 */ - 0x00, 0x00, 0x00, 0x00, /* 76 */ - 0x00, 0x00, 0x00, 0x00, /* 80 */ - 0x00, 0x00, 0x00, 0x00, /* 84 */ - 0x00, 0x00, 0x00, 0x00, /* 88 */ - 0x00, 0x00, 0x00, 0x00, /* 92 */ - 0x00, 0x00, 0x00, 0x00, /* 96 */ - 0x00, 0x00, 0x02, 0x00, /* 100 */ - 0x00, 0x00, 0x00, 0x00, /* 104 */ - 0x00, 0x00, /* 108 */ +static const struct reg_default aic3x_reg[] = { + { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, { 3, 0x10 }, + { 4, 0x04 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 }, + { 8, 0x00 }, { 9, 0x00 }, { 10, 0x00 }, { 11, 0x01 }, + { 12, 0x00 }, { 13, 0x00 }, { 14, 0x00 }, { 15, 0x80 }, + { 16, 0x80 }, { 17, 0xff }, { 18, 0xff }, { 19, 0x78 }, + { 20, 0x78 }, { 21, 0x78 }, { 22, 0x78 }, { 23, 0x78 }, + { 24, 0x78 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0xfe }, + { 28, 0x00 }, { 29, 0x00 }, { 30, 0xfe }, { 31, 0x00 }, + { 32, 0x18 }, { 33, 0x18 }, { 34, 0x00 }, { 35, 0x00 }, + { 36, 0x00 }, { 37, 0x00 }, { 38, 0x00 }, { 39, 0x00 }, + { 40, 0x00 }, { 41, 0x00 }, { 42, 0x00 }, { 43, 0x80 }, + { 44, 0x80 }, { 45, 0x00 }, { 46, 0x00 }, { 47, 0x00 }, + { 48, 0x00 }, { 49, 0x00 }, { 50, 0x00 }, { 51, 0x04 }, + { 52, 0x00 }, { 53, 0x00 }, { 54, 0x00 }, { 55, 0x00 }, + { 56, 0x00 }, { 57, 0x00 }, { 58, 0x04 }, { 59, 0x00 }, + { 60, 0x00 }, { 61, 0x00 }, { 62, 0x00 }, { 63, 0x00 }, + { 64, 0x00 }, { 65, 0x04 }, { 66, 0x00 }, { 67, 0x00 }, + { 68, 0x00 }, { 69, 0x00 }, { 70, 0x00 }, { 71, 0x00 }, + { 72, 0x04 }, { 73, 0x00 }, { 74, 0x00 }, { 75, 0x00 }, + { 76, 0x00 }, { 77, 0x00 }, { 78, 0x00 }, { 79, 0x00 }, + { 80, 0x00 }, { 81, 0x00 }, { 82, 0x00 }, { 83, 0x00 }, + { 84, 0x00 }, { 85, 0x00 }, { 86, 0x00 }, { 87, 0x00 }, + { 88, 0x00 }, { 89, 0x00 }, { 90, 0x00 }, { 91, 0x00 }, + { 92, 0x00 }, { 93, 0x00 }, { 94, 0x00 }, { 95, 0x00 }, + { 96, 0x00 }, { 97, 0x00 }, { 98, 0x00 }, { 99, 0x00 }, + { 100, 0x00 }, { 101, 0x00 }, { 102, 0x02 }, { 103, 0x00 }, + { 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 }, + { 108, 0x00 }, { 109, 0x00 }, +}; + +static const struct regmap_config aic3x_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = DAC_ICC_ADJ, + .reg_defaults = aic3x_reg, + .num_reg_defaults = ARRAY_SIZE(aic3x_reg), + .cache_type = REGCACHE_RBTREE, }; #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ @@ -1066,30 +1076,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -static int aic3x_init_3007(struct snd_soc_codec *codec) -{ - unsigned int tmp1, tmp2; - - /* - * There is no need to cache writes to undocumented page 0xD but - * respective page 0 register cache entries must be preserved - */ - tmp1 = snd_soc_read(codec, 0xD); - tmp2 = snd_soc_read(codec, 0x8); - /* Class-D speaker driver init; datasheet p. 46 */ - snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); - snd_soc_write(codec, 0xD, 0x0D); - snd_soc_write(codec, 0x8, 0x5C); - snd_soc_write(codec, 0x8, 0x5D); - snd_soc_write(codec, 0x8, 0x5C); - snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); - - snd_soc_write(codec, 0xD, tmp1); - snd_soc_write(codec, 0x8, tmp2); - - return 0; -} - static int aic3x_regulator_event(struct notifier_block *nb, unsigned long event, void *data) { @@ -1104,7 +1090,7 @@ static int aic3x_regulator_event(struct notifier_block *nb, */ if (gpio_is_valid(aic3x->gpio_reset)) gpio_set_value(aic3x->gpio_reset, 0); - aic3x->codec->cache_sync = 1; + regcache_mark_dirty(aic3x->regmap); } return 0; @@ -1113,8 +1099,7 @@ static int aic3x_regulator_event(struct notifier_block *nb, static int aic3x_set_power(struct snd_soc_codec *codec, int power) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); - int i, ret; - u8 *cache = codec->reg_cache; + int ret; if (power) { ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), @@ -1122,12 +1107,6 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) if (ret) goto out; aic3x->power = 1; - /* - * Reset release and cache sync is necessary only if some - * supply was off or if there were cached writes - */ - if (!codec->cache_sync) - goto out; if (gpio_is_valid(aic3x->gpio_reset)) { udelay(1); @@ -1135,12 +1114,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) } /* Sync reg_cache with the hardware */ - codec->cache_only = 0; - for (i = AIC3X_SAMPLE_RATE_SEL_REG; i < ARRAY_SIZE(aic3x_reg); i++) - snd_soc_write(codec, i, cache[i]); - if (aic3x->model == AIC3X_MODEL_3007) - aic3x_init_3007(codec); - codec->cache_sync = 0; + regcache_cache_only(aic3x->regmap, false); + regcache_sync(aic3x->regmap); } else { /* * Do soft reset to this codec instance in order to clear @@ -1148,10 +1123,10 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) * remain on */ snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); - codec->cache_sync = 1; + regcache_mark_dirty(aic3x->regmap); aic3x->power = 0; /* HW writes are needless when bias is off */ - codec->cache_only = 1; + regcache_cache_only(aic3x->regmap, true); ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); } @@ -1306,7 +1281,6 @@ static int aic3x_init(struct snd_soc_codec *codec) snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); if (aic3x->model == AIC3X_MODEL_3007) { - aic3x_init_3007(codec); snd_soc_write(codec, CLASSD_CTRL, 0); } @@ -1334,7 +1308,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) INIT_LIST_HEAD(&aic3x->list); aic3x->codec = codec; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -1353,7 +1327,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) } } - codec->cache_only = 1; + regcache_mark_dirty(aic3x->regmap); aic3x_init(codec); if (aic3x->setup) { @@ -1414,9 +1388,6 @@ static int aic3x_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ARRAY_SIZE(aic3x_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = aic3x_reg, .probe = aic3x_probe, .remove = aic3x_remove, .suspend = aic3x_suspend, @@ -1443,6 +1414,16 @@ static const struct i2c_device_id aic3x_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); +static const struct reg_default aic3007_class_d[] = { + /* Class-D speaker driver init; datasheet p. 46 */ + { AIC3X_PAGE_SELECT, 0x0D }, + { 0xD, 0x0D }, + { 0x8, 0x5C }, + { 0x8, 0x5D }, + { 0x8, 0x5C }, + { AIC3X_PAGE_SELECT, 0x00 }, +}; + /* * If the i2c layer weren't so broken, we could pass this kind of data * around @@ -1463,7 +1444,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, return -ENOMEM; } - aic3x->control_type = SND_SOC_I2C; + aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap); + if (IS_ERR(aic3x->regmap)) { + ret = PTR_ERR(aic3x->regmap); + return ret; + } + + regcache_cache_only(aic3x->regmap, true); i2c_set_clientdata(i2c, aic3x); if (pdata) { @@ -1533,6 +1520,14 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, goto err_gpio; } + if (aic3x->model == AIC3X_MODEL_3007) { + ret = regmap_register_patch(aic3x->regmap, aic3007_class_d, + ARRAY_SIZE(aic3007_class_d)); + if (ret != 0) + dev_err(&i2c->dev, "Failed to init class D: %d\n", + ret); + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); return ret; -- cgit v0.10.2 From 19ab2a7a24539d6c80dfe301d2970b075ad3b9ab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Sep 2013 11:14:39 +0100 Subject: ASoC: max98088: Set max_register Makes some of the debug functions more useful. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 31912d5..66ceee2 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -552,6 +552,7 @@ static const struct regmap_config max98088_regmap = { .readable_reg = max98088_readable_register, .volatile_reg = max98088_volatile_register, + .max_register = 0xff, .reg_defaults = max98088_reg, .num_reg_defaults = ARRAY_SIZE(max98088_reg), -- cgit v0.10.2 From 068416620c0d956b3b382d19dd3000119e280f8c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 18:12:51 +0100 Subject: ASoC: max9850: Convert to direct regmap API usage This prepares for removal of the duplicated register I/O functionality in ASoC. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 58c38a5..c5dd617 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,18 +28,26 @@ #include "max9850.h" struct max9850_priv { + struct regmap *regmap; unsigned int sysclk; }; /* max9850 register cache */ -static const u8 max9850_reg[MAX9850_CACHEREGNUM] = { - 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +static const struct reg_default max9850_reg[] = { + { 2, 0x0c }, + { 3, 0x00 }, + { 4, 0x00 }, + { 5, 0x00 }, + { 6, 0x00 }, + { 7, 0x00 }, + { 8, 0x00 }, + { 9, 0x00 }, + { 10, 0x00 }, }; /* these registers are not used at the moment but provided for the sake of * completeness */ -static int max9850_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) +static bool max9850_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case MAX9850_STATUSA: @@ -49,6 +58,15 @@ static int max9850_volatile_register(struct snd_soc_codec *codec, } } +static const struct regmap_config max9850_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = MAX9850_DIGITAL_AUDIO, + .volatile_reg = max9850_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + static const unsigned int max9850_tlv[] = { TLV_DB_RANGE_HEAD(4), 0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0), @@ -225,6 +243,7 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) static int max9850_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec); int ret; switch (level) { @@ -234,7 +253,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_cache_sync(codec); + ret = regcache_sync(max9850->regmap); if (ret) { dev_err(codec->dev, "Failed to sync cache: %d\n", ret); @@ -295,7 +314,7 @@ static int max9850_probe(struct snd_soc_codec *codec) { int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -316,10 +335,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = { .suspend = max9850_suspend, .resume = max9850_resume, .set_bias_level = max9850_set_bias_level, - .reg_cache_size = ARRAY_SIZE(max9850_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = max9850_reg, - .volatile_register = max9850_volatile_register, .controls = max9850_controls, .num_controls = ARRAY_SIZE(max9850_controls), @@ -340,6 +355,10 @@ static int max9850_i2c_probe(struct i2c_client *i2c, if (max9850 == NULL) return -ENOMEM; + max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap); + if (IS_ERR(max9850->regmap)) + return PTR_ERR(max9850->regmap); + i2c_set_clientdata(i2c, max9850); ret = snd_soc_register_codec(&i2c->dev, -- cgit v0.10.2 From 6f88063c1474b8cdd9254d3934047b6087222145 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 13:46:05 +0100 Subject: ASoC: cq93vc: Use table based control registration Saves a little code. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index e2c4c0a8..e538f4e 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -156,10 +156,6 @@ static int cq93vc_probe(struct snd_soc_codec *codec) davinci_vc->cq93vc.codec = codec; codec->control_data = davinci_vc; - /* Set controls */ - snd_soc_add_codec_controls(codec, cq93vc_snd_controls, - ARRAY_SIZE(cq93vc_snd_controls)); - /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -180,6 +176,8 @@ static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .probe = cq93vc_probe, .remove = cq93vc_remove, .resume = cq93vc_resume, + .controls = cq93vc_snd_controls, + .num_controls = ARRAY_SIZE(cq93vc_snd_controls), }; static int cq93vc_platform_probe(struct platform_device *pdev) -- cgit v0.10.2 From 1201939a6f981cb656872784e39ef443540078cd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 13:38:16 +0100 Subject: ASoC: cq93vc: Use core I/O functions Support future refactoring by using the core I/O functions rather than calling the driver provided I/O functions directly. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index e538f4e..2cbb584 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -64,13 +64,15 @@ static const struct snd_kcontrol_new cq93vc_snd_controls[] = { static int cq93vc_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u8 reg = cq93vc_read(codec, DAVINCI_VC_REG09) & ~DAVINCI_VC_REG09_MUTE; + u8 reg; if (mute) - cq93vc_write(codec, DAVINCI_VC_REG09, - reg | DAVINCI_VC_REG09_MUTE); + reg = DAVINCI_VC_REG09_MUTE; else - cq93vc_write(codec, DAVINCI_VC_REG09, reg); + reg = 0; + + snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE, + reg); return 0; } @@ -97,18 +99,18 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec, { switch (level) { case SND_SOC_BIAS_ON: - cq93vc_write(codec, DAVINCI_VC_REG12, + snd_soc_write(codec, DAVINCI_VC_REG12, DAVINCI_VC_REG12_POWER_ALL_ON); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - cq93vc_write(codec, DAVINCI_VC_REG12, + snd_soc_write(codec, DAVINCI_VC_REG12, DAVINCI_VC_REG12_POWER_ALL_OFF); break; case SND_SOC_BIAS_OFF: /* force all power off */ - cq93vc_write(codec, DAVINCI_VC_REG12, + snd_soc_write(codec, DAVINCI_VC_REG12, DAVINCI_VC_REG12_POWER_ALL_OFF); break; } -- cgit v0.10.2 From d33c33352b3228ca3a422e55981f80fc12dc30f8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 13:52:41 +0100 Subject: ASoC: cq93vc: Use regmap for I/O Avoid use of the ASoC-specific register I/O functions by converting to use the MMIO regmap provided the core MFD. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 2cbb584..43737a27 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -38,24 +38,6 @@ #include #include -static inline unsigned int cq93vc_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct davinci_vc *davinci_vc = codec->control_data; - - return readl(davinci_vc->base + reg); -} - -static inline int cq93vc_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - struct davinci_vc *davinci_vc = codec->control_data; - - writel(value, davinci_vc->base + reg); - - return 0; -} - static const struct snd_kcontrol_new cq93vc_snd_controls[] = { SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0), SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0), @@ -156,7 +138,9 @@ static int cq93vc_probe(struct snd_soc_codec *codec) struct davinci_vc *davinci_vc = codec->dev->platform_data; davinci_vc->cq93vc.codec = codec; - codec->control_data = davinci_vc; + codec->control_data = davinci_vc->regmap; + + snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP); /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -172,8 +156,6 @@ static int cq93vc_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { - .read = cq93vc_read, - .write = cq93vc_write, .set_bias_level = cq93vc_set_bias_level, .probe = cq93vc_probe, .remove = cq93vc_remove, -- cgit v0.10.2 From efeb970ee799b80c984a42d5706081af6047e160 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 23 Sep 2013 23:12:17 -0700 Subject: ASoC: rsnd: remove rsnd_priv_read/write/bset() adg.c only used rsnd_priv_read/write/bset() which is the only user of NULL mod. but, it can be removed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2935bbf..9430097 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -21,6 +21,7 @@ struct rsnd_adg { int rate_of_441khz_div_6; int rate_of_48khz_div_6; + u32 ckr; }; #define for_each_rsnd_clk(pos, adg, i) \ @@ -115,6 +116,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) found_clock: + /* see rsnd_adg_ssi_clk_init() */ + rsnd_mod_bset(mod, SSICKR, 0x00FF0000, adg->ckr); + rsnd_mod_write(mod, BRRA, 0x00000002); /* 1/6 */ + rsnd_mod_write(mod, BRRB, 0x00000002); /* 1/6 */ + /* * This "mod" = "ssi" here. * we can get "ssi id" from mod @@ -181,9 +187,7 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) } } - rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr); - rsnd_priv_write(priv, BRRA, 0x00000002); /* 1/6 */ - rsnd_priv_write(priv, BRRB, 0x00000002); /* 1/6 */ + adg->ckr = ckr; } int rsnd_adg_probe(struct platform_device *pdev, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9cc6986..3868aaf 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -78,10 +78,6 @@ struct rsnd_dai_stream; #define rsnd_mod_bset(m, r, s, d) \ rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) -#define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r) -#define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d) -#define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d) - u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); -- cgit v0.10.2 From 55e5b6fd5af04b6d8b0ac6635edf49476ff298ba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 23 Sep 2013 23:12:27 -0700 Subject: ASoC: rsnd: use regmap instead of original register mapping method Current Linux kernel is supporting regmap/regmap_field, and, it is good match for Renesas Sound Gen1/Gen2 register mapping. This patch uses regmap instead of original method for register access Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a357060..fc83f0f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -106,51 +106,6 @@ (!(priv->info->func) ? -ENODEV : \ priv->info->func(param)) - -/* - * basic function - */ -u32 rsnd_read(struct rsnd_priv *priv, - struct rsnd_mod *mod, enum rsnd_reg reg) -{ - void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); - - BUG_ON(!base); - - return ioread32(base); -} - -void rsnd_write(struct rsnd_priv *priv, - struct rsnd_mod *mod, - enum rsnd_reg reg, u32 data) -{ - void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); - struct device *dev = rsnd_priv_to_dev(priv); - - BUG_ON(!base); - - dev_dbg(dev, "w %p : %08x\n", base, data); - - iowrite32(data, base); -} - -void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, - enum rsnd_reg reg, u32 mask, u32 data) -{ - void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); - struct device *dev = rsnd_priv_to_dev(priv); - u32 val; - - BUG_ON(!base); - - val = ioread32(base); - val &= ~mask; - val |= data & mask; - iowrite32(val, base); - - dev_dbg(dev, "s %p : %08x\n", base, val); -} - /* * rsnd_mod functions */ diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 331fc55..61212ee 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -24,21 +24,97 @@ struct rsnd_gen_ops { struct rsnd_dai_stream *io); }; -struct rsnd_gen_reg_map { - int index; /* -1 : not supported */ - u32 offset_id; /* offset of ssi0, ssi1, ssi2... */ - u32 offset_adr; /* offset of SSICR, SSISR, ... */ -}; - struct rsnd_gen { void __iomem *base[RSND_BASE_MAX]; - struct rsnd_gen_reg_map reg_map[RSND_REG_MAX]; struct rsnd_gen_ops *ops; + + struct regmap *regmap; + struct regmap_field *regs[RSND_REG_MAX]; }; #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) +#define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \ + [id] = { \ + .reg = (unsigned int)gen->base[reg_id] + offset, \ + .lsb = 0, \ + .msb = 31, \ + .id_size = _id_size, \ + .id_offset = _id_offset, \ + } + +/* + * basic function + */ +static int rsnd_regmap_write32(void *context, const void *_data, size_t count) +{ + struct rsnd_priv *priv = context; + struct device *dev = rsnd_priv_to_dev(priv); + u32 *data = (u32 *)_data; + u32 val = data[1]; + void __iomem *reg = (void *)data[0]; + + iowrite32(val, reg); + + dev_dbg(dev, "w %p : %08x\n", reg, val); + + return 0; +} + +static int rsnd_regmap_read32(void *context, + const void *_data, size_t reg_size, + void *_val, size_t val_size) +{ + struct rsnd_priv *priv = context; + struct device *dev = rsnd_priv_to_dev(priv); + u32 *data = (u32 *)_data; + u32 *val = (u32 *)_val; + void __iomem *reg = (void *)data[0]; + + *val = ioread32(reg); + + dev_dbg(dev, "r %p : %08x\n", reg, *val); + + return 0; +} + +static struct regmap_bus rsnd_regmap_bus = { + .write = rsnd_regmap_write32, + .read = rsnd_regmap_read32, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +u32 rsnd_read(struct rsnd_priv *priv, + struct rsnd_mod *mod, enum rsnd_reg reg) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + u32 val; + + regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); + + return val; +} + +void rsnd_write(struct rsnd_priv *priv, + struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); +} + +void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, + enum rsnd_reg reg, u32 mask, u32 data) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), + mask, data); +} + /* * Gen2 * will be filled in the future @@ -103,39 +179,64 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv, return ret; } -#define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \ - do { \ - (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \ - (g)->reg_map[RSND_REG_##i].offset_id = oi; \ - (g)->reg_map[RSND_REG_##i].offset_adr = oa; \ - } while (0) +/* single address mapping */ +#define RSND_GEN1_S_REG(gen, reg, id, offset) \ + RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) -static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen) +/* multi address mapping */ +#define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset) \ + RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9) + +static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) { - RSND_GEN1_REG_MAP(gen, SRU, SRC_ROUTE_SEL, 0x0, 0x00); - RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL0, 0x0, 0x08); - RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL1, 0x0, 0x0c); - RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL2, 0x0, 0x10); - RSND_GEN1_REG_MAP(gen, SRU, SRC_CTRL, 0x0, 0xc0); - RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0); - RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4); - RSND_GEN1_REG_MAP(gen, SRU, BUSIF_MODE, 0x4, 0x20); - RSND_GEN1_REG_MAP(gen, SRU, BUSIF_ADINR, 0x40, 0x214); - - RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00); - RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04); - RSND_GEN1_REG_MAP(gen, ADG, SSICKR, 0x0, 0x08); - RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL0, 0x0, 0x0c); - RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL1, 0x0, 0x10); - RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18); - RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c); - RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20); - - RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00); - RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04); - RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08); - RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c); - RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20); + int i; + struct device *dev = rsnd_priv_to_dev(priv); + struct regmap_config regc; + struct reg_field regf[RSND_REG_MAX] = { + RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), + RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), + RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), + RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), + RSND_GEN1_S_REG(gen, SRU, SRC_CTRL, 0xc0), + RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), + RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), + RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), + RSND_GEN1_M_REG(gen, SRU, BUSIF_ADINR, 0x214, 0x40), + + RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), + RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), + RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20), + + RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), + RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), + RSND_GEN1_M_REG(gen, SSI, SSITDR, 0x08, 0x40), + RSND_GEN1_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), + RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), + }; + + memset(®c, 0, sizeof(regc)); + regc.reg_bits = 32; + regc.val_bits = 32; + + gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); + if (IS_ERR(gen->regmap)) { + dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); + return PTR_ERR(gen->regmap); + } + + for (i = 0; i < RSND_REG_MAX; i++) { + gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); + if (IS_ERR(gen->regs[i])) + return PTR_ERR(gen->regs[i]); + + } + + return 0; } static int rsnd_gen1_probe(struct platform_device *pdev, @@ -147,6 +248,7 @@ static int rsnd_gen1_probe(struct platform_device *pdev, struct resource *sru_res; struct resource *adg_res; struct resource *ssi_res; + int ret; /* * map address @@ -163,7 +265,9 @@ static int rsnd_gen1_probe(struct platform_device *pdev, IS_ERR(gen->base[RSND_GEN1_SSI])) return -ENODEV; - rsnd_gen1_reg_map_init(gen); + ret = rsnd_gen1_regmap_init(priv, gen); + if (ret < 0) + return ret; dev_dbg(dev, "Gen1 device probed\n"); dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start, @@ -210,46 +314,12 @@ int rsnd_gen_path_exit(struct rsnd_priv *priv, return gen->ops->path_exit(priv, rdai, io); } -void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, - struct rsnd_mod *mod, - enum rsnd_reg reg) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - struct device *dev = rsnd_priv_to_dev(priv); - int index; - u32 offset_id, offset_adr; - - if (reg >= RSND_REG_MAX) { - dev_err(dev, "rsnd_reg reg error\n"); - return NULL; - } - - index = gen->reg_map[reg].index; - offset_id = gen->reg_map[reg].offset_id; - offset_adr = gen->reg_map[reg].offset_adr; - - if (index < 0) { - dev_err(dev, "unsupported reg access %d\n", reg); - return NULL; - } - - if (offset_id && mod) - offset_id *= rsnd_mod_id(mod); - - /* - * index/offset were set on gen1/gen2 - */ - - return gen->base[index] + offset_id + offset_adr; -} - int rsnd_gen_probe(struct platform_device *pdev, struct rcar_snd_info *info, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen; - int i; gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); if (!gen) { @@ -267,14 +337,6 @@ int rsnd_gen_probe(struct platform_device *pdev, priv->gen = gen; - /* - * see - * rsnd_reg_get() - * rsnd_gen_probe() - */ - for (i = 0; i < RSND_REG_MAX; i++) - gen->reg_map[i].index = -1; - return gen->ops->probe(pdev, info, priv); } -- cgit v0.10.2 From 4aa11d67b66a84189d25f301e7ef206c4f541692 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Sep 2013 19:26:08 +0100 Subject: ASoC: tlv320aic23: Convert to direct regmap API usage This moves us towards being able to remove the duplicated register I/O code in ASoC. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 3a6be8c..5d430cc 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -37,11 +38,27 @@ /* * AIC23 register cache */ -static const u16 tlv320aic23_reg[] = { - 0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */ - 0x001A, 0x0004, 0x0007, 0x0001, /* 4 */ - 0x0020, 0x0000, 0x0000, 0x0000, /* 8 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */ +static const struct reg_default tlv320aic23_reg[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x00F9 }, + { 3, 0x00F9 }, + { 4, 0x001A }, + { 5, 0x0004 }, + { 6, 0x0007 }, + { 7, 0x0001 }, + { 8, 0x0020 }, + { 9, 0x0000 }, +}; + +static const struct regmap_config tlv320aic23_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = TLV320AIC23_RESET, + .reg_defaults = tlv320aic23_reg, + .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg), + .cache_type = REGCACHE_RBTREE, }; static const char *rec_src_text[] = { "Line", "Mic" }; @@ -171,7 +188,7 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = { /* AIC23 driver data */ struct aic23 { - enum snd_soc_control_type control_type; + struct regmap *regmap; int mclk; int requested_adc; int requested_dac; @@ -532,7 +549,9 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec) static int tlv320aic23_resume(struct snd_soc_codec *codec) { - snd_soc_cache_sync(codec); + struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); + regcache_mark_dirty(aic23->regmap); + regcache_sync(aic23->regmap); tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; @@ -540,10 +559,9 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec) static int tlv320aic23_probe(struct snd_soc_codec *codec) { - struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -552,16 +570,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec) /* Reset codec */ snd_soc_write(codec, TLV320AIC23_RESET, 0); - /* Write the register default value to cache for reserved registers, - * so the write to the these registers are suppressed by the cache - * restore code when it skips writes of default registers. - */ - snd_soc_cache_write(codec, 0x0A, 0); - snd_soc_cache_write(codec, 0x0B, 0); - snd_soc_cache_write(codec, 0x0C, 0); - snd_soc_cache_write(codec, 0x0D, 0); - snd_soc_cache_write(codec, 0x0E, 0); - /* power on device */ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -596,9 +604,6 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { - .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = tlv320aic23_reg, .probe = tlv320aic23_probe, .remove = tlv320aic23_remove, .suspend = tlv320aic23_suspend, @@ -629,8 +634,11 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c, if (aic23 == NULL) return -ENOMEM; + aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); + if (IS_ERR(aic23->regmap)) + return PTR_ERR(aic23->regmap); + i2c_set_clientdata(i2c, aic23); - aic23->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); -- cgit v0.10.2 From 806955dd9cf071ecd99acbaa8c73ae1f34dcf83d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Sep 2013 13:10:33 +0100 Subject: ASoC: tlv320aic26: Convert to table based control init Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 7b8f3d9..32c6b07 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -377,7 +377,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); static int aic26_probe(struct snd_soc_codec *codec) { struct aic26 *aic26 = dev_get_drvdata(codec->dev); - int ret, err, i, reg; + int ret, i, reg; aic26->codec = codec; @@ -403,12 +403,6 @@ static int aic26_probe(struct snd_soc_codec *codec) if (ret) dev_info(codec->dev, "error creating sysfs files\n"); - /* register controls */ - dev_dbg(codec->dev, "Registering controls\n"); - err = snd_soc_add_codec_controls(codec, aic26_snd_controls, - ARRAY_SIZE(aic26_snd_controls)); - WARN_ON(err < 0); - return 0; } @@ -418,6 +412,8 @@ static struct snd_soc_codec_driver aic26_soc_codec_dev = { .write = aic26_reg_write, .reg_cache_size = AIC26_NUM_REGS, .reg_word_size = sizeof(u16), + .controls = aic26_snd_controls, + .num_controls = ARRAY_SIZE(aic26_snd_controls), .dapm_widgets = tlv320aic26_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets), .dapm_routes = tlv320aic26_dapm_routes, -- cgit v0.10.2 From 5b0959d472c215e6d712ac47e64110bd125ddd07 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Sep 2013 13:14:41 +0100 Subject: ASoC: tlv320aic26: Use snd_soc_update_bits() Use snd_soc_update_bits() rather than open coding. Since the register cache is currently only used where update_bits() is used this means the current register cache can be removed entirely. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 32c6b07..4d82447 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -74,19 +74,6 @@ static unsigned int aic26_reg_read(struct snd_soc_codec *codec, return value; } -static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - if (reg >= AIC26_NUM_REGS) { - WARN_ON_ONCE(1); - return 0; - } - - return cache[reg]; -} - static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -195,19 +182,15 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg); /* Audio Control 3 (master mode, fsref rate) */ - reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3); - reg &= ~0xf800; if (aic26->master) - reg |= 0x0800; + reg = 0x0800; if (fsref == 48000) - reg |= 0x2000; - snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg); + reg = 0x2000; + snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL3, 0xf800, reg); /* Audio Control 1 (FSref divisor) */ - reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1); - reg &= ~0x0fff; - reg |= wlen | aic26->datfm | (divisor << 3) | divisor; - snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg); + reg = wlen | aic26->datfm | (divisor << 3) | divisor; + snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL1, 0xfff, reg); return 0; } @@ -219,16 +202,16 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec); - u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN); + u16 reg; dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n", dai, mute); if (mute) - reg |= 0x8080; + reg = 0x8080; else - reg &= ~0x8080; - snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg); + reg = 0; + snd_soc_update_bits(codec, AIC26_REG_DAC_GAIN, 0x8000, reg); return 0; } @@ -346,7 +329,7 @@ static ssize_t aic26_keyclick_show(struct device *dev, struct aic26 *aic26 = dev_get_drvdata(dev); int val, amp, freq, len; - val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2); + val = snd_soc_read(aic26->codec, AIC26_REG_AUDIO_CTRL2); amp = (val >> 12) & 0x7; freq = (125 << ((val >> 8) & 0x7)) >> 1; len = 2 * (1 + ((val >> 4) & 0xf)); @@ -360,11 +343,9 @@ static ssize_t aic26_keyclick_set(struct device *dev, const char *buf, size_t count) { struct aic26 *aic26 = dev_get_drvdata(dev); - int val; - val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2); - val |= 0x8000; - snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val); + snd_soc_update_bits(aic26->codec, AIC26_REG_AUDIO_CTRL2, + 0x8000, 0x800); return count; } @@ -377,7 +358,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); static int aic26_probe(struct snd_soc_codec *codec) { struct aic26 *aic26 = dev_get_drvdata(codec->dev); - int ret, i, reg; + int ret, reg; aic26->codec = codec; @@ -393,10 +374,6 @@ static int aic26_probe(struct snd_soc_codec *codec) reg |= 0x0800; /* set master mode */ snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg); - /* Fill register cache */ - for (i = 0; i < codec->driver->reg_cache_size; i++) - snd_soc_read(codec, i); - /* Register the sysfs files for debugging */ /* Create SysFS files */ ret = device_create_file(codec->dev, &dev_attr_keyclick); @@ -410,8 +387,6 @@ static struct snd_soc_codec_driver aic26_soc_codec_dev = { .probe = aic26_probe, .read = aic26_reg_read, .write = aic26_reg_write, - .reg_cache_size = AIC26_NUM_REGS, - .reg_word_size = sizeof(u16), .controls = aic26_snd_controls, .num_controls = ARRAY_SIZE(aic26_snd_controls), .dapm_widgets = tlv320aic26_dapm_widgets, -- cgit v0.10.2 From 7fbdeb809050cb958f3baa83dcc643f9a2f287f2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Sep 2013 13:29:44 +0100 Subject: ASoC: tlv320aic26: Convert to direct regmap API usage This moves us towards being able to remove the duplicated register I/O code in ASoC. The datasheet and the driver document the device as having a register map divided into pages but since the paging is actually done by sending the page address and the register address with each transaction this is no different to having a simple register address. The datasheet does also document the low five bits of the 16 bit "command" as unused which we could represent as padding but it seems simpler and less confusing to things that use block transfers or autoincrement to represent these as part of the register address. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 4d82447..94a658f 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -29,6 +29,7 @@ MODULE_LICENSE("GPL"); /* AIC26 driver private data */ struct aic26 { struct spi_device *spi; + struct regmap *regmap; struct snd_soc_codec *codec; int master; int datfm; @@ -40,72 +41,6 @@ struct aic26 { int keyclick_len; }; -/* --------------------------------------------------------------------- - * Register access routines - */ -static unsigned int aic26_reg_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - u16 cmd, value; - u8 buffer[2]; - int rc; - - if (reg >= AIC26_NUM_REGS) { - WARN_ON_ONCE(1); - return 0; - } - - /* Do SPI transfer; first 16bits are command; remaining is - * register contents */ - cmd = AIC26_READ_COMMAND_WORD(reg); - buffer[0] = (cmd >> 8) & 0xff; - buffer[1] = cmd & 0xff; - rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2); - if (rc) { - dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); - return -EIO; - } - value = (buffer[0] << 8) | buffer[1]; - - /* Update the cache before returning with the value */ - cache[reg] = value; - return value; -} - -static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - u16 cmd; - u8 buffer[4]; - int rc; - - if (reg >= AIC26_NUM_REGS) { - WARN_ON_ONCE(1); - return -EINVAL; - } - - /* Do SPI transfer; first 16bits are command; remaining is data - * to write into register */ - cmd = AIC26_WRITE_COMMAND_WORD(reg); - buffer[0] = (cmd >> 8) & 0xff; - buffer[1] = cmd & 0xff; - buffer[2] = value >> 8; - buffer[3] = value; - rc = spi_write(aic26->spi, buffer, 4); - if (rc) { - dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); - return -EIO; - } - - /* update cache before returning */ - cache[reg] = value; - return 0; -} - static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = { SND_SOC_DAPM_INPUT("MICIN"), SND_SOC_DAPM_INPUT("AUX"), @@ -360,6 +295,8 @@ static int aic26_probe(struct snd_soc_codec *codec) struct aic26 *aic26 = dev_get_drvdata(codec->dev); int ret, reg; + snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); + aic26->codec = codec; /* Reset the codec to power on defaults */ @@ -385,8 +322,6 @@ static int aic26_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver aic26_soc_codec_dev = { .probe = aic26_probe, - .read = aic26_reg_read, - .write = aic26_reg_write, .controls = aic26_snd_controls, .num_controls = ARRAY_SIZE(aic26_snd_controls), .dapm_widgets = tlv320aic26_dapm_widgets, @@ -395,6 +330,11 @@ static struct snd_soc_codec_driver aic26_soc_codec_dev = { .num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes), }; +static const struct regmap_config aic26_regmap = { + .reg_bits = 16, + .val_bits = 16, +}; + /* --------------------------------------------------------------------- * SPI device portion of driver: probe and release routines and SPI * driver registration. @@ -411,6 +351,10 @@ static int aic26_spi_probe(struct spi_device *spi) if (!aic26) return -ENOMEM; + aic26->regmap = devm_regmap_init_spi(spi, &aic26_regmap); + if (IS_ERR(aic26->regmap)) + return PTR_ERR(aic26->regmap); + /* Initialize the driver data */ aic26->spi = spi; dev_set_drvdata(&spi->dev, aic26); diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h index 67f19c3..629b85e 100644 --- a/sound/soc/codecs/tlv320aic26.h +++ b/sound/soc/codecs/tlv320aic26.h @@ -9,10 +9,7 @@ #define _TLV320AIC16_H_ /* AIC26 Registers */ -#define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5)) -#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5)) -#define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset) -#define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0) +#define AIC26_PAGE_ADDR(page, offset) ((page << 11) | offset << 5) /* Page 0: Auxiliary data registers */ #define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05) -- cgit v0.10.2 From c29c2d4e6ba4f8f5868a4c6dd75a4c23e1993721 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 19:14:31 +0100 Subject: mfd: mc13xxx: Don't require lock for simple register I/O Since the conversion to regmap there has been no need for device level locking for I/O as regmap provides locking so remove the locks. Signed-off-by: Mark Brown Signed-off-by: Lee Jones diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 2a9b100..dbbf8ee 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -158,8 +158,6 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) { int ret; - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); - if (offset > MC13XXX_NUMREGS) return -EINVAL; @@ -172,8 +170,6 @@ EXPORT_SYMBOL(mc13xxx_reg_read); int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) { - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); - dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val); if (offset > MC13XXX_NUMREGS || val > 0xffffff) @@ -186,7 +182,6 @@ EXPORT_SYMBOL(mc13xxx_reg_write); int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, u32 mask, u32 val) { - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); BUG_ON(val & ~mask); dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n", offset, val, mask); -- cgit v0.10.2 From fd792f8fbcfa95674b6c417429f576ad1d808086 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Sep 2013 19:14:32 +0100 Subject: mfd: mc13xxx: Move SPI erratum workaround into SPI I/O function Move the workaround for double sending AUDIO_CODEC and AUDIO_DAC writes into the SPI core, aiding refactoring to eliminate the ASoC custom I/O functions and avoiding the extra writes for I2C. Signed-off-by: Mark Brown Signed-off-by: Lee Jones diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 77189da..5f14ef6 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -94,10 +94,15 @@ static int mc13xxx_spi_write(void *context, const void *data, size_t count) { struct device *dev = context; struct spi_device *spi = to_spi_device(dev); + const char *reg = data; if (count != 4) return -ENOTSUPP; + /* include errata fix for spi audio problems */ + if (*reg == MC13783_AUDIO_CODEC || *reg == MC13783_AUDIO_DAC) + spi_write(spi, data, count); + return spi_write(spi, data, count); } diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index 41ed592..67c17b5 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -41,6 +41,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, unsigned int channel, u8 ato, bool atox, unsigned int *sample); +#define MC13783_AUDIO_RX0 36 +#define MC13783_AUDIO_RX1 37 +#define MC13783_AUDIO_TX 38 +#define MC13783_SSI_NETWORK 39 +#define MC13783_AUDIO_CODEC 40 +#define MC13783_AUDIO_DAC 41 + #define MC13XXX_IRQ_ADCDONE 0 #define MC13XXX_IRQ_ADCBISDONE 1 #define MC13XXX_IRQ_TS 2 diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index ea141e1..4d3c8fd 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -125,10 +125,6 @@ static int mc13783_write(struct snd_soc_codec *codec, ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - /* include errata fix for spi audio problems */ - if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC) - ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - mc13xxx_unlock(priv->mc13xxx); return ret; -- cgit v0.10.2 From 2d9215c1ecd6f133952bc081a288dbb180816290 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 18 Sep 2013 19:04:17 +0100 Subject: ASoC: mc13783: Use regmap directly from ASoC As part of a push to remove the register I/O functionality from ASoC (since it is now duplicated in the regmap API) convert the mc13783 driver to use regmap directly. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 4d3c8fd..eedbf05 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -30,16 +30,10 @@ #include #include #include +#include #include "mc13783.h" -#define MC13783_AUDIO_RX0 36 -#define MC13783_AUDIO_RX1 37 -#define MC13783_AUDIO_TX 38 -#define MC13783_SSI_NETWORK 39 -#define MC13783_AUDIO_CODEC 40 -#define MC13783_AUDIO_DAC 41 - #define AUDIO_RX0_ALSPEN (1 << 5) #define AUDIO_RX0_ALSPSEL (1 << 7) #define AUDIO_RX0_ADDCDC (1 << 21) @@ -95,41 +89,12 @@ struct mc13783_priv { struct mc13xxx *mc13xxx; + struct regmap *regmap; enum mc13783_ssi_port adc_ssi_port; enum mc13783_ssi_port dac_ssi_port; }; -static unsigned int mc13783_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); - unsigned int value = 0; - - mc13xxx_lock(priv->mc13xxx); - - mc13xxx_reg_read(priv->mc13xxx, reg, &value); - - mc13xxx_unlock(priv->mc13xxx); - - return value; -} - -static int mc13783_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - mc13xxx_lock(priv->mc13xxx); - - ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - - mc13xxx_unlock(priv->mc13xxx); - - return ret; -} - /* Mapping between sample rates and register value */ static unsigned int mc13783_rates[] = { 8000, 11025, 12000, 16000, @@ -583,8 +548,14 @@ static struct snd_kcontrol_new mc13783_control_list[] = { static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; - mc13xxx_lock(priv->mc13xxx); + codec->control_data = dev_get_regmap(codec->dev->parent, NULL); + ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } /* these are the reset values */ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893); @@ -608,8 +579,6 @@ static int mc13783_probe(struct snd_soc_codec *codec) mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, 0, AUDIO_SSI_SEL); - mc13xxx_unlock(priv->mc13xxx); - return 0; } @@ -617,13 +586,9 @@ static int mc13783_remove(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); - mc13xxx_lock(priv->mc13xxx); - /* Make sure VAUDIOON is off */ mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0); - mc13xxx_unlock(priv->mc13xxx); - return 0; } @@ -713,8 +678,6 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = { static struct snd_soc_codec_driver soc_codec_dev_mc13783 = { .probe = mc13783_probe, .remove = mc13783_remove, - .read = mc13783_read, - .write = mc13783_write, .controls = mc13783_control_list, .num_controls = ARRAY_SIZE(mc13783_control_list), .dapm_widgets = mc13783_dapm_widgets, -- cgit v0.10.2 From 83cbe35b874621a23ca468621c0d833b76a1b8de Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Sep 2013 19:22:54 +0100 Subject: ASoC: sn95031: Convert to regmap This moves us towards being able to remove the duplicated register I/O functionality in ASoC. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index dba26e63..13045f2 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -164,30 +164,28 @@ static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec) } /*end - adc helper functions */ -static inline unsigned int sn95031_read(struct snd_soc_codec *codec, - unsigned int reg) +static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val) { u8 value = 0; int ret; ret = intel_scu_ipc_ioread8(reg, &value); - if (ret) - pr_err("read of %x failed, err %d\n", reg, ret); - return value; + if (ret == 0) + *val = value; + return ret; } -static inline int sn95031_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static int sn95031_write(void *ctx, unsigned int reg, unsigned int value) { - int ret; - - ret = intel_scu_ipc_iowrite8(reg, value); - if (ret) - pr_err("write of %x failed, err %d\n", reg, ret); - return ret; + return intel_scu_ipc_iowrite8(reg, value); } +static const struct regmap_config sn95031_regmap = { + .reg_read = sn95031_read, + .reg_write = sn95031_write, +}; + static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -827,6 +825,8 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) { pr_debug("codec_probe called\n"); + snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); + /* PCM interface config * This sets the pcm rx slot conguration to max 6 slots * for max 4 dais (2 stereo and 2 mono) @@ -886,8 +886,6 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver sn95031_codec = { .probe = sn95031_codec_probe, .remove = sn95031_codec_remove, - .read = sn95031_read, - .write = sn95031_write, .set_bias_level = sn95031_set_vaud_bias, .idle_bias_off = true, .dapm_widgets = sn95031_dapm_widgets, @@ -898,7 +896,14 @@ static struct snd_soc_codec_driver sn95031_codec = { static int sn95031_device_probe(struct platform_device *pdev) { + struct regmap *regmap; + pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev)); + + regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + return snd_soc_register_codec(&pdev->dev, &sn95031_codec, sn95031_dais, ARRAY_SIZE(sn95031_dais)); } -- cgit v0.10.2 From 752b776435cb35da27a0bbec8deecc33b3461288 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Sep 2013 11:36:26 +0100 Subject: ASoC: tlv320aic32x4: Move GPIO acquisition to I2C probe This is more idiomatic and interacts better with deferred probe. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 2ed57d4..cf70bf8 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -617,16 +617,11 @@ static int aic32x4_probe(struct snd_soc_codec *codec) { struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); u32 tmp_reg; - int ret; codec->hw_write = (hw_write_t) i2c_master_send; codec->control_data = aic32x4->control_data; if (aic32x4->rstn_gpio >= 0) { - ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio, - GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); - if (ret != 0) - return ret; ndelay(10); gpio_set_value(aic32x4->rstn_gpio, 1); } @@ -735,6 +730,13 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; } + if (aic32x4->rstn_gpio >= 0) { + ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, + GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); + if (ret != 0) + return ret; + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic32x4, &aic32x4_dai, 1); return ret; -- cgit v0.10.2 From 4d208ca429ad424595fd08c0cca323605ebfc38b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Sep 2013 11:37:53 +0100 Subject: ASoC: tlv320aic32x4: Convert to direct regmap API usage This moves us towards being able to remove the duplicate register I/O functionality in ASoC and saves some code. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index cf70bf8..18cdcca 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -60,9 +60,8 @@ struct aic32x4_rate_divs { }; struct aic32x4_priv { + struct regmap *regmap; u32 sysclk; - u8 page_no; - void *control_data; u32 power_cfg; u32 micpga_routing; bool swapdacs; @@ -262,67 +261,25 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { {"Right ADC", NULL, "Right Input Mixer"}, }; -static inline int aic32x4_change_page(struct snd_soc_codec *codec, - unsigned int new_page) -{ - struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); - u8 data[2]; - int ret; - - data[0] = 0x00; - data[1] = new_page & 0xff; - - ret = codec->hw_write(codec->control_data, data, 2); - if (ret == 2) { - aic32x4->page_no = new_page; - return 0; - } else { - return ret; - } -} - -static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); - unsigned int page = reg / 128; - unsigned int fixed_reg = reg % 128; - u8 data[2]; - int ret; - - /* A write to AIC32X4_PSEL is really a non-explicit page change */ - if (reg == AIC32X4_PSEL) - return aic32x4_change_page(codec, val); - - if (aic32x4->page_no != page) { - ret = aic32x4_change_page(codec, page); - if (ret != 0) - return ret; - } +static const struct regmap_range_cfg aic32x4_regmap_pages[] = { + { + .selector_reg = 0, + .selector_mask = 0xff, + .window_start = 0, + .window_len = 128, + .range_min = AIC32X4_PAGE1, + .range_max = AIC32X4_PAGE1 + 127, + }, +}; - data[0] = fixed_reg & 0xff; - data[1] = val & 0xff; +static const struct regmap_config aic32x4_regmap = { + .reg_bits = 8, + .val_bits = 8, - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg) -{ - struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); - unsigned int page = reg / 128; - unsigned int fixed_reg = reg % 128; - int ret; - - if (aic32x4->page_no != page) { - ret = aic32x4_change_page(codec, page); - if (ret != 0) - return ret; - } - return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff); -} + .max_register = AIC32X4_RMICPGAVOL, + .ranges = aic32x4_regmap_pages, + .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), +}; static inline int aic32x4_get_divs(int mclk, int rate) { @@ -618,8 +575,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec) struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); u32 tmp_reg; - codec->hw_write = (hw_write_t) i2c_master_send; - codec->control_data = aic32x4->control_data; + snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (aic32x4->rstn_gpio >= 0) { ndelay(10); @@ -687,8 +643,6 @@ static int aic32x4_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { - .read = aic32x4_read, - .write = aic32x4_write, .probe = aic32x4_probe, .remove = aic32x4_remove, .suspend = aic32x4_suspend, @@ -715,7 +669,10 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, if (aic32x4 == NULL) return -ENOMEM; - aic32x4->control_data = i2c; + aic32x4->regmap = devm_regmap_init_i2c(i2c, &aic32x4_regmap); + if (IS_ERR(aic32x4->regmap)) + return PTR_ERR(aic32x4->regmap); + i2c_set_clientdata(i2c, aic32x4); if (pdata) { -- cgit v0.10.2 From ce3d060990cd799cef4eeffc290090fb5da15e94 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Thu, 19 Sep 2013 11:20:43 +0200 Subject: ASoc: kirkwood: Extend the min and max number of bytes per period This patch extends the min and max number of bytes per period. It mainly permits to reduce the sound delay in MIDI real-time playing. Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index f8e1ccc..bf23afb 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h @@ -123,8 +123,8 @@ /* need to find where they come from */ #define KIRKWOOD_SND_MIN_PERIODS 8 #define KIRKWOOD_SND_MAX_PERIODS 16 -#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000 -#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 +#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x800 +#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000 #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ * KIRKWOOD_SND_MAX_PERIODS) -- cgit v0.10.2 From 3a429eea10ded31d2ff088432d02072165a099f1 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 20 Sep 2013 15:54:54 -0700 Subject: ASoC: atmel-pcm: fix warning i386 allmodconfig: sound/soc/atmel/atmel-pcm.c: In function 'atmel_pcm_preallocate_dma_buffer': sound/soc/atmel/atmel-pcm.c:52: warning: cast to pointer from integer of different size Signed-off-by: Andrew Morton Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 3109db7..612e580 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -50,7 +50,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, buf->area = dma_alloc_coherent(pcm->card->dev, size, &buf->addr, GFP_KERNEL); pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n", - (void *)buf->area, (void *)buf->addr, size); + (void *)buf->area, (void *)(long)buf->addr, size); if (!buf->area) return -ENOMEM; -- cgit v0.10.2 From d60336e2f136287de821901d4a1b56179a0f7b69 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 23 Sep 2013 11:36:21 +0800 Subject: ASoC: fsl_ssi: let check zero instead of check NO_IRQ NO_IRQ may be defined as '(unsigned int) -1' in some architectures (arm, sh ...), and either may not be defined in some architectures which can enable SND_SOC_FSL_SSI (e.g. allmodconfig for arc). When irq_of_parse_and_map() fails, it will always return 0, so need check zero instead of NO_IRQ, or will cause compiling issue or run time bug in some architectures. Signed-off-by: Chen Gang Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index cdbb641..35e2773 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -929,7 +929,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi_private->ssi_phys = res.start; ssi_private->irq = irq_of_parse_and_map(np, 0); - if (ssi_private->irq == NO_IRQ) { + if (!ssi_private->irq) { dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); return -ENXIO; } -- cgit v0.10.2 From d6173df35f2dbd0e11f2361fc979ebf2e53cb6cc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Sep 2013 19:36:11 +0100 Subject: ASoC: si476x: Remove custom register I/O implementation The current si476x I/O implementation wraps the regmap for the core with functions that make the register map cache only when the device is powered down. This implementation appears to be incomplete since there is no code to synchronise the cache so writes done while the core is powered down will be ignored, the device will only be configured if it is powered. A better and more idiomatic approach would be to have the MFD manage the cache, making the device cache only when it powers things down. This also allows ASoC to use the standard regmap helpers for the device which helps remove the ASoC custom ones so do convert to do that. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 38f3b10..03645ce 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -60,48 +60,6 @@ enum si476x_pcm_format { SI476X_PCM_FORMAT_S24_LE = 6, }; -static unsigned int si476x_codec_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - int err; - unsigned int val; - struct si476x_core *core = codec->control_data; - - si476x_core_lock(core); - if (!si476x_core_is_powered_up(core)) - regcache_cache_only(core->regmap, true); - - err = regmap_read(core->regmap, reg, &val); - - if (!si476x_core_is_powered_up(core)) - regcache_cache_only(core->regmap, false); - si476x_core_unlock(core); - - if (err < 0) - return err; - - return val; -} - -static int si476x_codec_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val) -{ - int err; - struct si476x_core *core = codec->control_data; - - si476x_core_lock(core); - if (!si476x_core_is_powered_up(core)) - regcache_cache_only(core->regmap, true); - - err = regmap_write(core->regmap, reg, val); - - if (!si476x_core_is_powered_up(core)) - regcache_cache_only(core->regmap, false); - si476x_core_unlock(core); - - return err; -} - static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("LOUT"), SND_SOC_DAPM_OUTPUT("ROUT"), @@ -239,7 +197,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, static int si476x_codec_probe(struct snd_soc_codec *codec) { - codec->control_data = i2c_mfd_cell_to_core(codec->dev); + codec->control_data = dev_get_regmap(codec->dev->parent, NULL); return 0; } @@ -268,8 +226,6 @@ static struct snd_soc_dai_driver si476x_dai = { static struct snd_soc_codec_driver soc_codec_dev_si476x = { .probe = si476x_codec_probe, - .read = si476x_codec_read, - .write = si476x_codec_write, .dapm_widgets = si476x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), .dapm_routes = si476x_dapm_routes, -- cgit v0.10.2 From c3df37c9380d70f19a9cb2de4c7d58d7822a4b35 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Sep 2013 13:47:08 +0200 Subject: ASoC: adau1373: Convert to direct regmap usage Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1aa10dd..c57c1f8 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -32,6 +32,7 @@ struct adau1373_dai { }; struct adau1373 { + struct regmap *regmap; struct adau1373_dai dais[3]; }; @@ -152,37 +153,172 @@ struct adau1373 { #define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4 #define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2 -static const uint8_t adau1373_default_regs[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x30 */ - 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, /* 0x40 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x80 */ - 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, - 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x90 */ - 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, - 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0xa0 */ - 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, /* 0xe0 */ - 0x00, 0x1f, 0x0f, 0x00, 0x00, +static const struct reg_default adau1373_reg_defaults[] = { + { ADAU1373_INPUT_MODE, 0x00 }, + { ADAU1373_AINL_CTRL(0), 0x00 }, + { ADAU1373_AINR_CTRL(0), 0x00 }, + { ADAU1373_AINL_CTRL(1), 0x00 }, + { ADAU1373_AINR_CTRL(1), 0x00 }, + { ADAU1373_AINL_CTRL(2), 0x00 }, + { ADAU1373_AINR_CTRL(2), 0x00 }, + { ADAU1373_AINL_CTRL(3), 0x00 }, + { ADAU1373_AINR_CTRL(3), 0x00 }, + { ADAU1373_LLINE_OUT(0), 0x00 }, + { ADAU1373_RLINE_OUT(0), 0x00 }, + { ADAU1373_LLINE_OUT(1), 0x00 }, + { ADAU1373_RLINE_OUT(1), 0x00 }, + { ADAU1373_LSPK_OUT, 0x00 }, + { ADAU1373_RSPK_OUT, 0x00 }, + { ADAU1373_LHP_OUT, 0x00 }, + { ADAU1373_RHP_OUT, 0x00 }, + { ADAU1373_ADC_GAIN, 0x00 }, + { ADAU1373_LADC_MIXER, 0x00 }, + { ADAU1373_RADC_MIXER, 0x00 }, + { ADAU1373_LLINE1_MIX, 0x00 }, + { ADAU1373_RLINE1_MIX, 0x00 }, + { ADAU1373_LLINE2_MIX, 0x00 }, + { ADAU1373_RLINE2_MIX, 0x00 }, + { ADAU1373_LSPK_MIX, 0x00 }, + { ADAU1373_RSPK_MIX, 0x00 }, + { ADAU1373_LHP_MIX, 0x00 }, + { ADAU1373_RHP_MIX, 0x00 }, + { ADAU1373_EP_MIX, 0x00 }, + { ADAU1373_HP_CTRL, 0x00 }, + { ADAU1373_HP_CTRL2, 0x00 }, + { ADAU1373_LS_CTRL, 0x00 }, + { ADAU1373_EP_CTRL, 0x00 }, + { ADAU1373_MICBIAS_CTRL1, 0x00 }, + { ADAU1373_MICBIAS_CTRL2, 0x00 }, + { ADAU1373_OUTPUT_CTRL, 0x00 }, + { ADAU1373_PWDN_CTRL1, 0x00 }, + { ADAU1373_PWDN_CTRL2, 0x00 }, + { ADAU1373_PWDN_CTRL3, 0x00 }, + { ADAU1373_DPLL_CTRL(0), 0x00 }, + { ADAU1373_PLL_CTRL1(0), 0x00 }, + { ADAU1373_PLL_CTRL2(0), 0x00 }, + { ADAU1373_PLL_CTRL3(0), 0x00 }, + { ADAU1373_PLL_CTRL4(0), 0x00 }, + { ADAU1373_PLL_CTRL5(0), 0x00 }, + { ADAU1373_PLL_CTRL6(0), 0x02 }, + { ADAU1373_DPLL_CTRL(1), 0x00 }, + { ADAU1373_PLL_CTRL1(1), 0x00 }, + { ADAU1373_PLL_CTRL2(1), 0x00 }, + { ADAU1373_PLL_CTRL3(1), 0x00 }, + { ADAU1373_PLL_CTRL4(1), 0x00 }, + { ADAU1373_PLL_CTRL5(1), 0x00 }, + { ADAU1373_PLL_CTRL6(1), 0x02 }, + { ADAU1373_HEADDECT, 0x00 }, + { ADAU1373_ADC_CTRL, 0x00 }, + { ADAU1373_CLK_SRC_DIV(0), 0x00 }, + { ADAU1373_CLK_SRC_DIV(1), 0x00 }, + { ADAU1373_DAI(0), 0x0a }, + { ADAU1373_DAI(1), 0x0a }, + { ADAU1373_DAI(2), 0x0a }, + { ADAU1373_BCLKDIV(0), 0x00 }, + { ADAU1373_BCLKDIV(1), 0x00 }, + { ADAU1373_BCLKDIV(2), 0x00 }, + { ADAU1373_SRC_RATIOA(0), 0x00 }, + { ADAU1373_SRC_RATIOB(0), 0x00 }, + { ADAU1373_SRC_RATIOA(1), 0x00 }, + { ADAU1373_SRC_RATIOB(1), 0x00 }, + { ADAU1373_SRC_RATIOA(2), 0x00 }, + { ADAU1373_SRC_RATIOB(2), 0x00 }, + { ADAU1373_DEEMP_CTRL, 0x00 }, + { ADAU1373_SRC_DAI_CTRL(0), 0x08 }, + { ADAU1373_SRC_DAI_CTRL(1), 0x08 }, + { ADAU1373_SRC_DAI_CTRL(2), 0x08 }, + { ADAU1373_DIN_MIX_CTRL(0), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(1), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(2), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(3), 0x00 }, + { ADAU1373_DIN_MIX_CTRL(4), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(0), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(1), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(2), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(3), 0x00 }, + { ADAU1373_DOUT_MIX_CTRL(4), 0x00 }, + { ADAU1373_DAI_PBL_VOL(0), 0x00 }, + { ADAU1373_DAI_PBR_VOL(0), 0x00 }, + { ADAU1373_DAI_PBL_VOL(1), 0x00 }, + { ADAU1373_DAI_PBR_VOL(1), 0x00 }, + { ADAU1373_DAI_PBL_VOL(2), 0x00 }, + { ADAU1373_DAI_PBR_VOL(2), 0x00 }, + { ADAU1373_DAI_RECL_VOL(0), 0x00 }, + { ADAU1373_DAI_RECR_VOL(0), 0x00 }, + { ADAU1373_DAI_RECL_VOL(1), 0x00 }, + { ADAU1373_DAI_RECR_VOL(1), 0x00 }, + { ADAU1373_DAI_RECL_VOL(2), 0x00 }, + { ADAU1373_DAI_RECR_VOL(2), 0x00 }, + { ADAU1373_DAC1_PBL_VOL, 0x00 }, + { ADAU1373_DAC1_PBR_VOL, 0x00 }, + { ADAU1373_DAC2_PBL_VOL, 0x00 }, + { ADAU1373_DAC2_PBR_VOL, 0x00 }, + { ADAU1373_ADC_RECL_VOL, 0x00 }, + { ADAU1373_ADC_RECR_VOL, 0x00 }, + { ADAU1373_DMIC_RECL_VOL, 0x00 }, + { ADAU1373_DMIC_RECR_VOL, 0x00 }, + { ADAU1373_VOL_GAIN1, 0x00 }, + { ADAU1373_VOL_GAIN2, 0x00 }, + { ADAU1373_VOL_GAIN3, 0x00 }, + { ADAU1373_HPF_CTRL, 0x00 }, + { ADAU1373_BASS1, 0x00 }, + { ADAU1373_BASS2, 0x00 }, + { ADAU1373_DRC(0) + 0x0, 0x78 }, + { ADAU1373_DRC(0) + 0x1, 0x18 }, + { ADAU1373_DRC(0) + 0x2, 0x00 }, + { ADAU1373_DRC(0) + 0x3, 0x00 }, + { ADAU1373_DRC(0) + 0x4, 0x00 }, + { ADAU1373_DRC(0) + 0x5, 0xc0 }, + { ADAU1373_DRC(0) + 0x6, 0x00 }, + { ADAU1373_DRC(0) + 0x7, 0x00 }, + { ADAU1373_DRC(0) + 0x8, 0x00 }, + { ADAU1373_DRC(0) + 0x9, 0xc0 }, + { ADAU1373_DRC(0) + 0xa, 0x88 }, + { ADAU1373_DRC(0) + 0xb, 0x7a }, + { ADAU1373_DRC(0) + 0xc, 0xdf }, + { ADAU1373_DRC(0) + 0xd, 0x20 }, + { ADAU1373_DRC(0) + 0xe, 0x00 }, + { ADAU1373_DRC(0) + 0xf, 0x00 }, + { ADAU1373_DRC(1) + 0x0, 0x78 }, + { ADAU1373_DRC(1) + 0x1, 0x18 }, + { ADAU1373_DRC(1) + 0x2, 0x00 }, + { ADAU1373_DRC(1) + 0x3, 0x00 }, + { ADAU1373_DRC(1) + 0x4, 0x00 }, + { ADAU1373_DRC(1) + 0x5, 0xc0 }, + { ADAU1373_DRC(1) + 0x6, 0x00 }, + { ADAU1373_DRC(1) + 0x7, 0x00 }, + { ADAU1373_DRC(1) + 0x8, 0x00 }, + { ADAU1373_DRC(1) + 0x9, 0xc0 }, + { ADAU1373_DRC(1) + 0xa, 0x88 }, + { ADAU1373_DRC(1) + 0xb, 0x7a }, + { ADAU1373_DRC(1) + 0xc, 0xdf }, + { ADAU1373_DRC(1) + 0xd, 0x20 }, + { ADAU1373_DRC(1) + 0xe, 0x00 }, + { ADAU1373_DRC(1) + 0xf, 0x00 }, + { ADAU1373_DRC(2) + 0x0, 0x78 }, + { ADAU1373_DRC(2) + 0x1, 0x18 }, + { ADAU1373_DRC(2) + 0x2, 0x00 }, + { ADAU1373_DRC(2) + 0x3, 0x00 }, + { ADAU1373_DRC(2) + 0x4, 0x00 }, + { ADAU1373_DRC(2) + 0x5, 0xc0 }, + { ADAU1373_DRC(2) + 0x6, 0x00 }, + { ADAU1373_DRC(2) + 0x7, 0x00 }, + { ADAU1373_DRC(2) + 0x8, 0x00 }, + { ADAU1373_DRC(2) + 0x9, 0xc0 }, + { ADAU1373_DRC(2) + 0xa, 0x88 }, + { ADAU1373_DRC(2) + 0xb, 0x7a }, + { ADAU1373_DRC(2) + 0xc, 0xdf }, + { ADAU1373_DRC(2) + 0xd, 0x20 }, + { ADAU1373_DRC(2) + 0xe, 0x00 }, + { ADAU1373_DRC(2) + 0xf, 0x00 }, + { ADAU1373_3D_CTRL1, 0x00 }, + { ADAU1373_3D_CTRL2, 0x00 }, + { ADAU1373_FDSP_SEL1, 0x00 }, + { ADAU1373_FDSP_SEL2, 0x00 }, + { ADAU1373_FDSP_SEL2, 0x00 }, + { ADAU1373_FDSP_SEL4, 0x00 }, + { ADAU1373_DIGMICCTRL, 0x00 }, + { ADAU1373_DIGEN, 0x00 }, }; static const unsigned int adau1373_out_tlv[] = { @@ -418,6 +554,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int pll_id = w->name[3] - '1'; unsigned int val; @@ -426,7 +563,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w, else val = 0; - snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), + regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id), ADAU1373_PLL_CTRL6_PLL_EN, val); if (SND_SOC_DAPM_EVENT_ON(event)) @@ -938,7 +1075,7 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream, adau1373_dai->enable_src = (div != 0); - snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id), + regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id), ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK, (div << 2) | ADAU1373_BCLKDIV_64); @@ -959,7 +1096,7 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return snd_soc_update_bits(codec, ADAU1373_DAI(dai->id), + return regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id), ADAU1373_DAI_WLEN_MASK, ctrl); } @@ -1016,7 +1153,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - snd_soc_update_bits(codec, ADAU1373_DAI(dai->id), + regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id), ~ADAU1373_DAI_WLEN_MASK, ctrl); return 0; @@ -1039,7 +1176,7 @@ static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai, adau1373_dai->sysclk = freq; adau1373_dai->clk_src = clk_id; - snd_soc_update_bits(dai->codec, ADAU1373_BCLKDIV(dai->id), + regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id), ADAU1373_BCLKDIV_SOURCE, clk_id << 5); return 0; @@ -1120,6 +1257,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = { static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int dpll_div = 0; unsigned int x, r, n, m, i, j, mode; @@ -1187,36 +1325,36 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, if (dpll_div) { dpll_div = 11 - dpll_div; - snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), + regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id), ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0); } else { - snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id), + regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id), ADAU1373_PLL_CTRL6_DPLL_BYPASS, ADAU1373_PLL_CTRL6_DPLL_BYPASS); } - snd_soc_write(codec, ADAU1373_DPLL_CTRL(pll_id), + regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id), (source << 4) | dpll_div); - snd_soc_write(codec, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); - snd_soc_write(codec, ADAU1373_PLL_CTRL5(pll_id), + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); + regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), (r << 3) | (x << 1) | mode); /* Set sysclk to pll_rate / 4 */ - snd_soc_update_bits(codec, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); + regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); return 0; } -static void adau1373_load_drc_settings(struct snd_soc_codec *codec, +static void adau1373_load_drc_settings(struct adau1373 *adau1373, unsigned int nr, uint8_t *drc) { unsigned int i; for (i = 0; i < ADAU1373_DRC_SIZE; ++i) - snd_soc_write(codec, ADAU1373_DRC(nr) + i, drc[i]); + regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]); } static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) @@ -1235,13 +1373,14 @@ static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) static int adau1373_probe(struct snd_soc_codec *codec) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); struct adau1373_platform_data *pdata = codec->dev->platform_data; bool lineout_differential = false; unsigned int val; int ret; int i; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); if (ret) { dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); return ret; @@ -1256,7 +1395,7 @@ static int adau1373_probe(struct snd_soc_codec *codec) return -EINVAL; for (i = 0; i < pdata->num_drc; ++i) { - adau1373_load_drc_settings(codec, i, + adau1373_load_drc_settings(adau1373, i, pdata->drc_setting[i]); } @@ -1268,18 +1407,18 @@ static int adau1373_probe(struct snd_soc_codec *codec) if (pdata->input_differential[i]) val |= BIT(i); } - snd_soc_write(codec, ADAU1373_INPUT_MODE, val); + regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val); val = 0; if (pdata->lineout_differential) val |= ADAU1373_OUTPUT_CTRL_LDIFF; if (pdata->lineout_ground_sense) val |= ADAU1373_OUTPUT_CTRL_LNFBEN; - snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val); + regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val); lineout_differential = pdata->lineout_differential; - snd_soc_write(codec, ADAU1373_EP_CTRL, + regmap_write(adau1373->regmap, ADAU1373_EP_CTRL, (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) | (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET)); } @@ -1289,7 +1428,7 @@ static int adau1373_probe(struct snd_soc_codec *codec) ARRAY_SIZE(adau1373_lineout2_controls)); } - snd_soc_write(codec, ADAU1373_ADC_CTRL, + regmap_write(adau1373->regmap, ADAU1373_ADC_CTRL, ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT); return 0; @@ -1298,17 +1437,19 @@ static int adau1373_probe(struct snd_soc_codec *codec) static int adau1373_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3, + regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3, ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3, + regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3, ADAU1373_PWDN_CTRL3_PWR_EN, 0); break; } @@ -1324,17 +1465,49 @@ static int adau1373_remove(struct snd_soc_codec *codec) static int adau1373_suspend(struct snd_soc_codec *codec) { - return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_cache_only(adau1373->regmap, true); + + return ret; } static int adau1373_resume(struct snd_soc_codec *codec) { + struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(adau1373->regmap, false); adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_cache_sync(codec); + regcache_sync(adau1373->regmap); return 0; } +static bool adau1373_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADAU1373_SOFT_RESET: + case ADAU1373_ADC_DAC_STATUS: + return true; + default: + return false; + } +} + +static const struct regmap_config adau1373_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + + .volatile_reg = adau1373_register_volatile, + .max_register = ADAU1373_SOFT_RESET, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adau1373_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults), +}; + static struct snd_soc_codec_driver adau1373_codec_driver = { .probe = adau1373_probe, .remove = adau1373_remove, @@ -1342,9 +1515,6 @@ static struct snd_soc_codec_driver adau1373_codec_driver = { .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ARRAY_SIZE(adau1373_default_regs), - .reg_cache_default = adau1373_default_regs, - .reg_word_size = sizeof(uint8_t), .set_pll = adau1373_set_pll, @@ -1366,6 +1536,11 @@ static int adau1373_i2c_probe(struct i2c_client *client, if (!adau1373) return -ENOMEM; + adau1373->regmap = devm_regmap_init_i2c(client, + &adau1373_regmap_config); + if (IS_ERR(adau1373->regmap)) + return PTR_ERR(adau1373->regmap); + dev_set_drvdata(&client->dev, adau1373); ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver, -- cgit v0.10.2 From 6fb04138a3068609fa0ef3a98b60e31e686b3160 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Sep 2013 13:47:09 +0200 Subject: ASoC: adau1373: Remove ADAU1373_PLL_CTRL7 register definition There is no such register. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index c57c1f8..2f84054 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -74,7 +74,6 @@ struct adau1373 { #define ADAU1373_PLL_CTRL4(x) (0x2c + (x) * 7) #define ADAU1373_PLL_CTRL5(x) (0x2d + (x) * 7) #define ADAU1373_PLL_CTRL6(x) (0x2e + (x) * 7) -#define ADAU1373_PLL_CTRL7(x) (0x2f + (x) * 7) #define ADAU1373_HEADDECT 0x36 #define ADAU1373_ADC_DAC_STATUS 0x37 #define ADAU1373_ADC_CTRL 0x3c -- cgit v0.10.2 From 729485f6adbf1c7e1e08a01d2c276da30a91b0a4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Sep 2013 13:47:10 +0200 Subject: ASoC: adau1373: Issue soft reset on probe Reset the device on probe to make sure that the register settings match the register cache defaults. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 2f84054..59654b1 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1540,6 +1540,8 @@ static int adau1373_i2c_probe(struct i2c_client *client, if (IS_ERR(adau1373->regmap)) return PTR_ERR(adau1373->regmap); + regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); + dev_set_drvdata(&client->dev, adau1373); ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver, -- cgit v0.10.2 From 2560b3d1bdf1344aa65bba1523a08e4db27a3c14 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Sep 2013 15:18:25 +0200 Subject: ASoC: adav80x: Convert to direct regmap usage Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 15b012d0..14a7c16 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -115,22 +115,34 @@ #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) -static u8 adav80x_default_regs[] = { - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, - 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, - 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, - 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, - 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, - 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, +static struct reg_default adav80x_reg_defaults[] = { + { ADAV80X_PLAYBACK_CTRL, 0x01 }, + { ADAV80X_AUX_IN_CTRL, 0x01 }, + { ADAV80X_REC_CTRL, 0x02 }, + { ADAV80X_AUX_OUT_CTRL, 0x01 }, + { ADAV80X_DPATH_CTRL1, 0xc0 }, + { ADAV80X_DPATH_CTRL2, 0x11 }, + { ADAV80X_DAC_CTRL1, 0x00 }, + { ADAV80X_DAC_CTRL2, 0x00 }, + { ADAV80X_DAC_CTRL3, 0x00 }, + { ADAV80X_DAC_L_VOL, 0xff }, + { ADAV80X_DAC_R_VOL, 0xff }, + { ADAV80X_PGA_L_VOL, 0x00 }, + { ADAV80X_PGA_R_VOL, 0x00 }, + { ADAV80X_ADC_CTRL1, 0x00 }, + { ADAV80X_ADC_CTRL2, 0x00 }, + { ADAV80X_ADC_L_VOL, 0xff }, + { ADAV80X_ADC_R_VOL, 0xff }, + { ADAV80X_PLL_CTRL1, 0x00 }, + { ADAV80X_PLL_CTRL2, 0x00 }, + { ADAV80X_ICLK_CTRL1, 0x00 }, + { ADAV80X_ICLK_CTRL2, 0x00 }, + { ADAV80X_PLL_CLK_SRC, 0x00 }, + { ADAV80X_PLL_OUTE, 0x00 }, }; struct adav80x { - enum snd_soc_control_type control_type; + struct regmap *regmap; enum adav80x_clk_src clk_src; unsigned int sysclk; @@ -298,7 +310,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec) val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; } - return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, + return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2, ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); } @@ -394,10 +406,11 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], + regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0], ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, capture); - snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); + regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], + playback); adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; @@ -407,6 +420,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int adav80x_set_adc_clock(struct snd_soc_codec *codec, unsigned int sample_rate) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int val; if (sample_rate <= 48000) @@ -414,7 +428,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec, else val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; - snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, + regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1, ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); return 0; @@ -423,6 +437,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec, static int adav80x_set_dac_clock(struct snd_soc_codec *codec, unsigned int sample_rate) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int val; if (sample_rate <= 48000) @@ -430,7 +445,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec, else val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, + regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2, ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, val); @@ -440,6 +455,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec, static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, struct snd_soc_dai *dai, snd_pcm_format_t format) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int val; switch (format) { @@ -459,7 +475,7 @@ static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, return -EINVAL; } - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], + regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0], ADAV80X_CAPTURE_WORD_LEN_MASK, val); return 0; @@ -491,7 +507,7 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, return -EINVAL; } - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], + regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1], ADAV80X_PLAYBACK_MODE_MASK, val); return 0; @@ -554,8 +570,10 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); - snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); - snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); + regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1, + iclk_ctrl1); + regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, + iclk_ctrl2); snd_soc_dapm_sync(&codec->dapm); } @@ -575,10 +593,12 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); if (freq == 0) { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, + mask, mask); adav80x->sysclk_pd[clk_id] = true; } else { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE, + mask, 0); adav80x->sysclk_pd[clk_id] = false; } @@ -650,9 +670,9 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, return -EINVAL; } - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, - pll_ctrl1); - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1, + ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1); + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2, ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); if (source != adav80x->pll_src) { @@ -661,7 +681,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, else pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); - snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, + regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC, ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); adav80x->pll_src = source; @@ -675,6 +695,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, static int adav80x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int mask = ADAV80X_DAC_CTRL1_PD; switch (level) { @@ -683,10 +704,12 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); + regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, + 0x00); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); + regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask, + mask); break; } @@ -780,7 +803,7 @@ static int adav80x_probe(struct snd_soc_codec *codec) int ret; struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); if (ret) { dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); return ret; @@ -791,23 +814,31 @@ static int adav80x_probe(struct snd_soc_codec *codec) snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); /* Power down S/PDIF receiver, since it is currently not supported */ - snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); + regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20); /* Disable DAC zero flag */ - snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); + regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); } static int adav80x_suspend(struct snd_soc_codec *codec) { - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_cache_only(adav80x->regmap, true); + + return ret; } static int adav80x_resume(struct snd_soc_codec *codec) { + struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(adav80x->regmap, false); adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - codec->cache_sync = 1; - snd_soc_cache_sync(codec); + regcache_sync(adav80x->regmap); return 0; } @@ -827,10 +858,6 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .set_pll = adav80x_set_pll, .set_sysclk = adav80x_set_sysclk, - .reg_word_size = sizeof(u8), - .reg_cache_size = ARRAY_SIZE(adav80x_default_regs), - .reg_cache_default = adav80x_default_regs, - .controls = adav80x_controls, .num_controls = ARRAY_SIZE(adav80x_controls), .dapm_widgets = adav80x_dapm_widgets, @@ -839,18 +866,21 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), }; -static int adav80x_bus_probe(struct device *dev, - enum snd_soc_control_type control_type) +static int adav80x_bus_probe(struct device *dev, struct regmap *regmap) { struct adav80x *adav80x; int ret; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); if (!adav80x) return -ENOMEM; + dev_set_drvdata(dev, adav80x); - adav80x->control_type = control_type; + adav80x->regmap = regmap; ret = snd_soc_register_codec(dev, &adav80x_codec_driver, adav80x_dais, ARRAY_SIZE(adav80x_dais)); @@ -868,6 +898,19 @@ static int adav80x_bus_remove(struct device *dev) } #if defined(CONFIG_SPI_MASTER) +static const struct regmap_config adav80x_spi_regmap_config = { + .val_bits = 8, + .pad_bits = 1, + .reg_bits = 7, + .read_flag_mask = 0x01, + + .max_register = ADAV80X_PLL_OUTE, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adav80x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), +}; + static const struct spi_device_id adav80x_spi_id[] = { { "adav801", 0 }, { } @@ -876,7 +919,8 @@ MODULE_DEVICE_TABLE(spi, adav80x_spi_id); static int adav80x_spi_probe(struct spi_device *spi) { - return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); + return adav80x_bus_probe(&spi->dev, + devm_regmap_init_spi(spi, &adav80x_spi_regmap_config)); } static int adav80x_spi_remove(struct spi_device *spi) @@ -896,6 +940,18 @@ static struct spi_driver adav80x_spi_driver = { #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static const struct regmap_config adav80x_i2c_regmap_config = { + .val_bits = 8, + .pad_bits = 1, + .reg_bits = 7, + + .max_register = ADAV80X_PLL_OUTE, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adav80x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), +}; + static const struct i2c_device_id adav80x_i2c_id[] = { { "adav803", 0 }, { } @@ -905,7 +961,8 @@ MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); static int adav80x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return adav80x_bus_probe(&client->dev, SND_SOC_I2C); + return adav80x_bus_probe(&client->dev, + devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config)); } static int adav80x_i2c_remove(struct i2c_client *client) -- cgit v0.10.2 From 7cc302d231aae87a08909ae40cdf36dfe7bb5102 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 30 Sep 2013 17:08:15 +0300 Subject: ASoC: pcm: Remove extra spaces from dev_ prints dev_ prints are already prefixed by ": " before format string so there is no need for extra spaces. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 330c9a6..d449872 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -721,7 +721,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); - dev_dbg(fe->dev, " connected new DPCM %s path %s %s %s\n", + dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", stream ? "capture" : "playback", fe->dai_link->name, stream ? "<-" : "->", be->dai_link->name); @@ -749,7 +749,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, if (dpcm->fe == fe) continue; - dev_dbg(fe->dev, " reparent %s path %s %s %s\n", + dev_dbg(fe->dev, "reparent %s path %s %s %s\n", stream ? "capture" : "playback", dpcm->fe->dai_link->name, stream ? "<-" : "->", dpcm->be->dai_link->name); @@ -773,7 +773,7 @@ static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE) continue; - dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n", + dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n", stream ? "capture" : "playback", fe->dai_link->name, stream ? "<-" : "->", dpcm->be->dai_link->name); @@ -2116,7 +2116,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) pcm->private_free = platform->driver->pcm_free; out: - dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name, + dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; } -- cgit v0.10.2 From 4fa8dbc18e8a57ea21c63103abdea042ab923202 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 30 Sep 2013 22:17:37 -0300 Subject: ASoC: fsl: imx-sgtl5000: Add .remove back Commit e8f00c1b01 (Merge remote-tracking branch 'asoc/fix/fsl' into asoc-devm) fixed a conflict, but missed to add the .remove function back,which causes the following build warning: sound/soc/fsl/imx-sgtl5000.c:185:12: warning: 'imx_sgtl5000_remove' defined but not used [-Wunused-function] Fix the warning by adding the .remove function back. Reported-by: Olof Johansson Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 6f4bdc8..ed6ba1e 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -204,6 +204,7 @@ static struct platform_driver imx_sgtl5000_driver = { .of_match_table = imx_sgtl5000_dt_ids, }, .probe = imx_sgtl5000_probe, + .remove = imx_sgtl5000_remove, }; module_platform_driver(imx_sgtl5000_driver); -- cgit v0.10.2 From e2c9917bfa4e104ba53819b37498eb45fbcd4e41 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Sun, 29 Sep 2013 16:00:13 +0200 Subject: ASoC: kirkwood: fix compilation warning in kirkwood_dma_open writel() supposes the first argument of type unsigned int. This fix the warning: sound/soc/kirkwood/kirkwood-dma.c: In function 'kirkwood_dma_open': sound/soc/kirkwood/kirkwood-dma.c:164:3: warning: large integer implicitly truncated to unsigned type [-Woverflow] Signed-off-by: Vladimir Murzin Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 0c85c4e..55d0d9d3 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -159,7 +159,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) * Enable Error interrupts. We're only ack'ing them but * it's useful for diagnostics */ - writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK); + writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK); } dram = mv_mbus_dram_info(); -- cgit v0.10.2 From 648c538204c23370c734d72921155cc24aff928d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 1 Oct 2013 14:48:24 +0200 Subject: ASoC: tas5086: move two variables into private struct We need to access the charge_period and start_mid_z values from other places later, so move them to the private struct. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 6d31d88..31b5868 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -244,6 +244,8 @@ struct tas5086_private { unsigned int mclk, sclk; unsigned int format; bool deemph; + unsigned int charge_period; + unsigned int pwm_start_mid_z; /* Current sample rate for de-emphasis control */ int rate; /* GPIO driving Reset pin, if any */ @@ -720,13 +722,15 @@ static const int tas5086_charge_period[] = { static int tas5086_probe(struct snd_soc_codec *codec) { struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); - int charge_period = 1300000; /* hardware default is 1300 ms */ - u8 pwm_start_mid_z = 0; int i, ret; + priv->pwm_start_mid_z = 0; + priv->charge_period = 1300000; /* hardware default is 1300 ms */ + if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { struct device_node *of_node = codec->dev->of_node; - of_property_read_u32(of_node, "ti,charge-period", &charge_period); + of_property_read_u32(of_node, "ti,charge-period", + &priv->charge_period); for (i = 0; i < 6; i++) { char name[25]; @@ -735,7 +739,7 @@ static int tas5086_probe(struct snd_soc_codec *codec) "ti,mid-z-channel-%d", i + 1); if (of_get_property(of_node, name, NULL) != NULL) - pwm_start_mid_z |= 1 << i; + priv->pwm_start_mid_z |= 1 << i; } } @@ -744,25 +748,25 @@ static int tas5086_probe(struct snd_soc_codec *codec) * configure 'part 1' of the PWM starts to use Mid-Z, and tell * all configured mid-z channels to start start under 'part 1'. */ - if (pwm_start_mid_z) + if (priv->pwm_start_mid_z) regmap_write(priv->regmap, TAS5086_PWM_START, TAS5086_PWM_START_MIDZ_FOR_START_1 | - pwm_start_mid_z); + priv->pwm_start_mid_z); /* lookup and set split-capacitor charge period */ - if (charge_period == 0) { + if (priv->charge_period == 0) { regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); } else { i = index_in_array(tas5086_charge_period, ARRAY_SIZE(tas5086_charge_period), - charge_period); + priv->charge_period); if (i >= 0) regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, i + 0x08); else dev_warn(codec->dev, "Invalid split-cap charge period of %d ns.\n", - charge_period); + priv->charge_period); } /* enable factory trim */ -- cgit v0.10.2 From d5fd3ccc2d9df493ad6f1eaf7aba72f690e98937 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 1 Oct 2013 14:48:25 +0200 Subject: ASoC: tas5086: move initialization code to own functions We'll need to call code to initialize and reset the codec again at resume time, so factor it out first. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 31b5868..3a88c68 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -458,6 +458,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); } +static void tas5086_reset(struct tas5086_private *priv) +{ + if (gpio_is_valid(priv->gpio_nreset)) { + /* Reset codec - minimum assertion time is 400ns */ + gpio_direction_output(priv->gpio_nreset, 0); + udelay(1); + gpio_set_value(priv->gpio_nreset, 1); + + /* Codec needs ~15ms to wake up */ + msleep(15); + } +} + +/* charge period values in microseconds */ +static const int tas5086_charge_period[] = { + 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, + 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, + 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, +}; + +static int tas5086_init(struct device *dev, struct tas5086_private *priv) +{ + int ret, i; + + /* + * If any of the channels is configured to start in Mid-Z mode, + * configure 'part 1' of the PWM starts to use Mid-Z, and tell + * all configured mid-z channels to start start under 'part 1'. + */ + if (priv->pwm_start_mid_z) + regmap_write(priv->regmap, TAS5086_PWM_START, + TAS5086_PWM_START_MIDZ_FOR_START_1 | + priv->pwm_start_mid_z); + + /* lookup and set split-capacitor charge period */ + if (priv->charge_period == 0) { + regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); + } else { + i = index_in_array(tas5086_charge_period, + ARRAY_SIZE(tas5086_charge_period), + priv->charge_period); + if (i >= 0) + regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, + i + 0x08); + else + dev_warn(dev, + "Invalid split-cap charge period of %d ns.\n", + priv->charge_period); + } + + /* enable factory trim */ + ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); + if (ret < 0) + return ret; + + /* start all channels */ + ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); + if (ret < 0) + return ret; + + /* mute all channels for now */ + ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, + TAS5086_SOFT_MUTE_ALL); + if (ret < 0) + return ret; + + return 0; +} + /* TAS5086 controls */ static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); @@ -712,13 +781,6 @@ static const struct of_device_id tas5086_dt_ids[] = { MODULE_DEVICE_TABLE(of, tas5086_dt_ids); #endif -/* charge period values in microseconds */ -static const int tas5086_charge_period[] = { - 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, - 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, - 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, -}; - static int tas5086_probe(struct snd_soc_codec *codec) { struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); @@ -729,6 +791,7 @@ static int tas5086_probe(struct snd_soc_codec *codec) if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { struct device_node *of_node = codec->dev->of_node; + of_property_read_u32(of_node, "ti,charge-period", &priv->charge_period); @@ -743,39 +806,7 @@ static int tas5086_probe(struct snd_soc_codec *codec) } } - /* - * If any of the channels is configured to start in Mid-Z mode, - * configure 'part 1' of the PWM starts to use Mid-Z, and tell - * all configured mid-z channels to start start under 'part 1'. - */ - if (priv->pwm_start_mid_z) - regmap_write(priv->regmap, TAS5086_PWM_START, - TAS5086_PWM_START_MIDZ_FOR_START_1 | - priv->pwm_start_mid_z); - - /* lookup and set split-capacitor charge period */ - if (priv->charge_period == 0) { - regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); - } else { - i = index_in_array(tas5086_charge_period, - ARRAY_SIZE(tas5086_charge_period), - priv->charge_period); - if (i >= 0) - regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, - i + 0x08); - else - dev_warn(codec->dev, - "Invalid split-cap charge period of %d ns.\n", - priv->charge_period); - } - - /* enable factory trim */ - ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); - if (ret < 0) - return ret; - - /* start all channels */ - ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); + ret = tas5086_init(codec->dev, priv); if (ret < 0) return ret; @@ -784,12 +815,6 @@ static int tas5086_probe(struct snd_soc_codec *codec) if (ret < 0) return ret; - /* mute all channels for now */ - ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, - TAS5086_SOFT_MUTE_ALL); - if (ret < 0) - return ret; - return 0; } @@ -866,17 +891,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) gpio_nreset = -EINVAL; - if (gpio_is_valid(gpio_nreset)) { - /* Reset codec - minimum assertion time is 400ns */ - gpio_direction_output(gpio_nreset, 0); - udelay(1); - gpio_set_value(gpio_nreset, 1); - - /* Codec needs ~15ms to wake up */ - msleep(15); - } - priv->gpio_nreset = gpio_nreset; + tas5086_reset(priv); /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); -- cgit v0.10.2 From 25c84cc1ace56421fa9a676a387a1919e7bc4e62 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 1 Oct 2013 14:48:26 +0200 Subject: ASoC: tas5086: add suspend callback When going to suspend, shut down all channels and re-do the init procedure at resume time. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 3a88c68..2996d2e 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -762,14 +762,39 @@ static struct snd_soc_dai_driver tas5086_dai = { }; #ifdef CONFIG_PM +static int tas5086_soc_suspend(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + /* Shut down all channels */ + ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60); + if (ret < 0) + return ret; + + return 0; +} + static int tas5086_soc_resume(struct snd_soc_codec *codec) { struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; - /* Restore codec state */ - return regcache_sync(priv->regmap); + tas5086_reset(priv); + regcache_mark_dirty(priv->regmap); + + ret = tas5086_init(codec->dev, priv); + if (ret < 0) + return ret; + + ret = regcache_sync(priv->regmap); + if (ret < 0) + return ret; + + return 0; } #else +#define tas5086_soc_suspend NULL #define tas5086_soc_resume NULL #endif /* CONFIG_PM */ @@ -832,6 +857,7 @@ static int tas5086_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { .probe = tas5086_probe, .remove = tas5086_remove, + .suspend = tas5086_soc_suspend, .resume = tas5086_soc_resume, .controls = tas5086_controls, .num_controls = ARRAY_SIZE(tas5086_controls), -- cgit v0.10.2 From a85e419edee73ec458354388e1ba9b8b58bdcbba Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 1 Oct 2013 14:50:02 +0200 Subject: ASoC: davinci-mcasp: add support for suspend and resume When the system returns from suspend, it looses its configuration. Most of it is restored by running a normal audio stream startup, but the DAI format is left unset as that's configured on the audio device creation. Hence, it suffices here to care for the registers which are touched by davinci_mcasp_set_dai_fmt() and restore them when the system is resumed. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 32ddb7f..cdfe959 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1251,12 +1251,51 @@ static int davinci_mcasp_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int davinci_mcasp_suspend(struct device *dev) +{ + struct davinci_audio_dev *a = dev_get_drvdata(dev); + void __iomem *base = a->base; + + a->context.txfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_TXFMCTL_REG); + a->context.rxfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_RXFMCTL_REG); + a->context.txfmt = mcasp_get_reg(base + DAVINCI_MCASP_TXFMT_REG); + a->context.rxfmt = mcasp_get_reg(base + DAVINCI_MCASP_RXFMT_REG); + a->context.aclkxctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKXCTL_REG); + a->context.aclkrctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKRCTL_REG); + a->context.pdir = mcasp_get_reg(base + DAVINCI_MCASP_PDIR_REG); + + return 0; +} + +static int davinci_mcasp_resume(struct device *dev) +{ + struct davinci_audio_dev *a = dev_get_drvdata(dev); + void __iomem *base = a->base; + + mcasp_set_reg(base + DAVINCI_MCASP_TXFMCTL_REG, a->context.txfmtctl); + mcasp_set_reg(base + DAVINCI_MCASP_RXFMCTL_REG, a->context.rxfmtctl); + mcasp_set_reg(base + DAVINCI_MCASP_TXFMT_REG, a->context.txfmt); + mcasp_set_reg(base + DAVINCI_MCASP_RXFMT_REG, a->context.rxfmt); + mcasp_set_reg(base + DAVINCI_MCASP_ACLKXCTL_REG, a->context.aclkxctl); + mcasp_set_reg(base + DAVINCI_MCASP_ACLKRCTL_REG, a->context.aclkrctl); + mcasp_set_reg(base + DAVINCI_MCASP_PDIR_REG, a->context.pdir); + + return 0; +} +#endif + +SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops, + davinci_mcasp_suspend, + davinci_mcasp_resume); + static struct platform_driver davinci_mcasp_driver = { .probe = davinci_mcasp_probe, .remove = davinci_mcasp_remove, .driver = { .name = "davinci-mcasp", .owner = THIS_MODULE, + .pm = &davinci_mcasp_pm_ops, .of_match_table = mcasp_dt_ids, }, }; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index a9ac0c1..a2e27e1 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -43,6 +43,18 @@ struct davinci_audio_dev { /* McASP FIFO related */ u8 txnumevt; u8 rxnumevt; + +#ifdef CONFIG_PM_SLEEP + struct { + u32 txfmtctl; + u32 rxfmtctl; + u32 txfmt; + u32 rxfmt; + u32 aclkxctl; + u32 aclkrctl; + u32 pdir; + } context; +#endif }; #endif /* DAVINCI_MCASP_H */ -- cgit v0.10.2 From da83fea6122ea637be5f960b95bb599561617319 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 5 Oct 2013 19:26:17 +0200 Subject: ASoC: dapm: Ignore VMID widgets for target bias VMID widgets behave very similar to signal generator widgets. Both are always considered to be powered up. This means that we need to ignore the VMID widgets in the same way as signal generator widgets when calculating the DAPM context's target bias level. Otherwise the presence of a VMID widget, regardless whether it is on an active path or not, will cause the DAPM context to be powered up. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c17c14c..177f8a1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1840,6 +1840,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) */ switch (w->id) { case snd_soc_dapm_siggen: + case snd_soc_dapm_vmid: break; case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: -- cgit v0.10.2 From 249ce1387b7739dbea2ac1a697e4bf1e37ec06b7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Oct 2013 13:43:49 +0200 Subject: ASoC: dapm: Add support for virtual mixer controls This patch adds support for virtual DAPM mixer controls. They are similar to virtual DAPM enums. There is no hardware register backing the control, so changing the control's value wont have any direct effect on the hardware. But it still influences the DAPM graph by causing the path it sits on to be connected or disconnected. This in turn can cause power changes for some of the widgets on the DAPM graph, which will then modify the hardware state. Signed-off-by: Lars-Peter Clausen Tested-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 27a72d5..2037c45 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -286,6 +286,8 @@ struct device; .info = snd_soc_info_volsw, \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) } +#define SOC_DAPM_SINGLE_VIRT(xname, max) \ + SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0) #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \ @@ -300,6 +302,8 @@ struct device; .tlv.p = (tlv_array), \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } +#define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \ + SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array) #define SOC_DAPM_ENUM(xname, xenum) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ diff --git a/include/sound/soc.h b/include/sound/soc.h index d22cb0a..b429dba 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1088,7 +1088,8 @@ struct snd_soc_pcm_runtime { /* mixer control */ struct soc_mixer_control { int min, max, platform_max; - unsigned int reg, rreg, shift, rshift; + int reg, rreg; + unsigned int shift, rshift; unsigned int invert:1; unsigned int autodisable:1; }; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 177f8a1..9273216 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -499,18 +499,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, int val; struct soc_mixer_control *mc = (struct soc_mixer_control *) w->kcontrol_news[i].private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - val = soc_widget_read(w, reg); - val = (val >> shift) & mask; - if (invert) - val = max - val; + if (reg != SND_SOC_NOPM) { + val = soc_widget_read(w, reg); + val = (val >> shift) & mask; + if (invert) + val = max - val; + p->connect = !!val; + } else { + p->connect = 0; + } - p->connect = !!val; } break; case snd_soc_dapm_mux: { @@ -2792,7 +2796,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; @@ -2805,7 +2809,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, kcontrol->id.name); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (dapm_kcontrol_is_powered(kcontrol)) + if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) val = (snd_soc_read(codec, reg) >> shift) & mask; else val = dapm_kcontrol_get_value(kcontrol); @@ -2836,7 +2840,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; @@ -2858,19 +2862,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - dapm_kcontrol_set_value(kcontrol, val); + change = dapm_kcontrol_set_value(kcontrol, val); - mask = mask << shift; - val = val << shift; + if (reg != SND_SOC_NOPM) { + mask = mask << shift; + val = val << shift; + + change = snd_soc_test_bits(codec, reg, mask, val); + } - change = snd_soc_test_bits(codec, reg, mask, val); if (change) { - update.kcontrol = kcontrol; - update.reg = reg; - update.mask = mask; - update.val = val; + if (reg != SND_SOC_NOPM) { + update.kcontrol = kcontrol; + update.reg = reg; + update.mask = mask; + update.val = val; - card->update = &update; + card->update = &update; + } soc_dapm_mixer_update_power(card, kcontrol, connect); -- cgit v0.10.2 From 290c348ee5522a5682c2011fa4d51f232404e8a4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Oct 2013 13:43:51 +0200 Subject: ASoC: twl6040: Use virtual DAPM mixer controls By using the new virtual DAPM mixer controls it is possible to remove the twl6040 specific implementation of virtual controls. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 35059a2..f2f4bcb 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -54,12 +54,7 @@ enum twl6040_dai_id { #define TWL6040_OUTHF_0dB 0x03 #define TWL6040_OUTHF_M52dB 0x1D -/* Shadow register used by the driver */ -#define TWL6040_REG_SW_SHADOW 0x2F -#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1) - -/* TWL6040_REG_SW_SHADOW (0x2F) fields */ -#define TWL6040_EAR_PATH_ENABLE 0x01 +#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1) struct twl6040_jack_data { struct snd_soc_jack *jack; @@ -135,8 +130,6 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { 0x00, /* REG_HFOTRIM 0x2C */ 0x09, /* REG_ACCCTL 0x2D */ 0x00, /* REG_STATUS 0x2E (ro) */ - - 0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */ }; /* List of registers to be restored after power up */ @@ -220,12 +213,8 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, if (reg >= TWL6040_CACHEREGNUM) return -EIO; - if (likely(reg < TWL6040_REG_SW_SHADOW)) { - value = twl6040_reg_read(twl6040, reg); - twl6040_write_reg_cache(codec, reg, value); - } else { - value = twl6040_read_reg_cache(codec, reg); - } + value = twl6040_reg_read(twl6040, reg); + twl6040_write_reg_cache(codec, reg, value); return value; } @@ -261,8 +250,7 @@ static int twl6040_write(struct snd_soc_codec *codec, return -EIO; twl6040_write_reg_cache(codec, reg, value); - if (likely(reg < TWL6040_REG_SW_SHADOW) && - twl6040_is_path_unmuted(codec, reg)) + if (twl6040_is_path_unmuted(codec, reg)) return twl6040_reg_write(twl6040, reg, value); else return 0; @@ -555,7 +543,7 @@ static const struct snd_kcontrol_new hfr_mux_controls = SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]); static const struct snd_kcontrol_new ep_path_enable_control = - SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0); + SOC_DAPM_SINGLE_VIRT("Switch", 1); static const struct snd_kcontrol_new auxl_switch_control = SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0); -- cgit v0.10.2 From 052901f42f360062f36cc5c0aa6e5ae372fe0895 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Oct 2013 13:43:50 +0200 Subject: ASoC: twl4030: Use virtual DAPM mixer controls By using the new virtual DAPM mixer controls it is possible to remove the twl4030 specific implementation of virtual controls. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1e3884d..dfc51bb 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,13 +46,7 @@ /* TWL4030 PMBR1 Register GPIO6 mux bits */ #define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2) -/* Shadow register used by the audio driver */ -#define TWL4030_REG_SW_SHADOW 0x4A -#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) - -/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ -#define TWL4030_HFL_EN 0x01 -#define TWL4030_HFR_EN 0x02 +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) /* * twl4030 register cache & default register settings @@ -132,7 +126,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 0x00, /* REG_ANAMIC_GAIN (0x48) */ 0x00, /* REG_MISC_SET_2 (0x49) */ - 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */ }; /* codec private data */ @@ -198,42 +191,41 @@ static int twl4030_write(struct snd_soc_codec *codec, int write_to_reg = 0; twl4030_write_reg_cache(codec, reg, value); - if (likely(reg < TWL4030_REG_SW_SHADOW)) { - /* Decide if the given register can be written */ - switch (reg) { - case TWL4030_REG_EAR_CTL: - if (twl4030->earpiece_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PREDL_CTL: - if (twl4030->predrivel_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PREDR_CTL: - if (twl4030->predriver_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PRECKL_CTL: - if (twl4030->carkitl_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PRECKR_CTL: - if (twl4030->carkitr_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_HS_GAIN_SET: - if (twl4030->hsl_enabled || twl4030->hsr_enabled) - write_to_reg = 1; - break; - default: - /* All other register can be written */ + /* Decide if the given register can be written */ + switch (reg) { + case TWL4030_REG_EAR_CTL: + if (twl4030->earpiece_enabled) write_to_reg = 1; - break; - } - if (write_to_reg) - return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - value, reg); + break; + case TWL4030_REG_PREDL_CTL: + if (twl4030->predrivel_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_PREDR_CTL: + if (twl4030->predriver_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_PRECKL_CTL: + if (twl4030->carkitl_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_PRECKR_CTL: + if (twl4030->carkitr_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_HS_GAIN_SET: + if (twl4030->hsl_enabled || twl4030->hsr_enabled) + write_to_reg = 1; + break; + default: + /* All other register can be written */ + write_to_reg = 1; + break; } + if (write_to_reg) + return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + value, reg); + return 0; } @@ -532,7 +524,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); /* Handsfree Left virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0); + SOC_DAPM_SINGLE_VIRT("Switch", 1); /* Handsfree Right */ static const char *twl4030_handsfreer_texts[] = @@ -548,7 +540,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); /* Handsfree Right virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0); + SOC_DAPM_SINGLE_VIRT("Switch", 1); /* Vibra */ /* Vibra audio path selection */ -- cgit v0.10.2 From 7e09a979404ed07b8f05d09a0e87a87c7891f472 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 7 Oct 2013 23:00:24 +0100 Subject: regmap: Cache async work structures Rather than allocating and deallocating the structures used to manage async transfers each time we do one keep the structures around as long as the regmap is around. This should provide a small performance improvement. Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f7778..793ebe2 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -44,7 +44,6 @@ struct regmap_format { struct regmap_async { struct list_head list; - struct work_struct cleanup; struct regmap *map; void *work_buf; }; @@ -67,6 +66,7 @@ struct regmap { spinlock_t async_lock; wait_queue_head_t async_waitq; struct list_head async_list; + struct list_head async_free; int async_ret; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7d689a1..742f300 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); -static void async_cleanup(struct work_struct *work) -{ - struct regmap_async *async = container_of(work, struct regmap_async, - cleanup); - - kfree(async->work_buf); - kfree(async); -} - bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges) @@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev, spin_lock_init(&map->async_lock); INIT_LIST_HEAD(&map->async_list); + INIT_LIST_HEAD(&map->async_free); init_waitqueue_head(&map->async_waitq); if (config->read_flag_mask || config->write_flag_mask) { @@ -942,12 +934,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache); */ void regmap_exit(struct regmap *map) { + struct regmap_async *async; + regcache_exit(map); regmap_debugfs_exit(map); regmap_range_exit(map); if (map->bus && map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); + while (!list_empty(&map->async_free)) { + async = list_first_entry_or_null(&map->async_free, + struct regmap_async, + list); + list_del(&async->list); + kfree(async->work_buf); + kfree(async); + } kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); @@ -1115,20 +1117,31 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, u8[0] |= map->write_flag_mask; if (async && map->bus->async_write) { - struct regmap_async *async = map->bus->async_alloc(); - if (!async) - return -ENOMEM; + struct regmap_async *async; trace_regmap_async_write_start(map->dev, reg, val_len); - async->work_buf = kzalloc(map->format.buf_size, - GFP_KERNEL | GFP_DMA); - if (!async->work_buf) { - kfree(async); - return -ENOMEM; + spin_lock_irqsave(&map->async_lock, flags); + async = list_first_entry_or_null(&map->async_free, + struct regmap_async, + list); + if (async) + list_del(&async->list); + spin_unlock_irqrestore(&map->async_lock, flags); + + if (!async) { + async = map->bus->async_alloc(); + if (!async) + return -ENOMEM; + + async->work_buf = kzalloc(map->format.buf_size, + GFP_KERNEL | GFP_DMA); + if (!async->work_buf) { + kfree(async); + return -ENOMEM; + } } - INIT_WORK(&async->cleanup, async_cleanup); async->map = map; /* If the caller supplied the value we can use it safely. */ @@ -1152,11 +1165,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, ret); spin_lock_irqsave(&map->async_lock, flags); - list_del(&async->list); + list_move(&async->list, &map->async_free); spin_unlock_irqrestore(&map->async_lock, flags); - - kfree(async->work_buf); - kfree(async); } return ret; @@ -1820,8 +1830,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) trace_regmap_async_io_complete(map->dev); spin_lock(&map->async_lock); - - list_del(&async->list); + list_move(&async->list, &map->async_free); wake = list_empty(&map->async_list); if (ret != 0) @@ -1829,8 +1838,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) spin_unlock(&map->async_lock); - schedule_work(&async->cleanup); - if (wake) wake_up(&map->async_waitq); } -- cgit v0.10.2 From 651e013e3ce6c0646c39a07e22bebad75a207209 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 8 Oct 2013 18:37:36 +0100 Subject: regmap: Don't generate gather writes for single register raw writes Since it is quite common for single register raw or async writes to be generated by rbtree cache syncs or firmware downloads and essentially all hardware will be faster with only a single transfer optimise this case by copying single values into the internal scratch buffer before sending. Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 742f300..d27758c 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1116,6 +1116,16 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, u8[0] |= map->write_flag_mask; + /* + * Essentially all I/O mechanisms will be faster with a single + * buffer to write. Since register syncs often generate raw + * writes of single registers optimise that case. + */ + if (val != work_val && val_len == map->format.val_bytes) { + memcpy(work_val, val, map->format.val_bytes); + val = work_val; + } + if (async && map->bus->async_write) { struct regmap_async *async; -- cgit v0.10.2 From 0a8198094da895c8d5db95812fe9de7027d808e4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 9 Oct 2013 12:28:52 +0100 Subject: regmap: Simplify the initiation of async I/O Rather than passing a flag around through the entire call stack store it in the regmap struct and read it when required. This minimises the visibility of the feature through the API, minimising the code updates needed to use it more widely. Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 793ebe2..6873b4c 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -63,6 +63,7 @@ struct regmap { void *bus_context; const char *name; + bool async; spinlock_t async_lock; wait_queue_head_t async_waitq; struct list_head async_list; @@ -218,7 +219,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, int regcache_lookup_reg(struct regmap *map, unsigned int reg); int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async); + const void *val, size_t val_len); void regmap_async_complete_cb(struct regmap_async *async, int ret); diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index d6c2d69..a36112a 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -631,8 +631,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, map->cache_bypass = 1; - ret = _regmap_raw_write(map, base, *data, count * val_bytes, - false); + ret = _regmap_raw_write(map, base, *data, count * val_bytes); map->cache_bypass = 0; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d27758c..268fb71 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1041,7 +1041,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, } int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async) + const void *val, size_t val_len) { struct regmap_range_node *range; unsigned long flags; @@ -1093,7 +1093,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, dev_dbg(map->dev, "Writing window %d/%zu\n", win_residue, val_len / map->format.val_bytes); ret = _regmap_raw_write(map, reg, val, win_residue * - map->format.val_bytes, async); + map->format.val_bytes); if (ret != 0) return ret; @@ -1126,7 +1126,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, val = work_val; } - if (async && map->bus->async_write) { + if (map->async && map->bus->async_write) { struct regmap_async *async; trace_regmap_async_write_start(map->dev, reg, val_len); @@ -1273,7 +1273,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, map->work_buf + map->format.reg_bytes + map->format.pad_bytes, - map->format.val_bytes, false); + map->format.val_bytes); } static inline void *_regmap_map_get_context(struct regmap *map) @@ -1365,7 +1365,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, false); + ret = _regmap_raw_write(map, reg, val, val_len); map->unlock(map->lock_arg); @@ -1446,8 +1446,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, return ret; } } else { - ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, - false); + ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); } if (val_bytes != 1) @@ -1493,7 +1492,11 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, true); + map->async = true; + + ret = _regmap_raw_write(map, reg, val, val_len); + + map->async = false; map->unlock(map->lock_arg); -- cgit v0.10.2 From 915f441b6f31b1a8ee01e9263a4e2d44c434d832 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 9 Oct 2013 13:30:10 +0100 Subject: regmap: Provide asynchronous write and update bits operations Make it easier for drivers to include single register writes in asynchronous sequences by providing async versions of the write and update bits operations. The update bits operations are only likely to be effective when used with devices that have caches but this is common enough to be useful. Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 268fb71..0503d86 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1338,6 +1338,37 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write); /** + * regmap_write_async(): Write a value to a single register asynchronously + * + * @map: Register map to write to + * @reg: Register to write to + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) +{ + int ret; + + if (reg % map->reg_stride) + return -EINVAL; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_write(map, reg, val); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_async); + +/** * regmap_raw_write(): Write raw values to one or more registers * * @map: Register map to write to @@ -1811,6 +1842,41 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_update_bits); /** + * regmap_update_bits_async: Perform a read/modify/write cycle on the register + * map asynchronously + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * With most buses the read must be done synchronously so this is most + * useful for devices with a cache which do not need to interact with + * the hardware to determine the current register value. + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + bool change; + int ret; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_update_bits(map, reg, mask, val, &change); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_update_bits_async); + +/** * regmap_update_bits_check: Perform a read/modify/write cycle on the * register map and report if updated * @@ -1835,6 +1901,43 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits_check); +/** + * regmap_update_bits_check_async: Perform a read/modify/write cycle on the + * register map asynchronously and report if + * updated + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * @change: Boolean indicating if a write was done + * + * With most buses the read must be done synchronously so this is most + * useful for devices with a cache which do not need to interact with + * the hardware to determine the current register value. + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change) +{ + int ret; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_update_bits(map, reg, mask, val, change); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_update_bits_check_async); + void regmap_async_complete_cb(struct regmap_async *async, int ret) { struct regmap *map = async->map; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index a10380b..114565b 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -374,6 +374,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config); struct regmap *dev_get_regmap(struct device *dev, const char *name); int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); +int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val); int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, @@ -387,9 +388,14 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_update_bits_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val); int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); +int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change); int regmap_get_val_bytes(struct regmap *map); int regmap_async_complete(struct regmap *map); bool regmap_can_raw_write(struct regmap *map); @@ -527,6 +533,13 @@ static inline int regmap_write(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_write_async(struct regmap *map, unsigned int reg, + unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { @@ -576,6 +589,14 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_update_bits_async(struct regmap *map, + unsigned int reg, + unsigned int mask, unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, @@ -585,6 +606,16 @@ static inline int regmap_update_bits_check(struct regmap *map, return -EINVAL; } +static inline int regmap_update_bits_check_async(struct regmap *map, + unsigned int reg, + unsigned int mask, + unsigned int val, + bool *change) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_get_val_bytes(struct regmap *map) { WARN_ONCE(1, "regmap API is disabled"); -- cgit v0.10.2 From eb270e98e15b9f4303b074ba5d88ee98110bc451 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 9 Oct 2013 13:52:52 +0100 Subject: ASoC: dapm: Use async I/O for DAPM sequences Within a DAPM sequence we normally don't care about when exactly a register write has completed so long as they happen in the order we requested. This means that we can issue most of the writes we do asynchronously which should maximise the ability of the underlying frameworks to keep the hardware busy, providing a small performance improvement on some systems. We currently ensure that all writes are completed both when changing to a different device and when calling into the regulator and clock frameworks. This should ensure that the previous ordering is maintained. We also ensure that writes are completed prior to calling into widget event functions since some event functions implement delays. This should be improved in future so that widgets can disable this sync in order to add extra writes. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9273216..1dbc5f8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -409,6 +409,12 @@ static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w) mutex_unlock(&w->platform->mutex); } +static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) +{ + if (dapm->codec && dapm->codec->using_regmap) + regmap_async_complete(dapm->codec->control_data); +} + static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, unsigned short reg, unsigned int mask, unsigned int value) { @@ -417,8 +423,9 @@ static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, int ret; if (w->codec && w->codec->using_regmap) { - ret = regmap_update_bits_check(w->codec->control_data, - reg, mask, value, &change); + ret = regmap_update_bits_check_async(w->codec->control_data, + reg, mask, value, + &change); if (ret != 0) return ret; } else { @@ -1201,6 +1208,8 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, { int ret; + soc_dapm_async_complete(w->dapm); + if (SND_SOC_DAPM_EVENT_ON(event)) { if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { ret = regulator_allow_bypass(w->regulator, false); @@ -1234,6 +1243,8 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w, if (!w->clk) return -EIO; + soc_dapm_async_complete(w->dapm); + #ifdef CONFIG_HAVE_CLK if (SND_SOC_DAPM_EVENT_ON(event)) { return clk_prepare_enable(w->clk); @@ -1426,6 +1437,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card, if (w->event && (w->event_flags & event)) { pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n", w->name, ev_name); + soc_dapm_async_complete(w->dapm); trace_snd_soc_dapm_widget_event_start(w, event); ret = w->event(w, NULL, event); trace_snd_soc_dapm_widget_event_done(w, event); @@ -1498,6 +1510,7 @@ static void dapm_seq_run(struct snd_soc_card *card, struct list_head *list, int event, bool power_up) { struct snd_soc_dapm_widget *w, *n; + struct snd_soc_dapm_context *d; LIST_HEAD(pending); int cur_sort = -1; int cur_subseq = -1; @@ -1528,6 +1541,9 @@ static void dapm_seq_run(struct snd_soc_card *card, cur_subseq); } + if (cur_dapm && w->dapm != cur_dapm) + soc_dapm_async_complete(cur_dapm); + INIT_LIST_HEAD(&pending); cur_sort = -1; cur_subseq = INT_MIN; @@ -1586,6 +1602,10 @@ static void dapm_seq_run(struct snd_soc_card *card, cur_dapm->seq_notifier(cur_dapm, i, cur_subseq); } + + list_for_each_entry(d, &card->dapm_list, list) { + soc_dapm_async_complete(d); + } } static void dapm_widget_update(struct snd_soc_card *card) -- cgit v0.10.2 From 1dd275b60e5db4d0bb3763490b519176dcfc4308 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 9 Oct 2013 13:56:37 +0100 Subject: ASoC: dapm: Run clock and regulator events separately to other supplies In order to avoid trying to use an external clock or supply for an on-chip supply prior to it being enabled move the clock and regulator supply events to a separate step in DAPM sequencing from normal supply events. This should have minimal practical impact since these widgets are sorted using SND_SOC_NOPM which is a negative value and hence sorted separately to any real register writes, though it may be relevant if supplies have event callbacks only. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1dbc5f8..2fb0b72 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -59,31 +59,31 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_supply] = 1, [snd_soc_dapm_regulator_supply] = 1, [snd_soc_dapm_clock_supply] = 1, - [snd_soc_dapm_micbias] = 2, + [snd_soc_dapm_supply] = 2, + [snd_soc_dapm_micbias] = 3, [snd_soc_dapm_dai_link] = 2, - [snd_soc_dapm_dai_in] = 3, - [snd_soc_dapm_dai_out] = 3, - [snd_soc_dapm_aif_in] = 3, - [snd_soc_dapm_aif_out] = 3, - [snd_soc_dapm_mic] = 4, - [snd_soc_dapm_mux] = 5, - [snd_soc_dapm_virt_mux] = 5, - [snd_soc_dapm_value_mux] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_switch] = 7, - [snd_soc_dapm_mixer] = 7, - [snd_soc_dapm_mixer_named_ctl] = 7, - [snd_soc_dapm_pga] = 8, - [snd_soc_dapm_adc] = 9, - [snd_soc_dapm_out_drv] = 10, - [snd_soc_dapm_hp] = 10, - [snd_soc_dapm_spk] = 10, - [snd_soc_dapm_line] = 10, - [snd_soc_dapm_kcontrol] = 11, - [snd_soc_dapm_post] = 12, + [snd_soc_dapm_dai_in] = 4, + [snd_soc_dapm_dai_out] = 4, + [snd_soc_dapm_aif_in] = 4, + [snd_soc_dapm_aif_out] = 4, + [snd_soc_dapm_mic] = 5, + [snd_soc_dapm_mux] = 6, + [snd_soc_dapm_virt_mux] = 6, + [snd_soc_dapm_value_mux] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_switch] = 8, + [snd_soc_dapm_mixer] = 8, + [snd_soc_dapm_mixer_named_ctl] = 8, + [snd_soc_dapm_pga] = 9, + [snd_soc_dapm_adc] = 10, + [snd_soc_dapm_out_drv] = 11, + [snd_soc_dapm_hp] = 11, + [snd_soc_dapm_spk] = 11, + [snd_soc_dapm_line] = 11, + [snd_soc_dapm_kcontrol] = 12, + [snd_soc_dapm_post] = 13, }; static int dapm_down_seq[] = { @@ -109,10 +109,10 @@ static int dapm_down_seq[] = { [snd_soc_dapm_dai_in] = 10, [snd_soc_dapm_dai_out] = 10, [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_clock_supply] = 12, - [snd_soc_dapm_regulator_supply] = 12, [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_clock_supply] = 13, + [snd_soc_dapm_regulator_supply] = 13, + [snd_soc_dapm_post] = 14, }; static void pop_wait(u32 pop_time) -- cgit v0.10.2 From c6452e39e8286b88872aee20a4d083cfa65516bc Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Fri, 11 Oct 2013 12:28:13 +0200 Subject: ASoC: mc13783: add mixer controls Add more controls to the alsa mixer infrastructure. Signed-off-by: Steffen Trumtrar Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index eedbf05..2b62737 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -541,8 +541,26 @@ static const struct soc_enum mc13783_enum_3d_mixer = static struct snd_kcontrol_new mc13783_control_list[] = { SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0), SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0), + SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0), SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0), SOC_ENUM("3D Control", mc13783_enum_3d_mixer), + + SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0), + SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0), + SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0), + SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0), + + SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0), + SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0), + + SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0), + SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0), + + SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0), + SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0), + + SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0), + SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0), }; static int mc13783_probe(struct snd_soc_codec *codec) -- cgit v0.10.2 From bb7838d4f13c50df8ef7324f5fd4aeb729269e22 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Fri, 11 Oct 2013 12:28:14 +0200 Subject: ASoC: mc13783: add more DAPM routes Add more infrastructure (i.e. routes, muxes, switches) to the mc13783 DAPM. Signed-off-by: Steffen Trumtrar Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 2b62737..f5472ad 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -427,6 +427,29 @@ static const struct snd_kcontrol_new right_input_mux = static const struct snd_kcontrol_new samp_ctl = SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0); +static const char * const speaker_amp_source_text[] = { + "CODEC", "Right" +}; +static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, + speaker_amp_source_text); +static const struct snd_kcontrol_new speaker_amp_source_mux = + SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); + +static const char * const headset_amp_source_text[] = { + "CODEC", "Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, + headset_amp_source_text); +static const struct snd_kcontrol_new headset_amp_source_mux = + SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); + +static const struct snd_kcontrol_new cdcout_ctl = + SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0); + +static const struct snd_kcontrol_new adc_bypass_ctl = + SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0); + static const struct snd_kcontrol_new lamp_ctl = SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0); @@ -464,12 +487,22 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = { SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, &right_input_mux), + SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0, + &speaker_amp_source_mux), + + SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0, + &headset_amp_source_mux), + SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0), SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0), + SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0, + &adc_bypass_ctl), + /* Output */ SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0), @@ -477,10 +510,15 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("RXOUTR"), SND_SOC_DAPM_OUTPUT("HSL"), SND_SOC_DAPM_OUTPUT("HSR"), + SND_SOC_DAPM_OUTPUT("LSPL"), SND_SOC_DAPM_OUTPUT("LSP"), SND_SOC_DAPM_OUTPUT("SP"), + SND_SOC_DAPM_OUTPUT("CDCOUT"), - SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl), + SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0, + &cdcout_ctl), + SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0, + &samp_ctl), SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl), SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0, &hlamp_ctl), @@ -515,20 +553,28 @@ static struct snd_soc_dapm_route mc13783_routes[] = { { "ADC", NULL, "PGA Right Input"}, { "ADC", NULL, "ADC_Reset"}, + { "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" }, + + { "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"}, + { "Speaker Amp Source MUX", "Right", "DAC PGA"}, + + { "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"}, + { "Headset Amp Source MUX", "Mixer", "DAC PGA"}, + /* Output */ { "HSL", NULL, "Headset Amp Left" }, { "HSR", NULL, "Headset Amp Right"}, { "RXOUTL", NULL, "Line out Amp Left"}, { "RXOUTR", NULL, "Line out Amp Right"}, - { "SP", NULL, "Speaker Amp"}, - { "Speaker Amp", NULL, "DAC PGA"}, - { "LSP", NULL, "DAC PGA"}, - { "Headset Amp Left", NULL, "DAC PGA"}, - { "Headset Amp Right", NULL, "DAC PGA"}, + { "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"}, + { "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"}, + { "HSL", "Headset Amp Left", "Headset Amp Source MUX"}, + { "HSR", "Headset Amp Right", "Headset Amp Source MUX"}, { "Line out Amp Left", NULL, "DAC PGA"}, { "Line out Amp Right", NULL, "DAC PGA"}, { "DAC PGA", NULL, "DAC"}, { "DAC", NULL, "DAC_E"}, + { "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"}, }; static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", -- cgit v0.10.2 From 740ad6c328823f066efb8b907576a54ef92aca69 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Oct 2013 00:06:34 -0700 Subject: ASoC: rcar: fixup rsnd_platform_call() return value Un-implemented platform callback is not error. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index fc83f0f..28c24fc 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -103,7 +103,7 @@ * rsnd_platform functions */ #define rsnd_platform_call(priv, dai, func, param...) \ - (!(priv->info->func) ? -ENODEV : \ + (!(priv->info->func) ? 0 : \ priv->info->func(param)) /* -- cgit v0.10.2 From 2192f81c53a7879c803f0f7d6c49645fdf6c2f6a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Oct 2013 00:07:48 -0700 Subject: ASoC: rcar: add ID check on rsnd_dai_get() checking id in rsnd_dai_get() is good idea Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 28c24fc..b234ed6 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -318,6 +318,9 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) { + if ((id < 0) || (id >= rsnd_dai_nr(priv))) + return NULL; + return priv->rdai + id; } -- cgit v0.10.2 From 1b3ed70a1b22e54b6adaf6ffebe1aa6f26465bae Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 12 Oct 2013 19:35:06 -0300 Subject: ASoC: fsl: Fix memory leak in imx-audmux.c When audmux_clk is used and clk_prepare_enable function succeed, the memory alloc'd to buf variable is leaked Signed-off-by: Felipe Pena Reviewed-by: Sascha Hauer Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index d3bf71a..ac86993 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -66,13 +66,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + char *buf; int port = (int)file->private_data; u32 pdcr, ptcr; - if (!buf) - return -ENOMEM; - if (audmux_clk) { ret = clk_prepare_enable(audmux_clk); if (ret) @@ -85,6 +82,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, if (audmux_clk) clk_disable_unprepare(audmux_clk); + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr); -- cgit v0.10.2 From 48afa793525800eff66a2e792037108b7f0d8613 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 13 Oct 2013 18:17:50 +0200 Subject: ASoC: atmel: don't use devm_pinctrl_get_select_default() in probe Since commit ab78029 (drivers/pinctrl: grab default handles from device core), we can rely on device core for setting the default pins. Signed-off-by: Wolfram Sang Acked-by: Linus Walleij (personally at LCE13) Acked-by: Bo Shen Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index 7222380..b4e3690 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -12,7 +12,6 @@ #include #include #include -#include #include @@ -155,15 +154,8 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev) struct snd_soc_card *card = &atmel_asoc_wm8904_card; struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; struct clk *clk_src; - struct pinctrl *pinctrl; int id, ret; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - dev_err(&pdev->dev, "failed to request pinctrl\n"); - return PTR_ERR(pinctrl); - } - card->dev = &pdev->dev; ret = atmel_asoc_wm8904_dt_init(pdev); if (ret) { -- cgit v0.10.2 From 67093b253bb09276420c7b0a311425705d2714b4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 13 Oct 2013 21:51:26 +0200 Subject: ASoC: fsl: remove leftover release_mem_region When converting this driver to devm_ioremap_resource, the removal of this now unneeded function has been forgotten. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index f58bcd8..0272289 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -615,7 +615,6 @@ failed_pcm_dma: failed_pcm_fiq: snd_soc_unregister_component(&pdev->dev); failed_register: - release_mem_region(res->start, resource_size(res)); clk_disable_unprepare(ssi->clk); failed_clk: snd_soc_set_ac97_ops(NULL); @@ -625,7 +624,6 @@ failed_clk: static int imx_ssi_remove(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct imx_ssi *ssi = platform_get_drvdata(pdev); imx_pcm_dma_exit(pdev); @@ -636,7 +634,6 @@ static int imx_ssi_remove(struct platform_device *pdev) if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; - release_mem_region(res->start, resource_size(res)); clk_disable_unprepare(ssi->clk); snd_soc_set_ac97_ops(NULL); -- cgit v0.10.2 From 5e049fce368dfe07702c3664add9ae7b45df1a9a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 11 Oct 2013 15:43:17 -0600 Subject: ASoC: tegra: support new register layouts in Tegra124 Tegra124 introduces some small changes to the layout of some registers. Modify the affected drivers to program those registers appropriately based on which SoC they're running on. Tegra124 also introduced some new modules on the AHUB configlink register bus. These will require new entries in configlink_clocks[] in the AHUB driver. However, supporting that change likely relies on switching Tegra to the common reset framework, so I'll defer that change for now. Based-on-work-by: Arun Shamanna Lakshmi Based-on-work-by: Songhee Baek Signed-off-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d554d46..bdd19db 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -100,6 +100,7 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, { int channel; u32 reg, val; + struct tegra30_ahub_cif_conf cif_conf; channel = find_first_zero_bit(ahub->rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT); @@ -123,15 +124,21 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; tegra30_apbif_write(reg, val); + cif_conf.threshold = 0; + cif_conf.audio_channels = 2; + cif_conf.client_channels = 2; + cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.expand = 0; + cif_conf.stereo_conv = 0; + cif_conf.replicate = 0; + cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX; + cif_conf.truncate = 0; + cif_conf.mono_conv = 0; + reg = TEGRA30_AHUB_CIF_RX_CTRL + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); - val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | - (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | - TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 | - TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; - tegra30_apbif_write(reg, val); + ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); return 0; } @@ -183,6 +190,7 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, { int channel; u32 reg, val; + struct tegra30_ahub_cif_conf cif_conf; channel = find_first_zero_bit(ahub->tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT); @@ -206,15 +214,21 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; tegra30_apbif_write(reg, val); + cif_conf.threshold = 0; + cif_conf.audio_channels = 2; + cif_conf.client_channels = 2; + cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.expand = 0; + cif_conf.stereo_conv = 0; + cif_conf.replicate = 0; + cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX; + cif_conf.truncate = 0; + cif_conf.mono_conv = 0; + reg = TEGRA30_AHUB_CIF_TX_CTRL + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); - val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | - (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | - TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 | - TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; - tegra30_apbif_write(reg, val); + ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); return 0; } @@ -437,13 +451,21 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = { static struct tegra30_ahub_soc_data soc_data_tegra30 = { .clk_list_mask = CLK_LIST_MASK_TEGRA30, + .set_audio_cif = tegra30_ahub_set_cif, }; static struct tegra30_ahub_soc_data soc_data_tegra114 = { .clk_list_mask = CLK_LIST_MASK_TEGRA114, + .set_audio_cif = tegra30_ahub_set_cif, +}; + +static struct tegra30_ahub_soc_data soc_data_tegra124 = { + .clk_list_mask = CLK_LIST_MASK_TEGRA114, + .set_audio_cif = tegra124_ahub_set_cif, }; static const struct of_device_id tegra30_ahub_of_match[] = { + { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 }, { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 }, {}, @@ -497,6 +519,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, ahub); + ahub->soc_data = soc_data; ahub->dev = &pdev->dev; ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio"); @@ -669,6 +692,70 @@ static struct platform_driver tegra30_ahub_driver = { }; module_platform_driver(tegra30_ahub_driver); +void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg, + struct tegra30_ahub_cif_conf *conf) +{ + unsigned int value; + + value = (conf->threshold << + TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | + ((conf->audio_channels - 1) << + TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((conf->client_channels - 1) << + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (conf->audio_bits << + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (conf->client_bits << + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | + (conf->expand << + TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | + (conf->stereo_conv << + TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | + (conf->replicate << + TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | + (conf->direction << + TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | + (conf->truncate << + TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | + (conf->mono_conv << + TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); + + regmap_write(regmap, reg, value); +} +EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif); + +void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, + struct tegra30_ahub_cif_conf *conf) +{ + unsigned int value; + + value = (conf->threshold << + TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | + ((conf->audio_channels - 1) << + TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((conf->client_channels - 1) << + TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (conf->audio_bits << + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (conf->client_bits << + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | + (conf->expand << + TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | + (conf->stereo_conv << + TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | + (conf->replicate << + TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | + (conf->direction << + TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | + (conf->truncate << + TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | + (conf->mono_conv << + TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); + + regmap_write(regmap, reg, value); +} +EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif); + MODULE_AUTHOR("Stephen Warren "); MODULE_DESCRIPTION("Tegra30 AHUB driver"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 09766cd..d67321d 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -25,16 +25,30 @@ #define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0xf #define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) +#define TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 24 +#define TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0x3f +#define TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) + /* Channel count minus 1 */ #define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 24 #define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 7 #define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) /* Channel count minus 1 */ +#define TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 20 +#define TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 0xf +#define TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) + +/* Channel count minus 1 */ #define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16 #define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 7 #define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) +/* Channel count minus 1 */ +#define TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16 +#define TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 0xf +#define TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) + #define TEGRA30_AUDIOCIF_BITS_4 0 #define TEGRA30_AUDIOCIF_BITS_8 1 #define TEGRA30_AUDIOCIF_BITS_12 2 @@ -86,7 +100,7 @@ #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1 (TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG (TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) -#define TEGRA30_AUDIOCIF_CTRL_REPLICATE 3 +#define TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT 3 #define TEGRA30_AUDIOCIF_DIRECTION_TX 0 #define TEGRA30_AUDIOCIF_DIRECTION_RX 1 @@ -468,8 +482,30 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); +struct tegra30_ahub_cif_conf { + unsigned int threshold; + unsigned int audio_channels; + unsigned int client_channels; + unsigned int audio_bits; + unsigned int client_bits; + unsigned int expand; + unsigned int stereo_conv; + unsigned int replicate; + unsigned int direction; + unsigned int truncate; + unsigned int mono_conv; +}; + +void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg, + struct tegra30_ahub_cif_conf *conf); +void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, + struct tegra30_ahub_cif_conf *conf); + struct tegra30_ahub_soc_data { u32 clk_list_mask; + void (*set_audio_cif)(struct regmap *regmap, + unsigned int reg, + struct tegra30_ahub_cif_conf *conf); /* * FIXME: There are many more differences in HW, such as: * - More APBIF channels. diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 47565fd04..5f20b69 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -179,6 +180,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int mask, val, reg; int ret, sample_size, srate, i2sclock, bitcnt; + struct tegra30_ahub_cif_conf cif_conf; if (params_channels(params) != 2) return -EINVAL; @@ -217,21 +219,26 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val); - val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | - (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | - TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16; + cif_conf.threshold = 0; + cif_conf.audio_channels = 2; + cif_conf.client_channels = 2; + cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; + cif_conf.expand = 0; + cif_conf.stereo_conv = 0; + cif_conf.replicate = 0; + cif_conf.truncate = 0; + cif_conf.mono_conv = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; + cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX; reg = TEGRA30_I2S_CIF_RX_CTRL; } else { - val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; + cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX; reg = TEGRA30_I2S_CIF_TX_CTRL; } - regmap_write(i2s->regmap, reg, val); + i2s->soc_data->set_audio_cif(i2s->regmap, reg, &cif_conf); val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); @@ -396,9 +403,24 @@ static const struct regmap_config tegra30_i2s_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static const struct tegra30_i2s_soc_data tegra30_i2s_config = { + .set_audio_cif = tegra30_ahub_set_cif, +}; + +static const struct tegra30_i2s_soc_data tegra124_i2s_config = { + .set_audio_cif = tegra124_ahub_set_cif, +}; + +static const struct of_device_id tegra30_i2s_of_match[] = { + { .compatible = "nvidia,tegra124-i2s", .data = &tegra124_i2s_config }, + { .compatible = "nvidia,tegra30-i2s", .data = &tegra30_i2s_config }, + {}, +}; + static int tegra30_i2s_platform_probe(struct platform_device *pdev) { struct tegra30_i2s *i2s; + const struct of_device_id *match; u32 cif_ids[2]; struct resource *mem, *memregion; void __iomem *regs; @@ -412,6 +434,14 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, i2s); + match = of_match_device(tegra30_i2s_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + ret = -ENODEV; + goto err; + } + i2s->soc_data = (struct tegra30_i2s_soc_data *)match->data; + i2s->dai = tegra30_i2s_dai_template; i2s->dai.name = dev_name(&pdev->dev); @@ -539,11 +569,6 @@ static int tegra30_i2s_resume(struct device *dev) } #endif -static const struct of_device_id tegra30_i2s_of_match[] = { - { .compatible = "nvidia,tegra30-i2s", }, - {}, -}; - static const struct dev_pm_ops tegra30_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend, tegra30_i2s_runtime_resume, NULL) diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index bea23af..4d0b0a3 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -225,7 +225,14 @@ #define TEGRA30_I2S_LCOEF_COEF_MASK_US 0xffff #define TEGRA30_I2S_LCOEF_COEF_MASK (TEGRA30_I2S_LCOEF_COEF_MASK_US << TEGRA30_I2S_LCOEF_COEF_SHIFT) +struct tegra30_i2s_soc_data { + void (*set_audio_cif)(struct regmap *regmap, + unsigned int reg, + struct tegra30_ahub_cif_conf *conf); +}; + struct tegra30_i2s { + const struct tegra30_i2s_soc_data *soc_data; struct snd_soc_dai_driver dai; int cif_id; struct clk *clk_i2s; diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index d173880..1be311c 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -182,6 +182,8 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30; else if (of_machine_is_compatible("nvidia,tegra114")) data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114; + else if (of_machine_is_compatible("nvidia,tegra124")) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA124; else { dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n"); return -EINVAL; diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 19fdcaf..9577121 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -30,6 +30,7 @@ enum tegra_asoc_utils_soc { TEGRA_ASOC_UTILS_SOC_TEGRA20, TEGRA_ASOC_UTILS_SOC_TEGRA30, TEGRA_ASOC_UTILS_SOC_TEGRA114, + TEGRA_ASOC_UTILS_SOC_TEGRA124, }; struct tegra_asoc_utils_data { -- cgit v0.10.2 From 9f1614aae59033b79941220f65ad36f5fe54a579 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 11 Oct 2013 12:11:02 +0200 Subject: ASoC: snd_soc_dai_ops trigger function description Add a comment to the trigger function in snd_soc_dai_ops struct about possible command sequences. Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ae9a227..0f2e5da 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -166,6 +166,13 @@ struct snd_soc_dai_ops { struct snd_soc_dai *); int (*prepare)(struct snd_pcm_substream *, struct snd_soc_dai *); + /* + * NOTE: Commands passed to the trigger function are not necessarily + * compatible with the current state of the dai. For example this + * sequence of commands is possible: START STOP STOP. + * So do not unconditionally use refcounting functions in the trigger + * function, e.g. clk_enable/disable. + */ int (*trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *); int (*bespoke_trigger)(struct snd_pcm_substream *, int, -- cgit v0.10.2 From 88cf632a135188db35b4db412a06b155fa444eb1 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 11 Oct 2013 12:11:03 +0200 Subject: ASoC: mxs-saif: Store saif state Trigger commands may be passed multiple times. To avoid errors with clk_enable/disable, store the saif state and return if saif is already running/stopped. Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index b56b8a0..c8ead01 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -503,6 +503,9 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (saif->state == MXS_SAIF_STATE_RUNNING) + return 0; + dev_dbg(cpu_dai->dev, "start\n"); clk_enable(master_saif->clk); @@ -543,6 +546,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, } master_saif->ongoing = 1; + saif->state = MXS_SAIF_STATE_RUNNING; dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n", __raw_readl(saif->base + SAIF_CTRL), @@ -555,6 +559,9 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (saif->state == MXS_SAIF_STATE_STOPPED) + return 0; + dev_dbg(cpu_dai->dev, "stop\n"); /* wait a while for the current sample to complete */ @@ -575,6 +582,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, } master_saif->ongoing = 0; + saif->state = MXS_SAIF_STATE_STOPPED; break; default: diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h index 53eaa4b..fbaf7ba 100644 --- a/sound/soc/mxs/mxs-saif.h +++ b/sound/soc/mxs/mxs-saif.h @@ -124,6 +124,11 @@ struct mxs_saif { u32 fifo_underrun; u32 fifo_overrun; + + enum { + MXS_SAIF_STATE_STOPPED, + MXS_SAIF_STATE_RUNNING, + } state; }; extern int mxs_saif_put_mclk(unsigned int saif_id); -- cgit v0.10.2 From 863ebddec85c5ce2fb2e7742e8834a3bd69a2512 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 11 Oct 2013 12:11:04 +0200 Subject: ASoC: mxs-saif: Handle errors in trigger function Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index c8ead01..fc3d89b 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -494,6 +494,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); struct mxs_saif *master_saif; u32 delay; + int ret; master_saif = mxs_saif_get_master(saif); if (!master_saif) @@ -508,21 +509,32 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, dev_dbg(cpu_dai->dev, "start\n"); - clk_enable(master_saif->clk); - if (!master_saif->mclk_in_use) - __raw_writel(BM_SAIF_CTRL_RUN, - master_saif->base + SAIF_CTRL + MXS_SET_ADDR); + ret = clk_enable(master_saif->clk); + if (ret) { + dev_err(saif->dev, "Failed to enable master clock\n"); + return ret; + } /* * If the saif's master is not himself, we also need to enable * itself clk for its internal basic logic to work. */ if (saif != master_saif) { - clk_enable(saif->clk); + ret = clk_enable(saif->clk); + if (ret) { + dev_err(saif->dev, "Failed to enable master clock\n"); + clk_disable(master_saif->clk); + return ret; + } + __raw_writel(BM_SAIF_CTRL_RUN, saif->base + SAIF_CTRL + MXS_SET_ADDR); } + if (!master_saif->mclk_in_use) + __raw_writel(BM_SAIF_CTRL_RUN, + master_saif->base + SAIF_CTRL + MXS_SET_ADDR); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* * write data to saif data register to trigger -- cgit v0.10.2 From de0022d4bf3a5acaef75cf1c7c2f8d71b020e8c9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 16 Oct 2013 15:58:48 +0530 Subject: ASoC: smdk_wm8994: Add .pm to struct smdk_audio_driver Register PM ops for this driver. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 831972d..b072bd1 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -9,6 +9,7 @@ #include "../codecs/wm8994.h" #include +#include #include #include #include @@ -206,6 +207,7 @@ static struct platform_driver smdk_audio_driver = { .name = "smdk-audio-wm8894", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_wm8994_of_match), + .pm = &snd_soc_pm_ops, }, .probe = smdk_audio_probe, }; -- cgit v0.10.2 From a7ea1b7249adc8c090a0b277ab5f3737ee4023c1 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 11 Oct 2013 17:23:56 +0530 Subject: ASoC: cs4271: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index a20f1bb..f6e9534 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 193a47162c93afa09fffd04a04443f14d402c606 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 11 Oct 2013 17:23:57 +0530 Subject: ASoC: pcm1681: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 651ce09..54ea15b 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 4b2fa5121c758db6fe9ed4931b54e390661395de Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 11 Oct 2013 17:23:58 +0530 Subject: ASoC: pcm1792a: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 2a8eccf..6f14c50 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "pcm1792a.h" -- cgit v0.10.2 From 285d00c11b0a8d0ef63c176f88caab5071c9e80d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 11 Oct 2013 17:23:59 +0530 Subject: ASoC: tas5086: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 2996d2e..fe4d29d 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From b3b70786ec18ef3088b55b76258bbd48d75aee08 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 11 Oct 2013 17:24:00 +0530 Subject: ASoC: tlv320aic3x: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 892c108..f8b9fa6 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 8aa99652cd52af07f4fa49fc50d78ede48c9c9b3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 11 Oct 2013 17:24:01 +0530 Subject: ASoC: atmel: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 802717e..f15bff1 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -37,6 +37,7 @@ #include #include #include +#include #include -- cgit v0.10.2 From beb02cddd64b56081951de9048952f0fa1ff545f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 17 Oct 2013 14:01:35 +0400 Subject: ALSA: pxa: slightly refactor reset handling PXA25x also shows some problems when using interrupts during reset handling. Thus do not use interrupts on all pxa kinds (to detect codec ready state). Instead use a common mdelay-loop on all platforms to detect codecs becoming ready. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Mark Brown diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index e6f4633..99a4668 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -117,8 +117,7 @@ static inline void pxa_ac97_warm_pxa25x(void) { gsr_bits = 0; - GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; - wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); + GCR |= GCR_WARM_RST; } static inline void pxa_ac97_cold_pxa25x(void) @@ -129,8 +128,6 @@ static inline void pxa_ac97_cold_pxa25x(void) gsr_bits = 0; GCR = GCR_COLD_RST; - GCR |= GCR_CDONE_IE|GCR_SDONE_IE; - wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); } #endif @@ -149,8 +146,6 @@ static inline void pxa_ac97_warm_pxa27x(void) static inline void pxa_ac97_cold_pxa27x(void) { - unsigned int timeout; - GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */ @@ -161,29 +156,20 @@ static inline void pxa_ac97_cold_pxa27x(void) udelay(5); clk_disable(ac97conf_clk); GCR = GCR_COLD_RST | GCR_WARM_RST; - timeout = 100; /* wait for the codec-ready bit to be set */ - while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) - mdelay(1); } #endif #ifdef CONFIG_PXA3xx static inline void pxa_ac97_warm_pxa3xx(void) { - int timeout = 100; - gsr_bits = 0; /* Can't use interrupts */ GCR |= GCR_WARM_RST; - while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) - mdelay(1); } static inline void pxa_ac97_cold_pxa3xx(void) { - int timeout = 1000; - /* Hold CLKBPB for 100us */ GCR = 0; GCR = GCR_CLKBPB; @@ -199,14 +185,13 @@ static inline void pxa_ac97_cold_pxa3xx(void) GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); GCR = GCR_WARM_RST | GCR_COLD_RST; - while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) - mdelay(10); } #endif bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) { unsigned long gsr; + unsigned int timeout = 100; #ifdef CONFIG_PXA25x if (cpu_is_pxa25x()) @@ -224,6 +209,10 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) else #endif BUG(); + + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); + gsr = GSR | gsr_bits; if (!(gsr & (GSR_PCR | GSR_SCR))) { printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", @@ -239,6 +228,7 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) { unsigned long gsr; + unsigned int timeout = 1000; #ifdef CONFIG_PXA25x if (cpu_is_pxa25x()) @@ -257,6 +247,9 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) #endif BUG(); + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); + gsr = GSR | gsr_bits; if (!(gsr & (GSR_PCR | GSR_SCR))) { printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", -- cgit v0.10.2 From f62aa9b6c900a9aaf302c1f9ac1883c143afd832 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 17 Oct 2013 14:01:36 +0400 Subject: ALSA: ASoC: pxa: fix pxa2xx-ac97 DAI initialization order After recent changes to codec/DAI initialization order changes, codec driver (wm9712 in my case) tries to access codec prior to pxa2xx_ac97_hw_probe() being called (because DAIs are probed after all codecs are probed). Move hw-related probe/remove/suspend/resume functions to pxa2xx-ac97 driver level, instead of DAI level. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index f1059d9..ae956e3 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -89,33 +89,6 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = { .filter_data = &pxa2xx_ac97_pcm_aux_mic_mono_req, }; -#ifdef CONFIG_PM -static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai) -{ - return pxa2xx_ac97_hw_suspend(); -} - -static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) -{ - return pxa2xx_ac97_hw_resume(); -} - -#else -#define pxa2xx_ac97_suspend NULL -#define pxa2xx_ac97_resume NULL -#endif - -static int pxa2xx_ac97_probe(struct snd_soc_dai *dai) -{ - return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev)); -} - -static int pxa2xx_ac97_remove(struct snd_soc_dai *dai) -{ - pxa2xx_ac97_hw_remove(to_platform_device(dai->dev)); - return 0; -} - static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) @@ -185,10 +158,6 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { { .name = "pxa2xx-ac97", .ac97_control = 1, - .probe = pxa2xx_ac97_probe, - .remove = pxa2xx_ac97_remove, - .suspend = pxa2xx_ac97_suspend, - .resume = pxa2xx_ac97_resume, .playback = { .stream_name = "AC97 Playback", .channels_min = 2, @@ -246,6 +215,12 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) return -ENXIO; } + ret = pxa2xx_ac97_hw_probe(pdev); + if (ret) { + dev_err(&pdev->dev, "PXA2xx AC97 hw probe error (%d)\n", ret); + return ret; + } + ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops); if (ret != 0) return ret; @@ -262,15 +237,34 @@ static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); snd_soc_set_ac97_ops(NULL); + pxa2xx_ac97_hw_remove(pdev); return 0; } +#ifdef CONFIG_PM_SLEEP +static int pxa2xx_ac97_dev_suspend(struct device *dev) +{ + return pxa2xx_ac97_hw_suspend(); +} + +static int pxa2xx_ac97_dev_resume(struct device *dev) +{ + return pxa2xx_ac97_hw_resume(); +} + +static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, + pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume); +#endif + static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_dev_probe, .remove = pxa2xx_ac97_dev_remove, .driver = { .name = "pxa2xx-ac97", .owner = THIS_MODULE, +#ifdef CONFIG_PM_SLEEP + .pm = &pxa2xx_ac97_pm_ops, +#endif }, }; -- cgit v0.10.2 From 7db1698f728e1176cc7869f22565e3faa8ec2b72 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 17 Oct 2013 14:01:37 +0400 Subject: ALSA: ASoC: pxa: add asoc pm callbacks to pxa audio drivers After convertion to snd_soc_register_card, platform driver should reference snd_soc_pm_ops callbacks to properly suspend/resume sound hardware. This was missed during conversion of PXA sound devices. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 5b7d969..08acdc2 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -163,6 +163,7 @@ static struct platform_driver mmp_driver = { .driver = { .name = "brownstone-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = brownstone_probe, .remove = brownstone_remove, diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index f4cce1e..1853d41 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -329,6 +329,7 @@ static struct platform_driver corgi_driver = { .driver = { .name = "corgi-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = corgi_probe, .remove = corgi_remove, diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 70d799b..44b5c09 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -178,6 +178,7 @@ static struct platform_driver e740_driver = { .driver = { .name = "e740-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = e740_probe, .remove = e740_remove, diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index f94d2ab..c34e447 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -160,6 +160,7 @@ static struct platform_driver e750_driver = { .driver = { .name = "e750-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = e750_probe, .remove = e750_remove, diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 8768a64..3137f80 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -150,6 +150,7 @@ static struct platform_driver e800_driver = { .driver = { .name = "e800-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = e800_probe, .remove = e800_remove, diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c index eef1f7b..fd2f4ed 100644 --- a/sound/soc/pxa/imote2.c +++ b/sound/soc/pxa/imote2.c @@ -91,6 +91,7 @@ static struct platform_driver imote2_driver = { .driver = { .name = "imote2-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = imote2_probe, .remove = imote2_remove, diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index bbea778..160c524 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -215,6 +215,7 @@ static struct platform_driver mioa701_wm9713_driver = { .driver = { .name = "mioa701-wm9713", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index e1ffcdd..3284c4b 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -181,6 +181,7 @@ static struct platform_driver palm27x_wm9712_driver = { .driver = { .name = "palm27x-asoc", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, }; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index fafe463..c93e138 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -303,6 +303,7 @@ static struct platform_driver poodle_driver = { .driver = { .name = "poodle-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = poodle_probe, .remove = poodle_remove, diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index a3fe191..1d9c2ed 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -275,6 +275,7 @@ static struct platform_driver tosa_driver = { .driver = { .name = "tosa-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = tosa_probe, .remove = tosa_remove, diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index 13c9ee0..0b535b5 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -160,6 +160,7 @@ static struct platform_driver ttc_dkb_driver = { .driver = { .name = "ttc-dkb-audio", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = ttc_dkb_probe, .remove = ttc_dkb_remove, -- cgit v0.10.2 From 3d8c8bc0250f7cb11f887691b7473b51adcd2bcb Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 17 Oct 2013 11:03:33 -0500 Subject: ASoC: cs42l73: Add platform data support for cs42l73 codec Add support for RST GPIO and Charge Pump Freq in platform data Signed-off-by: Brian Austin Signed-off-by: Mark Brown diff --git a/include/sound/cs42l73.h b/include/sound/cs42l73.h new file mode 100644 index 0000000..f354be4 --- /dev/null +++ b/include/sound/cs42l73.h @@ -0,0 +1,22 @@ +/* + * linux/sound/cs42l73.h -- Platform data for CS42L73 + * + * Copyright (c) 2012 Cirrus Logic Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __CS42L73_H +#define __CS42L73_H + +struct cs42l73_platform_data { + /* RST GPIO */ + unsigned int reset_gpio; + unsigned int chgfreq; + int jack_detection; + unsigned int mclk_freq; +}; + +#endif /* __CS42L73_H */ diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 3b20c86..db9d396 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include "cs42l73.h" struct sp_config { @@ -35,6 +37,7 @@ struct sp_config { u32 srate; }; struct cs42l73_private { + struct cs42l73_platform_data pdata; struct sp_config config[3]; struct regmap *regmap; u32 sysclk; @@ -310,15 +313,6 @@ static const struct soc_enum ng_delay_enum = SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); -static const char * const charge_pump_freq_text[] = { - "0", "1", "2", "3", "4", - "5", "6", "7", "8", "9", - "10", "11", "12", "13", "14", "15" }; - -static const struct soc_enum charge_pump_enum = - SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4, - ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text); - static const char * const cs42l73_mono_mix_texts[] = { "Left", "Right", "Mono Mix"}; @@ -511,8 +505,6 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0), SOC_ENUM("NG Delay", ng_delay_enum), - SOC_ENUM("Charge Pump Frequency", charge_pump_enum), - SOC_DOUBLE_R_TLV("XSP-IP Volume", CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1, attn_tlv), @@ -1367,11 +1359,16 @@ static int cs42l73_probe(struct snd_soc_codec *codec) return ret; } - regcache_cache_only(cs42l73->regmap, true); - cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - cs42l73->mclksel = CS42L73_CLKID_MCLK1; /* MCLK1 as master clk */ + /* Set Charge Pump Frequency */ + if (cs42l73->pdata.chgfreq) + snd_soc_update_bits(codec, CS42L73_CPFCHC, + CS42L73_CHARGEPUMP_MASK, + cs42l73->pdata.chgfreq << 4); + + /* MCLK1 as master clk */ + cs42l73->mclksel = CS42L73_CLKID_MCLK1; cs42l73->mclk = 0; return ret; @@ -1415,6 +1412,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l73_private *cs42l73; + struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev); int ret; unsigned int devid = 0; unsigned int reg; @@ -1426,14 +1424,32 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, return -ENOMEM; } - i2c_set_clientdata(i2c_client, cs42l73); - cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); if (IS_ERR(cs42l73->regmap)) { ret = PTR_ERR(cs42l73->regmap); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); return ret; } + + if (pdata) + cs42l73->pdata = *pdata; + + i2c_set_clientdata(i2c_client, cs42l73); + + if (cs42l73->pdata.reset_gpio) { + ret = gpio_request_one(cs42l73->pdata.reset_gpio, + GPIOF_OUT_INIT_HIGH, "CS42L73 /RST"); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", + cs42l73->pdata.reset_gpio, ret); + return ret; + } + gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0); + gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1); + } + + regcache_cache_bypass(cs42l73->regmap, true); + /* initialize codec */ ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); devid = (reg & 0xFF) << 12; @@ -1444,7 +1460,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®); devid |= (reg & 0xF0) >> 4; - if (devid != CS42L73_DEVID) { ret = -ENODEV; dev_err(&i2c_client->dev, @@ -1462,7 +1477,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, dev_info(&i2c_client->dev, "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); - regcache_cache_only(cs42l73->regmap, true); + regcache_cache_bypass(cs42l73->regmap, false); ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_cs42l73, cs42l73_dai, diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h index f30a4c4..4f83d39 100644 --- a/sound/soc/codecs/cs42l73.h +++ b/sound/soc/codecs/cs42l73.h @@ -159,6 +159,7 @@ #define THMOVLD_115C 2 #define THMOVLD_098C 3 +#define CS42L73_CHARGEPUMP_MASK (0xF0) /* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */ #define SP_3ST (1 << 7) -- cgit v0.10.2 From f9ca060680e7c26a88d990ad9370572274b0d54b Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 17 Oct 2013 11:03:34 -0500 Subject: ASoC: cs42l73: Namespace defines for cs42l73 codec Cleanup to namespace the defines for the cs42l73 driver Signed-off-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index db9d396..89efc3c 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1047,11 +1047,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - mmcc |= MS_MASTER; + mmcc |= CS42L73_MS_MASTER; break; case SND_SOC_DAIFMT_CBS_CFS: - mmcc &= ~MS_MASTER; + mmcc &= ~CS42L73_MS_MASTER; break; default: @@ -1063,11 +1063,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) switch (format) { case SND_SOC_DAIFMT_I2S: - spc &= ~SPDIF_PCM; + spc &= ~CS42L73_SPDIF_PCM; break; case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: - if (mmcc & MS_MASTER) { + if (mmcc & CS42L73_MS_MASTER) { dev_err(codec->dev, "PCM format in slave mode only\n"); return -EINVAL; @@ -1077,25 +1077,25 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) "PCM format is not supported on ASP port\n"); return -EINVAL; } - spc |= SPDIF_PCM; + spc |= CS42L73_SPDIF_PCM; break; default: return -EINVAL; } - if (spc & SPDIF_PCM) { + if (spc & CS42L73_SPDIF_PCM) { /* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */ - spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER); + spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER); switch (format) { case SND_SOC_DAIFMT_DSP_B: if (inv == SND_SOC_DAIFMT_IB_IF) - spc |= PCM_MODE0; + spc |= CS42L73_PCM_MODE0; if (inv == SND_SOC_DAIFMT_IB_NF) - spc |= PCM_MODE1; + spc |= CS42L73_PCM_MODE1; break; case SND_SOC_DAIFMT_DSP_A: if (inv == SND_SOC_DAIFMT_IB_IF) - spc |= PCM_MODE1; + spc |= CS42L73_PCM_MODE1; break; default: return -EINVAL; @@ -1155,7 +1155,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, int mclk_coeff; int srate = params_rate(params); - if (priv->config[id].mmcc & MS_MASTER) { + if (priv->config[id].mmcc & CS42L73_MS_MASTER) { /* CS42L73 Master */ /* MCLK -> srate */ mclk_coeff = @@ -1174,13 +1174,13 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, priv->config[id].spc &= 0xFC; /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */ if (priv->mclk >= 6400000) - priv->config[id].spc |= MCK_SCLK_64FS; + priv->config[id].spc |= CS42L73_MCK_SCLK_64FS; else - priv->config[id].spc |= MCK_SCLK_MCLK; + priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK; } else { /* CS42L73 Slave */ priv->config[id].spc &= 0xFC; - priv->config[id].spc |= MCK_SCLK_64FS; + priv->config[id].spc |= CS42L73_MCK_SCLK_64FS; } /* Update ASRCs */ priv->config[id].srate = srate; @@ -1200,8 +1200,8 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0); - snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0); + snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0); + snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0); break; case SND_SOC_BIAS_PREPARE: @@ -1212,11 +1212,11 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, regcache_cache_only(cs42l73->regmap, false); regcache_sync(cs42l73->regmap); } - snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1); if (cs42l73->shutdwn_delay > 0) { mdelay(cs42l73->shutdwn_delay); cs42l73->shutdwn_delay = 0; @@ -1225,7 +1225,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, * down. */ } - snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); + snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1); break; } codec->dapm.bias_level = level; diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h index 4f83d39..4574618 100644 --- a/sound/soc/codecs/cs42l73.h +++ b/sound/soc/codecs/cs42l73.h @@ -128,60 +128,60 @@ /* Bitfield Definitions */ /* CS42L73_PWRCTL1 */ -#define PDN_ADCB (1 << 7) -#define PDN_DMICB (1 << 6) -#define PDN_ADCA (1 << 5) -#define PDN_DMICA (1 << 4) -#define PDN_LDO (1 << 2) -#define DISCHG_FILT (1 << 1) -#define PDN (1 << 0) +#define CS42L73_PDN_ADCB (1 << 7) +#define CS42L73_PDN_DMICB (1 << 6) +#define CS42L73_PDN_ADCA (1 << 5) +#define CS42L73_PDN_DMICA (1 << 4) +#define CS42L73_PDN_LDO (1 << 2) +#define CS42L73_DISCHG_FILT (1 << 1) +#define CS42L73_PDN (1 << 0) /* CS42L73_PWRCTL2 */ -#define PDN_MIC2_BIAS (1 << 7) -#define PDN_MIC1_BIAS (1 << 6) -#define PDN_VSP (1 << 4) -#define PDN_ASP_SDOUT (1 << 3) -#define PDN_ASP_SDIN (1 << 2) -#define PDN_XSP_SDOUT (1 << 1) -#define PDN_XSP_SDIN (1 << 0) +#define CS42L73_PDN_MIC2_BIAS (1 << 7) +#define CS42L73_PDN_MIC1_BIAS (1 << 6) +#define CS42L73_PDN_VSP (1 << 4) +#define CS42L73_PDN_ASP_SDOUT (1 << 3) +#define CS42L73_PDN_ASP_SDIN (1 << 2) +#define CS42L73_PDN_XSP_SDOUT (1 << 1) +#define CS42L73_PDN_XSP_SDIN (1 << 0) /* CS42L73_PWRCTL3 */ -#define PDN_THMS (1 << 5) -#define PDN_SPKLO (1 << 4) -#define PDN_EAR (1 << 3) -#define PDN_SPK (1 << 2) -#define PDN_LO (1 << 1) -#define PDN_HP (1 << 0) +#define CS42L73_PDN_THMS (1 << 5) +#define CS42L73_PDN_SPKLO (1 << 4) +#define CS42L73_PDN_EAR (1 << 3) +#define CS42L73_PDN_SPK (1 << 2) +#define CS42L73_PDN_LO (1 << 1) +#define CS42L73_PDN_HP (1 << 0) /* Thermal Overload Detect. Requires interrupt ... */ -#define THMOVLD_150C 0 -#define THMOVLD_132C 1 -#define THMOVLD_115C 2 -#define THMOVLD_098C 3 +#define CS42L73_THMOVLD_150C 0 +#define CS42L73_THMOVLD_132C 1 +#define CS42L73_THMOVLD_115C 2 +#define CS42L73_THMOVLD_098C 3 #define CS42L73_CHARGEPUMP_MASK (0xF0) /* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */ -#define SP_3ST (1 << 7) -#define SPDIF_I2S (0 << 6) -#define SPDIF_PCM (1 << 6) -#define PCM_MODE0 (0 << 4) -#define PCM_MODE1 (1 << 4) -#define PCM_MODE2 (2 << 4) -#define PCM_MODE_MASK (3 << 4) -#define PCM_BIT_ORDER (1 << 3) -#define MCK_SCLK_64FS (0 << 0) -#define MCK_SCLK_MCLK (2 << 0) -#define MCK_SCLK_PREMCLK (3 << 0) +#define CS42L73_SP_3ST (1 << 7) +#define CS42L73_SPDIF_I2S (0 << 6) +#define CS42L73_SPDIF_PCM (1 << 6) +#define CS42L73_PCM_MODE0 (0 << 4) +#define CS42L73_PCM_MODE1 (1 << 4) +#define CS42L73_PCM_MODE2 (2 << 4) +#define CS42L73_PCM_MODE_MASK (3 << 4) +#define CS42L73_PCM_BIT_ORDER (1 << 3) +#define CS42L73_MCK_SCLK_64FS (0 << 0) +#define CS42L73_MCK_SCLK_MCLK (2 << 0) +#define CS42L73_MCK_SCLK_PREMCLK (3 << 0) /* CS42L73_xSPMMCC */ -#define MS_MASTER (1 << 7) +#define CS42L73_MS_MASTER (1 << 7) /* CS42L73_DMMCC */ -#define MCLKDIS (1 << 0) -#define MCLKSEL_MCLK2 (1 << 4) -#define MCLKSEL_MCLK1 (0 << 4) +#define CS42L73_MCLKDIS (1 << 0) +#define CS42L73_MCLKSEL_MCLK2 (1 << 4) +#define CS42L73_MCLKSEL_MCLK1 (0 << 4) /* CS42L73 MCLK derived from MCLK1 or MCLK2 */ #define CS42L73_CLKID_MCLK1 0 @@ -195,28 +195,26 @@ #define CS42L73_VSP 2 /* IS1, IM1 */ -#define MIC2_SDET (1 << 6) -#define THMOVLD (1 << 4) -#define DIGMIXOVFL (1 << 3) -#define IPBOVFL (1 << 1) -#define IPAOVFL (1 << 0) +#define CS42L73_MIC2_SDET (1 << 6) +#define CS42L73_THMOVLD (1 << 4) +#define CS42L73_DIGMIXOVFL (1 << 3) +#define CS42L73_IPBOVFL (1 << 1) +#define CS42L73_IPAOVFL (1 << 0) /* Analog Softramp */ -#define ANLGOSFT (1 << 0) +#define CS42L73_ANLGOSFT (1 << 0) /* HP A/B Analog Mute */ -#define HPA_MUTE (1 << 7) +#define CS42L73_HPA_MUTE (1 << 7) /* LO A/B Analog Mute */ -#define LOA_MUTE (1 << 7) +#define CS42L73_LOA_MUTE (1 << 7) /* Digital Mute */ -#define HLAD_MUTE (1 << 0) -#define HLBD_MUTE (1 << 1) -#define SPKD_MUTE (1 << 2) -#define ESLD_MUTE (1 << 3) +#define CS42L73_HLAD_MUTE (1 << 0) +#define CS42L73_HLBD_MUTE (1 << 1) +#define CS42L73_SPKD_MUTE (1 << 2) +#define CS42L73_ESLD_MUTE (1 << 3) /* Misc defines for codec */ -#define CS42L73_RESET_GPIO 143 - #define CS42L73_DEVID 0x00042A73 #define CS42L73_MCLKX_MIN 5644800 #define CS42L73_MCLKX_MAX 38400000 -- cgit v0.10.2 From 6833c452c2fb47353566aa705d68541c6045c796 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 16 Oct 2013 22:05:26 -0700 Subject: ASoC: add snd_soc_of_get_dai_name() default of_xlate Current snd_soc_of_get_dai_name() needs .of_xlate_dai_name() callback on each component drivers. But required behavior on almost all these drivers is just returns its indexed driver's name. This patch adds this feature as default behavior. .of_xlate_dai_name() can overwrite it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index b13eecb..6ed3dc0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -644,10 +644,12 @@ struct snd_soc_component_driver { struct snd_soc_component { const char *name; int id; - int num_dai; struct device *dev; struct list_head list; + struct snd_soc_dai_driver *dai_drv; + int num_dai; + const struct snd_soc_component_driver *driver; }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 67cfb5f..0860a7f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4023,6 +4023,7 @@ __snd_soc_register_component(struct device *dev, cmpnt->dev = dev; cmpnt->driver = cmpnt_drv; + cmpnt->dai_drv = dai_drv; cmpnt->num_dai = num_dai; /* @@ -4548,12 +4549,31 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, if (pos->dev->of_node != args.np) continue; - if (!pos->driver->of_xlate_dai_name) { - ret = -ENOSYS; - break; + if (pos->driver->of_xlate_dai_name) { + ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); + } else { + int id = -1; + + switch (args.args_count) { + case 0: + id = 0; /* same as dai_drv[0] */ + break; + case 1: + id = args.args[0]; + break; + default: + /* not supported */ + break; + } + + if (id < 0 || id >= pos->num_dai) { + ret = -EINVAL; + } else { + *dai_name = pos->dai_drv[id].name; + ret = 0; + } } - ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); break; } mutex_unlock(&client_mutex); -- cgit v0.10.2 From ca50410b731c636b9750c02d5ae45be215056634 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Oct 2013 14:56:13 +0100 Subject: ASoC: wm8962: Move interrupt initalisation to probe() This is more idiomatic and fixes bugs in the error handling paths. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 11d80f3..54379ee 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3377,7 +3377,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) int ret; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); struct wm8962_pdata *pdata = &wm8962->pdata; - int i, trigger, irq_pol; + int i; bool dmicclk, dmicdat; wm8962->codec = codec; @@ -3506,36 +3506,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) wm8962_init_beep(codec); wm8962_init_gpio(codec); - if (wm8962->irq) { - if (pdata->irq_active_low) { - trigger = IRQF_TRIGGER_LOW; - irq_pol = WM8962_IRQ_POL; - } else { - trigger = IRQF_TRIGGER_HIGH; - irq_pol = 0; - } - - snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, - WM8962_IRQ_POL, irq_pol); - - ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq, - trigger | IRQF_ONESHOT, - "wm8962", codec->dev); - if (ret != 0) { - dev_err(codec->dev, "Failed to request IRQ %d: %d\n", - wm8962->irq, ret); - wm8962->irq = 0; - /* Non-fatal */ - } else { - /* Enable some IRQs by default */ - snd_soc_update_bits(codec, - WM8962_INTERRUPT_STATUS_2_MASK, - WM8962_FLL_LOCK_EINT | - WM8962_TEMP_SHUT_EINT | - WM8962_FIFOS_ERR_EINT, 0); - } - } - return 0; } @@ -3544,9 +3514,6 @@ static int wm8962_remove(struct snd_soc_codec *codec) struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); int i; - if (wm8962->irq) - free_irq(wm8962->irq, codec); - cancel_delayed_work_sync(&wm8962->mic_work); wm8962_free_gpio(codec); @@ -3619,7 +3586,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm8962_priv *wm8962; unsigned int reg; - int ret, i; + int ret, i, irq_pol, trigger; wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv), GFP_KERNEL); @@ -3714,6 +3681,37 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, ret); } + if (wm8962->irq) { + if (pdata->irq_active_low) { + trigger = IRQF_TRIGGER_LOW; + irq_pol = WM8962_IRQ_POL; + } else { + trigger = IRQF_TRIGGER_HIGH; + irq_pol = 0; + } + + regmap_update_bits(wm8962->regmap, WM8962_INTERRUPT_CONTROL, + WM8962_IRQ_POL, irq_pol); + + ret = devm_request_threaded_irq(&i2c->dev, wm8962->irq, NULL, + wm8962_irq, + trigger | IRQF_ONESHOT, + "wm8962", &i2c->dev); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + wm8962->irq, ret); + wm8962->irq = 0; + /* Non-fatal */ + } else { + /* Enable some IRQs by default */ + regmap_update_bits(wm8962->regmap, + WM8962_INTERRUPT_STATUS_2_MASK, + WM8962_FLL_LOCK_EINT | + WM8962_TEMP_SHUT_EINT | + WM8962_FIFOS_ERR_EINT, 0); + } + } + pm_runtime_enable(&i2c->dev); pm_request_idle(&i2c->dev); -- cgit v0.10.2 From 78b78f5c019e5c68c88afad4b0d3070becde939e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Oct 2013 15:04:21 +0100 Subject: ASoC: wm8962: Move register initialisation to I2C probe() This is more idiomatic and is required for robust operation since we must ensure that the clocking configuration is valid as rapidly as possible. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 54379ee..2bf9ee7 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3242,7 +3242,7 @@ static void wm8962_free_beep(struct snd_soc_codec *codec) } #endif -static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio) +static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio) { int mask = 0; int val = 0; @@ -3263,8 +3263,8 @@ static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio) } if (mask) - snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1, - mask, val); + regmap_update_bits(wm8962->regmap, WM8962_ANALOGUE_CLOCKING1, + mask, val); } #ifdef CONFIG_GPIOLIB @@ -3276,7 +3276,6 @@ static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip) static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) { struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); - struct snd_soc_codec *codec = wm8962->codec; /* The WM8962 GPIOs aren't linearly numbered. For simplicity * we export linear numbers and error out if the unsupported @@ -3292,7 +3291,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) return -EINVAL; } - wm8962_set_gpio_mode(codec, offset + 1); + wm8962_set_gpio_mode(wm8962, offset + 1); return 0; } @@ -3376,7 +3375,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) { int ret; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - struct wm8962_pdata *pdata = &wm8962->pdata; int i; bool dmicclk, dmicdat; @@ -3409,75 +3407,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) } } - /* SYSCLK defaults to on; make sure it is off so we can safely - * write to registers if the device is declocked. - */ - snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0); - - /* Ensure we have soft control over all registers */ - snd_soc_update_bits(codec, WM8962_CLOCKING2, - WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); - - /* Ensure that the oscillator and PLLs are disabled */ - snd_soc_update_bits(codec, WM8962_PLL2, - WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, - 0); - - /* Apply static configuration for GPIOs */ - for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) - if (pdata->gpio_init[i]) { - wm8962_set_gpio_mode(codec, i + 1); - snd_soc_write(codec, 0x200 + i, - pdata->gpio_init[i] & 0xffff); - } - - - /* Put the speakers into mono mode? */ - if (pdata->spk_mono) - snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2, - WM8962_SPK_MONO_MASK, WM8962_SPK_MONO); - - /* Micbias setup, detection enable and detection - * threasholds. */ - if (pdata->mic_cfg) - snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4, - WM8962_MICDET_ENA | - WM8962_MICDET_THR_MASK | - WM8962_MICSHORT_THR_MASK | - WM8962_MICBIAS_LVL, - pdata->mic_cfg); - - /* Latch volume update bits */ - snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME, - WM8962_IN_VU, WM8962_IN_VU); - snd_soc_update_bits(codec, WM8962_RIGHT_INPUT_VOLUME, - WM8962_IN_VU, WM8962_IN_VU); - snd_soc_update_bits(codec, WM8962_LEFT_ADC_VOLUME, - WM8962_ADC_VU, WM8962_ADC_VU); - snd_soc_update_bits(codec, WM8962_RIGHT_ADC_VOLUME, - WM8962_ADC_VU, WM8962_ADC_VU); - snd_soc_update_bits(codec, WM8962_LEFT_DAC_VOLUME, - WM8962_DAC_VU, WM8962_DAC_VU); - snd_soc_update_bits(codec, WM8962_RIGHT_DAC_VOLUME, - WM8962_DAC_VU, WM8962_DAC_VU); - snd_soc_update_bits(codec, WM8962_SPKOUTL_VOLUME, - WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); - snd_soc_update_bits(codec, WM8962_SPKOUTR_VOLUME, - WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); - snd_soc_update_bits(codec, WM8962_HPOUTL_VOLUME, - WM8962_HPOUT_VU, WM8962_HPOUT_VU); - snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, - WM8962_HPOUT_VU, WM8962_HPOUT_VU); - - /* Stereo control for EQ */ - snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0); - - /* Don't debouce interrupts so we don't need SYSCLK */ - snd_soc_update_bits(codec, WM8962_IRQ_DEBOUNCE, - WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB | - WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB, - 0); - wm8962_add_widgets(codec); /* Save boards having to disable DMIC when not in use */ @@ -3671,6 +3600,77 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, goto err_enable; } + /* SYSCLK defaults to on; make sure it is off so we can safely + * write to registers if the device is declocked. + */ + regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, + WM8962_SYSCLK_ENA, 0); + + /* Ensure we have soft control over all registers */ + regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, + WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); + + /* Ensure that the oscillator and PLLs are disabled */ + regmap_update_bits(wm8962->regmap, WM8962_PLL2, + WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, + 0); + + /* Apply static configuration for GPIOs */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) + if (pdata->gpio_init[i]) { + wm8962_set_gpio_mode(wm8962, i + 1); + regmap_write(wm8962->regmap, 0x200 + i, + pdata->gpio_init[i] & 0xffff); + } + + + /* Put the speakers into mono mode? */ + if (pdata->spk_mono) + regmap_update_bits(wm8962->regmap, WM8962_CLASS_D_CONTROL_2, + WM8962_SPK_MONO_MASK, WM8962_SPK_MONO); + + /* Micbias setup, detection enable and detection + * threasholds. */ + if (pdata->mic_cfg) + regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, + WM8962_MICDET_ENA | + WM8962_MICDET_THR_MASK | + WM8962_MICSHORT_THR_MASK | + WM8962_MICBIAS_LVL, + pdata->mic_cfg); + + /* Latch volume update bits */ + regmap_update_bits(wm8962->regmap, WM8962_LEFT_INPUT_VOLUME, + WM8962_IN_VU, WM8962_IN_VU); + regmap_update_bits(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME, + WM8962_IN_VU, WM8962_IN_VU); + regmap_update_bits(wm8962->regmap, WM8962_LEFT_ADC_VOLUME, + WM8962_ADC_VU, WM8962_ADC_VU); + regmap_update_bits(wm8962->regmap, WM8962_RIGHT_ADC_VOLUME, + WM8962_ADC_VU, WM8962_ADC_VU); + regmap_update_bits(wm8962->regmap, WM8962_LEFT_DAC_VOLUME, + WM8962_DAC_VU, WM8962_DAC_VU); + regmap_update_bits(wm8962->regmap, WM8962_RIGHT_DAC_VOLUME, + WM8962_DAC_VU, WM8962_DAC_VU); + regmap_update_bits(wm8962->regmap, WM8962_SPKOUTL_VOLUME, + WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); + regmap_update_bits(wm8962->regmap, WM8962_SPKOUTR_VOLUME, + WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); + regmap_update_bits(wm8962->regmap, WM8962_HPOUTL_VOLUME, + WM8962_HPOUT_VU, WM8962_HPOUT_VU); + regmap_update_bits(wm8962->regmap, WM8962_HPOUTR_VOLUME, + WM8962_HPOUT_VU, WM8962_HPOUT_VU); + + /* Stereo control for EQ */ + regmap_update_bits(wm8962->regmap, WM8962_EQ1, + WM8962_EQ_SHARED_COEFF, 0); + + /* Don't debouce interrupts so we don't need SYSCLK */ + regmap_update_bits(wm8962->regmap, WM8962_IRQ_DEBOUNCE, + WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB | + WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB, + 0); + if (wm8962->pdata.in4_dc_measure) { ret = regmap_register_patch(wm8962->regmap, wm8962_dc_measure, -- cgit v0.10.2 From 6197c34425c3d9a622d3a7031c91104909224a67 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 14:09:27 +0100 Subject: ASoC: cirrus: Enable compile test builds The core support for ep93xx (currently only the DMA driver) does not depend on the architecture at all and everything else has more strict dependencies so enable compile test builds for improved build coverage. Signed-off-by: Mark Brown diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 2c20f01..06f938d 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -1,6 +1,6 @@ config SND_EP93XX_SOC tristate "SoC Audio support for the Cirrus Logic EP93xx series" - depends on ARCH_EP93XX && SND_SOC + depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to -- cgit v0.10.2 From e58f301ec969430cdafd7fa872660458f4939507 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 16 Oct 2013 17:26:22 +0100 Subject: ASoC: rt5640: Power down LDO while suspended If we have control over the LDO then disable it during suspend; the device is already being put into reset so will be non-functional over suspend anyway and this will save a small amount of power. Signed-off-by: Mark Brown Tested-by: Stephen Warren diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 641eeeb..b0cde92 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1979,12 +1979,20 @@ static int rt5640_suspend(struct snd_soc_codec *codec) rt5640_reset(codec); regcache_cache_only(rt5640->regmap, true); regcache_mark_dirty(rt5640->regmap); + if (gpio_is_valid(rt5640->pdata.ldo1_en)) + gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0); return 0; } static int rt5640_resume(struct snd_soc_codec *codec) { + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + + if (gpio_is_valid(rt5640->pdata.ldo1_en)) { + gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1); + msleep(400); + } rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; -- cgit v0.10.2 From ebce31140c2ddfda005e88957ac1ee1eacaa8dc5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 16 Oct 2013 17:30:44 +0100 Subject: ASoC: rt5640: Don't go to standby on resume There is no need for the CODEC to go to standby on resume since the core will power it up as needed and in any case it is an idle_bias_off CODEC so would normally sit with bias off while idle. Signed-off-by: Mark Brown Tested-by: Stephen Warren diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index b0cde92..4d041d3 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1993,7 +1993,6 @@ static int rt5640_resume(struct snd_soc_codec *codec) gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1); msleep(400); } - rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } -- cgit v0.10.2 From c0de42bf595238e9dd593405ebc2992cc8470732 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 8 Oct 2013 15:07:59 +0200 Subject: ASoC: dmaengine-pcm: Add support for querying DMA capabilities Currently each platform making use the the generic dmaengine PCM driver still needs to provide a custom snd_pcm_hardware struct which specifies the capabilities of the DMA controller, e.g. the maximum period size that can be supported. This patch adds code which uses the newly introduced dma_get_slave_caps() API to query this information from the dmaengine driver. The new code path will only be taken if the 'pcm_hardware' field of the snd_dmaengine_pcm_config struct is NULL. The patch also introduces a new 'fifo_size' field to the snd_dmaengine_dai_dma_data struct which is used to initialize the snd_pcm_hardware 'fifo_size' field and needs to be set by the DAI driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index f11c35c..83b2c3e 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -61,6 +61,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. + * @fifo_size: FIFO size of the DAI controller in bytes */ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; @@ -68,6 +69,7 @@ struct snd_dmaengine_dai_dma_data { u32 maxburst; unsigned int slave_id; void *filter_data; + unsigned int fifo_size; }; void snd_dmaengine_pcm_set_config_from_dai_data( diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index e29ec3c..c39e19e 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -36,6 +36,15 @@ static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) return container_of(p, struct dmaengine_pcm, platform); } +static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, + struct snd_pcm_substream *substream) +{ + if (!pcm->chan[substream->stream]) + return NULL; + + return pcm->chan[substream->stream]->device->dev; +} + /** * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback * @substream: PCM substream @@ -92,28 +101,54 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static int dmaengine_pcm_open(struct snd_pcm_substream *substream) +static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct device *dma_dev = dmaengine_dma_dev(pcm, substream); struct dma_chan *chan = pcm->chan[substream->stream]; + struct snd_dmaengine_dai_dma_data *dma_data; + struct dma_slave_caps dma_caps; + struct snd_pcm_hardware hw; int ret; - ret = snd_soc_set_runtime_hwparams(substream, + if (pcm->config->pcm_hardware) + return snd_soc_set_runtime_hwparams(substream, pcm->config->pcm_hardware); - if (ret) - return ret; - return snd_dmaengine_pcm_open(substream, chan); + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + memset(&hw, 0, sizeof(hw)); + hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED; + hw.periods_min = 2; + hw.periods_max = UINT_MAX; + hw.period_bytes_min = 256; + hw.period_bytes_max = dma_get_max_seg_size(dma_dev); + hw.buffer_bytes_max = SIZE_MAX; + hw.fifo_size = dma_data->fifo_size; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret == 0) { + if (dma_caps.cmd_pause) + hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + } + + return snd_soc_set_runtime_hwparams(substream, &hw); } -static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, - struct snd_pcm_substream *substream) +static int dmaengine_pcm_open(struct snd_pcm_substream *substream) { - if (!pcm->chan[substream->stream]) - return NULL; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct dma_chan *chan = pcm->chan[substream->stream]; + int ret; - return pcm->chan[substream->stream]->device->dev; + ret = dmaengine_pcm_set_runtime_hwparams(substream); + if (ret) + return ret; + + return snd_dmaengine_pcm_open(substream, chan); } static void dmaengine_pcm_free(struct snd_pcm *pcm) -- cgit v0.10.2 From fa654e085300e9c222ef931bc0702a9df2542666 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 8 Oct 2013 15:08:00 +0200 Subject: ASoC: dmaengine-pcm: Provide default config This patch adds some default settings for the generic dmaengine PCM driver for the case that no config has been supplied. The following defaults are used: * Use snd_dmaengine_pcm_prepare_slave_config for preparing the DMA slave config. * 512kB for the prealloc buffer size. This value has been chosen based on 'feels about right' and is not backed up by any scientific facts. We may need to come up with something smarter in the future but it should work fine for now. With this infrastructure in place we can finally write DAI drivers which are independent of the DMA controller they are connected to. This is e.g. useful if the DAI IP core is reused across different SoCs, but the SoCs uses different DMA controllers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index c39e19e..99f9495 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -84,12 +84,19 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); + int (*prepare_slave_config)(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config); struct dma_slave_config slave_config; int ret; - if (pcm->config->prepare_slave_config) { - ret = pcm->config->prepare_slave_config(substream, params, - &slave_config); + if (!pcm->config) + prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; + else + prepare_slave_config = pcm->config->prepare_slave_config; + + if (prepare_slave_config) { + ret = prepare_slave_config(substream, params, &slave_config); if (ret) return ret; @@ -112,7 +119,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea struct snd_pcm_hardware hw; int ret; - if (pcm->config->pcm_hardware) + if (pcm->config && pcm->config->pcm_hardware) return snd_soc_set_runtime_hwparams(substream, pcm->config->pcm_hardware); @@ -177,9 +184,20 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; struct snd_pcm_substream *substream; + size_t prealloc_buffer_size; + size_t max_buffer_size; unsigned int i; int ret; + if (config && config->prealloc_buffer_size) { + prealloc_buffer_size = config->prealloc_buffer_size; + max_buffer_size = config->pcm_hardware->buffer_bytes_max; + } else { + prealloc_buffer_size = 512 * 1024; + max_buffer_size = SIZE_MAX; + } + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { substream = rtd->pcm->streams[i].substream; if (!substream) @@ -200,8 +218,8 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) ret = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, dmaengine_dma_dev(pcm, substream), - config->prealloc_buffer_size, - config->pcm_hardware->buffer_bytes_max); + prealloc_buffer_size, + max_buffer_size); if (ret) goto err_free; } -- cgit v0.10.2 From ecfc0c04f236f1e2a95094792ec10cf27be39f7c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Oct 2013 21:13:19 +0100 Subject: ASoC: dai: Provide interface for setting DMA data at probe time Allow DMA data to be set at probe time for devices that can do that, avoiding the need to do it every time we start a stream and supporting non-DT dmaengine users using the helpers. Signed-off-by: Mark Brown diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ae9a227..97943fd 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -276,6 +276,13 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai, dai->capture_dma_data = data; } +static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, + void *playback, void *capture) +{ + dai->playback_dma_data = playback; + dai->capture_dma_data = capture; +} + static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai, void *data) { -- cgit v0.10.2 From 511e30331745e0c3452b89354a4b94c0e60f15a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Oct 2013 21:18:40 +0100 Subject: ASoC: samsung: Initialise DMA data at device probe time This is a minor simplification and will help with converting the platform to use the dmaengine helpers. Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b302f3b..3e08b6c 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -702,13 +702,6 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, } writel(mod, i2s->addr + I2SMOD); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_playback); - else - snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_capture); - i2s->frmclk = params_rate(params); return 0; @@ -970,6 +963,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) } clk_prepare_enable(i2s->clk); + snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); + if (other) { other->addr = i2s->addr; other->clk = i2s->clk; -- cgit v0.10.2 From e244bb9bc1883547d44642c99f483c2e57e2a940 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Oct 2013 22:46:49 -0700 Subject: ASoC: simple-card: un-implemented set_fmt is not error Current simple-card returns error if DAI doesn't support .set_fmt callback. But the error is -ENOTSUPP (= not supported), and it is not error. This patch avoids such case Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 8c49147..b2fbb70 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -27,6 +27,11 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, if (!ret && daifmt) ret = snd_soc_dai_set_fmt(dai, daifmt); + if (ret == -ENOTSUPP) { + dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n"); + ret = 0; + } + if (!ret && set->sysclk) ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); -- cgit v0.10.2 From cdcfcac968a1ec648434892b6addd80e66a5a892 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Oct 2013 22:50:59 -0700 Subject: ASoC: rcar: add rsnd_scu_hpbif_is_enable() Current SSI needs RSND_SSI_DEPENDENT flag to decide dependent/independent mode. And SCU needs RSND_SCU_USE_HPBIF flag to decide HPBIF is enable/disable. But these 2 means same things. This patch adds new rsnd_scu_hpbif_is_enable() function, and merges above methods. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index fe66533..6b4211c 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -36,7 +36,6 @@ #define RSND_SSI_CLK_PIN_SHARE (1 << 31) #define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */ #define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */ -#define RSND_SSI_DEPENDENT (1 << 28) /* SSI needs SRU/SCU */ #define RSND_SSI_PLAY (1 << 24) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 3868aaf..5feb67c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -281,6 +281,7 @@ int rsnd_scu_probe(struct platform_device *pdev, void rsnd_scu_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); +bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); #define rsnd_scu_nr(priv) ((priv)->scu_nr) /* diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 2df2e91..1ab1bce 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -146,20 +146,26 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, return 0; } +bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod) +{ + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + u32 flags = rsnd_scu_mode_flags(scu); + + return !!(flags & RSND_SCU_USE_HPBIF); +} + static int rsnd_scu_start(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_scu *scu = rsnd_mod_to_scu(mod); struct device *dev = rsnd_priv_to_dev(priv); - u32 flags = rsnd_scu_mode_flags(scu); int ret; /* * SCU will be used if it has RSND_SCU_USE_HPBIF flags */ - if (!(flags & RSND_SCU_USE_HPBIF)) { + if (!rsnd_scu_hpbif_is_enable(mod)) { /* it use PIO transter */ dev_dbg(dev, "%s%d is not used\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index fae26d3..7613256 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -106,6 +106,7 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv, { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ssi *ssi; + struct rsnd_mod *scu; u32 flags; u32 val; int i; @@ -116,13 +117,14 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv, ssiu->ssi_mode0 = 0; for_each_rsnd_ssi(ssi, priv, i) { flags = rsnd_ssi_mode_flags(ssi); + scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod)); /* see also BUSIF_MODE */ - if (!(flags & RSND_SSI_DEPENDENT)) { + if (rsnd_scu_hpbif_is_enable(scu)) { + dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i); + } else { ssiu->ssi_mode0 |= (1 << i); dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i); - } else { - dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i); } } -- cgit v0.10.2 From 92eba04e4bcd469518cc759ac1bf1a49acaa5cc1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Oct 2013 22:51:40 -0700 Subject: ASoC: rcar: remove RSND_SSI_CLK_FROM_ADG R-Car sound has clock pin for each SSI, and sometimes, these pins are shared with paired SSI. It may sometimes become "SSI-A clock pin is master" and "SSI-B clock pin is slave", but "SSI-A/B clock pins are shared". SSI-B needs SSI-A clock in this case. Current R-Car sound driver is using RSND_SSI_xxx flag to control this kind of shared pin behavior. But, this information, especially clock master setting, can be got from ASoC set_fmt settings. This patch removes rsnd_ssi_mode_init() and extend rsnd_ssi_mode_set() to controlling pin settings via .set_fmt. This patch doesn't removes RSND_SSI_CLK_FROM_ADG flag at this point to avoid conflict branch merging between ASoC <-> SH-ARM. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7613256..b71cf9d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -101,31 +101,30 @@ struct rsnd_ssiu { #define rsnd_ssi_to_ssiu(ssi)\ (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) -static void rsnd_ssi_mode_init(struct rsnd_priv *priv, - struct rsnd_ssiu *ssiu) +static void rsnd_ssi_mode_set(struct rsnd_priv *priv, + struct rsnd_dai *rdai, + struct rsnd_ssi *ssi) { struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_ssi *ssi; struct rsnd_mod *scu; + struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); + int id = rsnd_mod_id(&ssi->mod); u32 flags; u32 val; - int i; + + scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod)); /* * SSI_MODE0 */ - ssiu->ssi_mode0 = 0; - for_each_rsnd_ssi(ssi, priv, i) { - flags = rsnd_ssi_mode_flags(ssi); - scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod)); - - /* see also BUSIF_MODE */ - if (rsnd_scu_hpbif_is_enable(scu)) { - dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i); - } else { - ssiu->ssi_mode0 |= (1 << i); - dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i); - } + + /* see also BUSIF_MODE */ + if (rsnd_scu_hpbif_is_enable(scu)) { + ssiu->ssi_mode0 &= ~(1 << id); + dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id); + } else { + ssiu->ssi_mode0 |= (1 << id); + dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id); } /* @@ -134,7 +133,7 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv, #define ssi_parent_set(p, sync, adg, ext) \ do { \ ssi->parent = ssiu->ssi + p; \ - if (flags & RSND_SSI_CLK_FROM_ADG) \ + if (rsnd_rdai_is_clk_master(rdai)) \ val = adg; \ else \ val = ext; \ @@ -142,15 +141,11 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv, val |= sync; \ } while (0) - ssiu->ssi_mode1 = 0; - for_each_rsnd_ssi(ssi, priv, i) { - flags = rsnd_ssi_mode_flags(ssi); - - if (!(flags & RSND_SSI_CLK_PIN_SHARE)) - continue; + flags = rsnd_ssi_mode_flags(ssi); + if (flags & RSND_SSI_CLK_PIN_SHARE) { val = 0; - switch (i) { + switch (id) { case 1: ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); break; @@ -167,11 +162,6 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv, ssiu->ssi_mode1 |= val; } -} - -static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi) -{ - struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); @@ -381,7 +371,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, ssi->cr_own = cr; ssi->err = -1; /* ignore 1st error */ - rsnd_ssi_mode_set(ssi); + rsnd_ssi_mode_set(priv, rdai, ssi); dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); @@ -708,8 +698,6 @@ int rsnd_ssi_probe(struct platform_device *pdev, rsnd_mod_init(priv, &ssi->mod, ops, i); } - rsnd_ssi_mode_init(priv, ssiu); - dev_dbg(dev, "ssi probed\n"); return 0; -- cgit v0.10.2 From 1f1b65796ef882bb9101d22b17e1a1824b3a6489 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 18 Oct 2013 20:34:52 +0200 Subject: ASoC: kirkwood: prefer external clock over internal clock When there is an external clock, always use this one. This prevents the two Dove audio devices to use the same DCO clock at different rates. Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 3e59af9..d0504a2 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -103,7 +103,7 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai, { uint32_t clks_ctrl; - if (rate == 44100 || rate == 48000 || rate == 96000) { + if (IS_ERR(priv->extclk)) { /* use internal dco for the supported rates * defined in kirkwood_i2s_dai */ dev_dbg(dai->dev, "%s: dco set rate = %lu\n", -- cgit v0.10.2 From 7b09eea52939d2b979f19de40e34b8670feff4c5 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Fri, 18 Oct 2013 14:30:01 -0500 Subject: ASoC: cs42l73: Add Device Tree support for CS42L73 This patch adds support for device tree for the CS42L73 CODEC Signed-off-by: Brian Austin Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/cs42l73.txt b/Documentation/devicetree/bindings/sound/cs42l73.txt new file mode 100644 index 0000000..80ae910 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs42l73.txt @@ -0,0 +1,22 @@ +CS42L73 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l73" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset_gpio : a GPIO spec for the reset pin. + - chgfreq : Charge Pump Frequency values 0x00-0x0F + + +Example: + +codec: cs42l73@4a { + compatible = "cirrus,cs42l73"; + reg = <0x4a>; + reset_gpio = <&gpio 10 0>; + chgfreq = <0x05>; +}; \ No newline at end of file diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 89efc3c..549d5d6 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -1416,6 +1416,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, int ret; unsigned int devid = 0; unsigned int reg; + u32 val32; cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private), GFP_KERNEL); @@ -1431,8 +1432,25 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, return ret; } - if (pdata) + if (pdata) { cs42l73->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs42l73_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + if (of_property_read_u32(i2c_client->dev.of_node, + "chgfreq", &val32) >= 0) + pdata->chgfreq = val32; + } + pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node, + "reset-gpio", 0); + cs42l73->pdata = *pdata; + } i2c_set_clientdata(i2c_client, cs42l73); @@ -1493,6 +1511,12 @@ static int cs42l73_i2c_remove(struct i2c_client *client) return 0; } +static const struct of_device_id cs42l73_of_match[] = { + { .compatible = "cirrus,cs42l73", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs42l73_of_match); + static const struct i2c_device_id cs42l73_id[] = { {"cs42l73", 0}, {} @@ -1504,6 +1528,7 @@ static struct i2c_driver cs42l73_i2c_driver = { .driver = { .name = "cs42l73", .owner = THIS_MODULE, + .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, .probe = cs42l73_i2c_probe, -- cgit v0.10.2 From cfcff69af8447df8dd3c5b14349c3b84b8b569a5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 20 Oct 2013 18:14:20 +0100 Subject: ASoC: si476x: Fix locking of core The conversion of the si476x to regmap removed locking of the core during register updates, allowing things like power state changes for the MFD to happen during a register update. Avoid this by taking the core lock in the DAI operations (which are the only things that do register updates) as we used to do in the open coded register I/O functions. Signed-off-by: Mark Brown Acked-by: Andrey Smirnov diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 03645ce..52e7cb0 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -73,6 +73,7 @@ static const struct snd_soc_dapm_route si476x_dapm_routes[] = { static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { + struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev); int err; u16 format = 0; @@ -136,9 +137,14 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } + si476x_core_lock(core); + err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK, format); + + si476x_core_unlock(core); + if (err < 0) { dev_err(codec_dai->codec->dev, "Failed to set output format\n"); return err; @@ -151,6 +157,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev); int rate, width, err; rate = params_rate(params); @@ -176,11 +183,13 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + si476x_core_lock(core); + err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE, rate); if (err < 0) { dev_err(dai->codec->dev, "Failed to set sample rate\n"); - return err; + goto out; } err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, @@ -189,10 +198,13 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)); if (err < 0) { dev_err(dai->codec->dev, "Failed to set output width\n"); - return err; + goto out; } - return 0; +out: + si476x_core_unlock(core); + + return err; } static int si476x_codec_probe(struct snd_soc_codec *codec) -- cgit v0.10.2 From 30a765d6433413c0eba90c969eecf12dfa2d111a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 21 Oct 2013 19:07:34 +0530 Subject: ASoC: dont call dapm_sync while reporting jack always While reporting the jack status snd_soc_jack_report() invokes snd_soc_dapm_sync() always. This should be required when we have pins associated with jack and reporting enables or disables these. So add a check for this case Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 71358e3..23d43da 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -65,6 +65,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_codec *codec; struct snd_soc_dapm_context *dapm; struct snd_soc_jack_pin *pin; + unsigned int sync = 0; int enable; trace_snd_soc_jack_report(jack, mask, status); @@ -92,12 +93,16 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) snd_soc_dapm_enable_pin(dapm, pin->pin); else snd_soc_dapm_disable_pin(dapm, pin->pin); + + /* we need to sync for this case only */ + sync = 1; } /* Report before the DAPM sync to help users updating micbias status */ blocking_notifier_call_chain(&jack->notifier, jack->status, jack); - snd_soc_dapm_sync(dapm); + if (sync) + snd_soc_dapm_sync(dapm); snd_jack_report(jack->jack, jack->status); -- cgit v0.10.2 From 75b9b65ee5a80e99efe2fd551d08bc86f115550f Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Mon, 21 Oct 2013 10:50:49 +0200 Subject: ASoC: kirkwood: add S/PDIF support This patch adds S/PDIF input/output for mvebu DT boards. Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index d0504a2..9ec38d1 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -160,9 +160,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | - KIRKWOOD_PLAYCTL_I2S_EN; + KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN; ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | - KIRKWOOD_RECCTL_I2S_EN; + KIRKWOOD_RECCTL_I2S_EN | + KIRKWOOD_RECCTL_SPDIF_EN; break; /* * doesn't work... S20_3LE != kirkwood 20bit format ? @@ -178,9 +180,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S24_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | - KIRKWOOD_PLAYCTL_I2S_EN; + KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN; ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | - KIRKWOOD_RECCTL_I2S_EN; + KIRKWOOD_RECCTL_I2S_EN | + KIRKWOOD_RECCTL_SPDIF_EN; break; case SNDRV_PCM_FORMAT_S32_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; @@ -240,6 +244,11 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, ctl); } + if (dai->id == 0) + ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ + else + ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ + switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* configure */ @@ -258,7 +267,8 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: /* stop audio, disable interrupts */ - ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | + KIRKWOOD_PLAYCTL_SPDIF_MUTE; writel(ctl, priv->io + KIRKWOOD_PLAYCTL); value = readl(priv->io + KIRKWOOD_INT_MASK); @@ -272,13 +282,15 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | + KIRKWOOD_PLAYCTL_SPDIF_MUTE; writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); + ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | + KIRKWOOD_PLAYCTL_SPDIF_MUTE); writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; @@ -301,7 +313,13 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: /* configure */ ctl = priv->ctl_rec; - value = ctl & ~KIRKWOOD_RECCTL_I2S_EN; + if (dai->id == 0) + ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */ + else + ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ + + value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN | + KIRKWOOD_RECCTL_SPDIF_EN); writel(value, priv->io + KIRKWOOD_RECCTL); /* enable interrupts */ @@ -361,9 +379,8 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int kirkwood_i2s_probe(struct snd_soc_dai *dai) +static int kirkwood_i2s_init(struct kirkwood_dma_data *priv) { - struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); unsigned long value; unsigned int reg_data; @@ -404,9 +421,29 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { .set_fmt = kirkwood_i2s_set_fmt, }; - -static struct snd_soc_dai_driver kirkwood_i2s_dai = { - .probe = kirkwood_i2s_probe, +static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = { + { + .name = "i2s", + .id = 0, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .ops = &kirkwood_i2s_dai_ops, + }, + { + .name = "spdif", + .id = 1, .playback = { .channels_min = 1, .channels_max = 2, @@ -422,10 +459,34 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { .formats = KIRKWOOD_I2S_FORMATS, }, .ops = &kirkwood_i2s_dai_ops, + }, }; -static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { - .probe = kirkwood_i2s_probe, +static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = { + { + .name = "i2s", + .id = 0, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .ops = &kirkwood_i2s_dai_ops, + }, + { + .name = "spdif", + .id = 1, .playback = { .channels_min = 1, .channels_max = 2, @@ -443,6 +504,7 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { .formats = KIRKWOOD_I2S_FORMATS, }, .ops = &kirkwood_i2s_dai_ops, + }, }; static const struct snd_soc_component_driver kirkwood_i2s_component = { @@ -452,7 +514,7 @@ static const struct snd_soc_component_driver kirkwood_i2s_component = { static int kirkwood_i2s_dev_probe(struct platform_device *pdev) { struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; - struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; + struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai; struct kirkwood_dma_data *priv; struct resource *mem; struct device_node *np = pdev->dev.of_node; @@ -524,7 +586,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) } err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, - soc_dai, 1); + soc_dai, 2); if (err) { dev_err(&pdev->dev, "snd_soc_register_component failed\n"); goto err_component; @@ -535,6 +597,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "snd_soc_register_platform failed\n"); goto err_platform; } + + kirkwood_i2s_init(priv); + return 0; err_platform: snd_soc_unregister_component(&pdev->dev); diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c index 025be0e..65f2a5b 100644 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ b/sound/soc/kirkwood/kirkwood-openrd.c @@ -52,7 +52,7 @@ static struct snd_soc_dai_link openrd_client_dai[] = { { .name = "CS42L51", .stream_name = "CS42L51 HiFi", - .cpu_dai_name = "mvebu-audio", + .cpu_dai_name = "i2s", .platform_name = "mvebu-audio", .codec_dai_name = "cs42l51-hifi", .codec_name = "cs42l51-codec.0-004a", diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index 27545b0..d213832 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c @@ -68,7 +68,7 @@ static struct snd_soc_dai_link t5325_dai[] = { { .name = "ALC5621", .stream_name = "ALC5621 HiFi", - .cpu_dai_name = "mvebu-audio", + .cpu_dai_name = "i2s", .platform_name = "mvebu-audio", .codec_dai_name = "alc5621-hifi", .codec_name = "alc562x-codec.0-001a", -- cgit v0.10.2 From 256ba181cb2ddeef8e0a9b0540b09e0f77bf5540 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 18 Oct 2013 18:37:42 +0300 Subject: ASoC: davinci-mcasp: Add location for data port registers to DT This patch adds a separate register location for data port registers to mcasp DT bindings. On am33xx SoCs the McASP registers are mapped trough L4 interconnect, but data port registers are also mapped trough L3 bus to a different memory location. Signed-off-by: Hebbar, Gururaja Signed-off-by: Darren Etheridge Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 374e145..c2ab869 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -6,7 +6,11 @@ Required properties: "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms "ti,omap2-mcasp-audio" : for OMAP2 platforms (TI81xx, AM33xx) -- reg : Should contain McASP registers offset and length +- reg : Should contain reg specifiers for the entries in the reg-names property. +- reg-names : Should contain: + * "mpu" for the main registers (required). For compatibility with + existing software, it is recommended this is the first entry. + * "dat" for separate data port register access (optional). - interrupts : Interrupt number for McASP - op-mode : I2S/DIT ops mode. - tdm-slots : Slots for TDM operation. @@ -15,7 +19,6 @@ Required properties: to "num-serializer" parameter. Each entry is a number indication serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) - Optional properties: - ti,hwmods : Must be "mcasp", n is controller instance starting 0 @@ -31,6 +34,7 @@ mcasp0: mcasp0@1d00000 { #address-cells = <1>; #size-cells = <0>; reg = <0x100000 0x3000>; + reg-names "mpu"; interrupts = <82 83>; op-mode = <0>; /* MCASP_IIS_MODE */ tdm-slots = <2>; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index cdfe959..806bec3 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1001,18 +1001,40 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { .name = "davinci-mcasp", }; +/* Some HW specific values and defaults. The rest is filled in from DT. */ +static struct snd_platform_data dm646x_mcasp_pdata = { + .tx_dma_offset = 0x400, + .rx_dma_offset = 0x400, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_1, +}; + +static struct snd_platform_data da830_mcasp_pdata = { + .tx_dma_offset = 0x2000, + .rx_dma_offset = 0x2000, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_2, +}; + +static struct snd_platform_data omap2_mcasp_pdata = { + .tx_dma_offset = 0, + .rx_dma_offset = 0, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_3, +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", - .data = (void *)MCASP_VERSION_1, + .data = &dm646x_mcasp_pdata, }, { .compatible = "ti,da830-mcasp-audio", - .data = (void *)MCASP_VERSION_2, + .data = &da830_mcasp_pdata, }, { .compatible = "ti,omap2-mcasp-audio", - .data = (void *)MCASP_VERSION_3, + .data = &omap2_mcasp_pdata, }, { /* sentinel */ } }; @@ -1035,20 +1057,13 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata = pdev->dev.platform_data; return pdata; } else if (match) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - goto nodata; - } + pdata = (struct snd_platform_data *) match->data; } else { /* control shouldn't reach here. something is wrong */ ret = -EINVAL; goto nodata; } - if (match->data) - pdata->version = (u8)((int)match->data); - ret = of_property_read_u32(np, "op-mode", &val); if (ret >= 0) pdata->op_mode = val; @@ -1124,7 +1139,7 @@ nodata: static int davinci_mcasp_probe(struct platform_device *pdev) { struct davinci_pcm_dma_params *dma_data; - struct resource *mem, *ioarea, *res; + struct resource *mem, *ioarea, *res, *dat; struct snd_platform_data *pdata; struct davinci_audio_dev *dev; int ret; @@ -1145,10 +1160,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev) return -EINVAL; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; + dev_warn(dev->dev, + "\"mpu\" mem resource not found, using index 0\n"); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -ENODEV; + } } ioarea = devm_request_mem_region(&pdev->dev, mem->start, @@ -1182,13 +1202,16 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->rxnumevt = pdata->rxnumevt; dev->dev = &pdev->dev; + dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); + if (!dat) + dat = mem; + dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_playback; - dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + - mem->start); + dma_data->dma_addr = dat->start + pdata->tx_dma_offset; /* first TX, then RX */ res = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -1205,8 +1228,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->ram_chan_q = pdata->ram_chan_q; dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_capture; - dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + - mem->start); + dma_data->dma_addr = dat->start + pdata->rx_dma_offset; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!res) { @@ -1305,4 +1327,3 @@ module_platform_driver(davinci_mcasp_driver); MODULE_AUTHOR("Steve Chen"); MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface"); MODULE_LICENSE("GPL"); - -- cgit v0.10.2 From 4023fe6ff2192d6050647571ea54f5497b2ec8f6 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 18 Oct 2013 18:37:43 +0300 Subject: ASoC: davinci-mcasp: Extract DMA channels directly from DT Extract DMA channels directly from DT as they can not be found from platform resources anymore. This is a work-around until davinci audio driver is updated to use dmaengine. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index c2ab869..c3ccde7 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -18,6 +18,11 @@ Required properties: - serial-dir : A list of serializer pin mode. The list number should be equal to "num-serializer" parameter. Each entry is a number indication serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) +- dmas: two element list of DMA controller phandles and DMA request line + ordered pairs. +- dma-names: identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. The dma + identifiers must be "rx" and "tx". Optional properties: diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 8db5ae0..689a856 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -84,6 +84,8 @@ struct snd_platform_data { u8 version; u8 txnumevt; u8 rxnumevt; + int tx_dma_channel; + int rx_dma_channel; }; enum { diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 806bec3..4c20750 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1047,6 +1047,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( struct snd_platform_data *pdata = NULL; const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev); + struct of_phandle_args dma_spec; const u32 *of_serial_dir32; u8 *of_serial_dir; @@ -1109,6 +1110,28 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata->serial_dir = of_serial_dir; } + ret = of_property_match_string(np, "dma-names", "tx"); + if (ret < 0) + goto nodata; + + ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, + &dma_spec); + if (ret < 0) + goto nodata; + + pdata->tx_dma_channel = dma_spec.args[0]; + + ret = of_property_match_string(np, "dma-names", "rx"); + if (ret < 0) + goto nodata; + + ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, + &dma_spec); + if (ret < 0) + goto nodata; + + pdata->rx_dma_channel = dma_spec.args[0]; + ret = of_property_read_u32(np, "tx-num-evt", &val); if (ret >= 0) pdata->txnumevt = val; @@ -1213,15 +1236,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->sram_size = pdata->sram_size_playback; dma_data->dma_addr = dat->start + pdata->tx_dma_offset; - /* first TX, then RX */ res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, "no DMA resource\n"); - ret = -ENODEV; - goto err_release_clk; - } - - dma_data->channel = res->start; + if (res) + dma_data->channel = res->start; + else + dma_data->channel = pdata->tx_dma_channel; dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data->asp_chan_q = pdata->asp_chan_q; @@ -1231,13 +1250,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->dma_addr = dat->start + pdata->rx_dma_offset; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, "no DMA resource\n"); - ret = -ENODEV; - goto err_release_clk; - } + if (res) + dma_data->channel = res->start; + else + dma_data->channel = pdata->rx_dma_channel; - dma_data->channel = res->start; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); -- cgit v0.10.2 From 3af9e0315699b60762157662f721f50fd1fe529b Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 18 Oct 2013 18:37:44 +0300 Subject: ASoC: davinci-mcasp: Change compatible property model to more accurate Change the model omap2-mcasp-audio in compatible property to am33xx-mcasp-audio as omap2 does not have mcasp. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index c3ccde7..1945aec 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -4,7 +4,7 @@ Required properties: - compatible : "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms - "ti,omap2-mcasp-audio" : for OMAP2 platforms (TI81xx, AM33xx) + "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, TI81xx) - reg : Should contain reg specifiers for the entries in the reg-names property. - reg-names : Should contain: diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 4c20750..bbc9a07 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1033,7 +1033,7 @@ static const struct of_device_id mcasp_dt_ids[] = { .data = &da830_mcasp_pdata, }, { - .compatible = "ti,omap2-mcasp-audio", + .compatible = "ti,am33xx-mcasp-audio", .data = &omap2_mcasp_pdata, }, { /* sentinel */ } -- cgit v0.10.2 From 62561b39ea346ec2e48e01de9fd6f38383b67bd3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 18 Oct 2013 18:37:45 +0300 Subject: ASoC: davinci-mcasp: Improve DT bindings document Makes interrupts property optional as the interrupts are not currently used by the driver and adds interrupt-names property to name listed interrupts. Currently know interrupt names are "tx" and "rx". - Improve tdm-slots propery description - Improve op-mode property description - Add pinctrl-names and pinctrl-0 properties - Remove #address-cells and #size-cells as they are not needed. - Bracket named interrupts property tuples for uniformity. - Add missing "for" to serial-dir prop in DT bindings doc. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 1945aec..b925bf9 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -11,13 +11,14 @@ Required properties: * "mpu" for the main registers (required). For compatibility with existing software, it is recommended this is the first entry. * "dat" for separate data port register access (optional). -- interrupts : Interrupt number for McASP -- op-mode : I2S/DIT ops mode. -- tdm-slots : Slots for TDM operation. +- op-mode : I2S/DIT ops mode. 0 for I2S mode. 1 for DIT mode used for S/PDIF, + IEC60958-1, and AES-3 formats. +- tdm-slots : Slots for TDM operation. Indicates number of channels transmitted + or received over one serializer. - num-serializer : Serializers used by McASP. -- serial-dir : A list of serializer pin mode. The list number should be equal - to "num-serializer" parameter. Each entry is a number indication - serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) +- serial-dir : A list of serializer configuration. Each entry is a number + indication for serializer pin direction. + (0 - INACTIVE, 1 - TX, 2 - RX) - dmas: two element list of DMA controller phandles and DMA request line ordered pairs. - dma-names: identifier string for each DMA request line in the dmas property. @@ -31,16 +32,21 @@ Optional properties: - rx-num-evt : FIFO levels. - sram-size-playback : size of sram to be allocated during playback - sram-size-capture : size of sram to be allocated during capture +- interrupts : Interrupt numbers for McASP, currently not used by the driver +- interrupt-names : Known interrupt names are "tx" and "rx" +- pinctrl-0: Should specify pin control group used for this controller. +- pinctrl-names: Should contain only one value - "default", for more details + please refer to pinctrl-bindings.txt + Example: mcasp0: mcasp0@1d00000 { compatible = "ti,da830-mcasp-audio"; - #address-cells = <1>; - #size-cells = <0>; reg = <0x100000 0x3000>; reg-names "mpu"; - interrupts = <82 83>; + interrupts = <82>, <83>; + interrupts-names = "tx", "rx"; op-mode = <0>; /* MCASP_IIS_MODE */ tdm-slots = <2>; num-serializer = <16>; -- cgit v0.10.2 From 1427e660b49e87cd842dba94158b0fc73030c17e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 18 Oct 2013 18:37:46 +0300 Subject: ASoC: davinci-mcasp: Remove redundant num-serializer DT parameter The serial-dir array gives this information so there is no need to have the num-serializer property in DT description. Just ignore the property in the driver the DTS files can be updated separately without regression. Update the documentation at the same time for davinci-mcasp Signed-off-by: Peter Ujfalusi Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index b925bf9..0aa416b 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -49,7 +49,6 @@ mcasp0: mcasp0@1d00000 { interrupts-names = "tx", "rx"; op-mode = <0>; /* MCASP_IIS_MODE */ tdm-slots = <2>; - num-serializer = <16>; serial-dir = < 0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */ 0 0 0 0 diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index bbc9a07..71e14bb3 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1050,7 +1050,6 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( struct of_phandle_args dma_spec; const u32 *of_serial_dir32; - u8 *of_serial_dir; u32 val; int i, ret = 0; @@ -1081,32 +1080,21 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata->tdm_slots = val; } - ret = of_property_read_u32(np, "num-serializer", &val); - if (ret >= 0) - pdata->num_serializer = val; - of_serial_dir32 = of_get_property(np, "serial-dir", &val); val /= sizeof(u32); - if (val != pdata->num_serializer) { - dev_err(&pdev->dev, - "num-serializer(%d) != serial-dir size(%d)\n", - pdata->num_serializer, val); - ret = -EINVAL; - goto nodata; - } - if (of_serial_dir32) { - of_serial_dir = devm_kzalloc(&pdev->dev, - (sizeof(*of_serial_dir) * val), - GFP_KERNEL); + u8 *of_serial_dir = devm_kzalloc(&pdev->dev, + (sizeof(*of_serial_dir) * val), + GFP_KERNEL); if (!of_serial_dir) { ret = -ENOMEM; goto nodata; } - for (i = 0; i < pdata->num_serializer; i++) + for (i = 0; i < val; i++) of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); + pdata->num_serializer = val; pdata->serial_dir = of_serial_dir; } -- cgit v0.10.2 From d7711dc5930ced241c4f6e9b14df2a92814f9f12 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 14:13:04 +0100 Subject: ASoC: ep93xx: Open code dma channel request Currently the ep93xx DMA code is one of the few users relying on the fact that the compat code uses the dma_data as the filter data for non-DT channel requests. Since the rest of the core expects this to be a struct snd_dmaengine_dai_data this isn't terribly helpful this will be changed to use the already existing filter data so avoid breaking ep93xx by open coding the current behaviour. Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 0e9f56e..cfe517e 100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c @@ -57,9 +57,22 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) return false; } +static struct dma_chan *ep93xx_compat_request_channel( + struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) +{ + struct snd_dmaengine_dai_dma_data *dma_data; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + return snd_dmaengine_pcm_request_channel(ep93xx_pcm_dma_filter, + dma_data); +} + static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = { .pcm_hardware = &ep93xx_pcm_hardware, .compat_filter_fn = ep93xx_pcm_dma_filter, + .compat_request_channel = ep93xx_compat_request_channel, .prealloc_buffer_size = 131072, }; -- cgit v0.10.2 From 0eef5381b7271702c7e65c637cb46804c482a90a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 14:17:03 +0100 Subject: ASoC: tegra: Remove redundant initialisation of compat_filter_fn Setting a field in a static struct to NULL has no effect so don't bother (and don't generate false positives for grep). Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen Acked-by: Stephen Warren diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index f056f63..7b2d23b 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -56,7 +56,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = { .pcm_hardware = &tegra_pcm_hardware, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - .compat_filter_fn = NULL, .prealloc_buffer_size = PAGE_SIZE * 8, }; -- cgit v0.10.2 From d79e07c95d1328773509c69131e5f25cac5dbf50 Mon Sep 17 00:00:00 2001 From: "Hebbar, Gururaja" Date: Wed, 23 Oct 2013 15:30:13 +0300 Subject: ASoC: davinci: Add support for AM33xx SoC Audio AM33xx uses same McASP IP as the Davinci Platform. This patch updates Kconfig and makefile to enable build for McASP, PCM & Codec drivers. Signed-off-by: Hebbar, Gururaja Signed-off-by: Darren Etheridge Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index c82f89c..95970f5 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -1,9 +1,10 @@ config SND_DAVINCI_SOC - tristate "SoC Audio for the TI DAVINCI chip" - depends on ARCH_DAVINCI + tristate "SoC Audio for the TI DAVINCI or AM33XX chip" + depends on ARCH_DAVINCI || SOC_AM33XX help + Platform driver for daVinci or AM33xx Say Y or M if you want to add support for codecs attached to - the DAVINCI AC97 or I2S interface. You will also need + the DAVINCI AC97, I2S, or McASP interface. You will also need to select the audio interfaces to support below. config SND_DAVINCI_SOC_I2S @@ -15,6 +16,17 @@ config SND_DAVINCI_SOC_MCASP config SND_DAVINCI_SOC_VCIF tristate +config SND_AM33XX_SOC_EVM + tristate "SoC Audio for the AM33XX chip based boards" + depends on SND_DAVINCI_SOC && SOC_AM33XX + select SND_SOC_TLV320AIC3X + select SND_DAVINCI_SOC_MCASP + help + Say Y or M if you want to add support for SoC audio on AM33XX + boards using McASP and TLV320AIC3X codec. For example AM335X-EVM, + AM335X-EVMSK, and BeagelBone with AudioCape boards have this + setup. + config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" depends on SND_DAVINCI_SOC diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index a396ab6..bc81e79 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o snd-soc-evm-objs := davinci-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_AM33XX_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o -- cgit v0.10.2 From d5faaa34262d432130f07fed958c8161ef2715ab Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 23 Oct 2013 15:30:15 +0300 Subject: ASoC: davinci-mcasp: Remove last reference to num-serializer in DT doc Remove last reference to num-serializer in davinci-mcasp devicetree binding document. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 0aa416b..ed785b3 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -15,7 +15,6 @@ Required properties: IEC60958-1, and AES-3 formats. - tdm-slots : Slots for TDM operation. Indicates number of channels transmitted or received over one serializer. -- num-serializer : Serializers used by McASP. - serial-dir : A list of serializer configuration. Each entry is a number indication for serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) -- cgit v0.10.2 From ee2f615d6e59cea2b9a415661a7f27caffcb3528 Mon Sep 17 00:00:00 2001 From: "Hebbar, Gururaja" Date: Wed, 23 Oct 2013 15:30:14 +0300 Subject: ASoC: davinci-evm: Add device tree binding Device tree support for Davinci Machine driver When the board boots with device tree, the driver will receive card, codec, dai interface details (like the card name, DAPM routing map, phandle for the audio components described in the dts file, codec mclk speed). The card will be set up based on this information. Since the routing is provided via DT we can mark the card fully routed so core can take care of disconnecting the unused pins. Signed-off-by: Hebbar, Gururaja Signed-off-by: Darren Etheridge Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt new file mode 100644 index 0000000..865178d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt @@ -0,0 +1,42 @@ +* Texas Instruments SoC audio setups with TLV320AIC3X Codec + +Required properties: +- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx +- ti,model : The user-visible name of this sound complex. +- ti,audio-codec : The phandle of the TLV320AIC3x audio codec +- ti,mcasp-controller : The phandle of the McASP controller +- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec +- ti,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the codec's pins, and the jacks on the board: + + Board connectors: + + * Headphone Jack + * Line Out + * Mic Jack + * Line In + + +Example: + +sound { + compatible = "ti,da830-evm-audio"; + ti,model = "DA830 EVM"; + ti,audio-codec = <&tlv320aic3x>; + ti,mcasp-controller = <&mcasp1>; + ti,codec-clock-rate = <12000000>; + ti,audio-routing = + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "Line Out", "LLOUT", + "Line Out", "RLOUT", + "MIC3L", "Mic Bias 2V", + "MIC3R", "Mic Bias 2V", + "Mic Bias 2V", "Mic Jack", + "LINE1L", "Line In", + "LINE2L", "Line In", + "LINE1R", "Line In", + "LINE2R", "Line In"; +}; diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 2f8161c..623eb5e 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,8 @@ #include #include +#include + #include "davinci-pcm.h" #include "davinci-i2s.h" #include "davinci-mcasp.h" @@ -121,13 +124,22 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; + struct device_node *np = codec->card->dev->of_node; + int ret; /* Add davinci-evm specific widgets */ snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, ARRAY_SIZE(aic3x_dapm_widgets)); - /* Set up davinci-evm specific audio path audio_map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + if (np) { + ret = snd_soc_of_parse_audio_routing(codec->card, + "ti,audio-routing"); + if (ret) + return ret; + } else { + /* Set up davinci-evm specific audio path audio_map */ + snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + } /* not connected */ snd_soc_dapm_disable_pin(dapm, "MONO_LOUT"); @@ -312,6 +324,98 @@ static struct snd_soc_card da850_snd_soc_card = { .drvdata = &da850_snd_soc_card_drvdata, }; +#if defined(CONFIG_OF) + +/* + * The struct is used as place holder. It will be completely + * filled with data from dt node. + */ +static struct snd_soc_dai_link evm_dai_tlv320aic3x = { + .name = "TLV320AIC3X", + .stream_name = "AIC3X", + .codec_dai_name = "tlv320aic3x-hifi", + .ops = &evm_ops, + .init = evm_aic3x_init, +}; + +static const struct of_device_id davinci_evm_dt_ids[] = { + { + .compatible = "ti,da830-evm-audio", + .data = (void *) &evm_dai_tlv320aic3x, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids); + +/* davinci evm audio machine driver */ +static struct snd_soc_card evm_soc_card = { + .owner = THIS_MODULE, + .num_links = 1, +}; + +static int davinci_evm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match = + of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); + struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; + struct snd_soc_card_drvdata_davinci *drvdata = NULL; + int ret = 0; + + evm_soc_card.dai_link = dai; + + dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0); + if (!dai->codec_of_node) + return -EINVAL; + + dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0); + if (!dai->cpu_of_node) + return -EINVAL; + + dai->platform_of_node = dai->cpu_of_node; + + evm_soc_card.dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model"); + if (ret) + return ret; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); + if (ret < 0) + return -EINVAL; + + snd_soc_card_set_drvdata(&evm_soc_card, drvdata); + ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); + + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + + return ret; +} + +static int davinci_evm_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver davinci_evm_driver = { + .probe = davinci_evm_probe, + .remove = davinci_evm_remove, + .driver = { + .name = "davinci_evm", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(davinci_evm_dt_ids), + }, +}; +#endif + static struct platform_device *evm_snd_device; static int __init evm_init(void) @@ -320,6 +424,15 @@ static int __init evm_init(void) int index; int ret; + /* + * If dtb is there, the devices will be created dynamically. + * Only register platfrom driver structure. + */ +#if defined(CONFIG_OF) + if (of_have_populated_dt()) + return platform_driver_register(&davinci_evm_driver); +#endif + if (machine_is_davinci_evm()) { evm_snd_dev_data = &dm6446_snd_soc_card_evm; index = 0; @@ -355,6 +468,13 @@ static int __init evm_init(void) static void __exit evm_exit(void) { +#if defined(CONFIG_OF) + if (of_have_populated_dt()) { + platform_driver_unregister(&davinci_evm_driver); + return; + } +#endif + platform_device_unregister(evm_snd_device); } -- cgit v0.10.2 From f95a48834cb9c581eec952215666a323136f339f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Wed, 23 Oct 2013 14:03:28 +0200 Subject: ASoC: tpa6130a2: Add device tree support Add device tree support to tpa6130a2 driver and document the bindings. Signed-off-by: Sebastian Reichel Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/tpa6130a2.txt b/Documentation/devicetree/bindings/sound/tpa6130a2.txt new file mode 100644 index 0000000..6dfa740 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tpa6130a2.txt @@ -0,0 +1,27 @@ +Texas Instruments - tpa6130a2 Codec module + +The tpa6130a2 serial control bus communicates through I2C protocols + +Required properties: + +- compatible - "string" - One of: + "ti,tpa6130a2" - TPA6130A2 + "ti,tpa6140a2" - TPA6140A2 + + +- reg - - I2C slave address + +- Vdd-supply - - power supply regulator + +Optional properties: + +- power-gpio - gpio pin to power the device + +Example: + +tpa6130a2: tpa6130a2@60 { + compatible = "ti,tpa6130a2"; + reg = <0x60>; + Vdd-supply = <&vmmc2>; + power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; +}; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index c58bee8..998555f 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "tpa6130a2.h" @@ -364,30 +365,33 @@ static int tpa6130a2_probe(struct i2c_client *client, { struct device *dev; struct tpa6130a2_data *data; - struct tpa6130a2_platform_data *pdata; + struct tpa6130a2_platform_data *pdata = client->dev.platform_data; + struct device_node *np = client->dev.of_node; const char *regulator; int ret; dev = &client->dev; - if (client->dev.platform_data == NULL) { - dev_err(dev, "Platform data not set\n"); - dump_stack(); - return -ENODEV; - } - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) { dev_err(dev, "Can not allocate memory\n"); return -ENOMEM; } + if (pdata) { + data->power_gpio = pdata->power_gpio; + } else if (np) { + data->power_gpio = of_get_named_gpio(np, "power-gpio", 0); + } else { + dev_err(dev, "Platform data not set\n"); + dump_stack(); + return -ENODEV; + } + tpa6130a2_client = client; i2c_set_clientdata(tpa6130a2_client, data); - pdata = client->dev.platform_data; - data->power_gpio = pdata->power_gpio; data->id = id->driver_data; mutex_init(&data->mutex); @@ -466,10 +470,20 @@ static const struct i2c_device_id tpa6130a2_id[] = { }; MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id tpa6130a2_of_match[] = { + { .compatible = "ti,tpa6130a2", }, + { .compatible = "ti,tpa6140a2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tpa6130a2_of_match); +#endif + static struct i2c_driver tpa6130a2_i2c_driver = { .driver = { .name = "tpa6130a2", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tpa6130a2_of_match), }, .probe = tpa6130a2_probe, .remove = tpa6130a2_remove, -- cgit v0.10.2 From ea73b7ddf13548afd666373dc5e26ee7c812a3fe Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 17:43:51 +0100 Subject: ASoC: dmaengine: Support custom channel names Some devices have more than just simple TX and RX DMA channels, for example modern Samsung I2S IPs support a secondary transmit DMA stream which is mixed into the primary stream during playback. Allow such devices to specify the names of the channels to be requested in their dma_data. Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 83b2c3e..1501731 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -61,6 +61,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. + * @chan_name: Custom channel name to use when requesting DMA channel. * @fifo_size: FIFO size of the DAI controller in bytes */ struct snd_dmaengine_dai_dma_data { @@ -69,6 +70,7 @@ struct snd_dmaengine_dai_dma_data { u32 maxburst; unsigned int slave_id; void *filter_data; + const char *chan_name; unsigned int fifo_size; }; @@ -98,6 +100,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) +/* + * The PCM streams have custom channel names specified. + */ +#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 99f9495..793cd6c 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -183,6 +183,8 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; + struct device *dev = rtd->platform->dev; + struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -203,6 +205,13 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + if (!pcm->chan[i] && + (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + pcm->chan[i] = dma_request_slave_channel(dev, + dma_data->chan_name); + if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, substream); @@ -275,7 +284,9 @@ static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, { unsigned int i; - if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node) + if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | + SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || + !dev->of_node) return; if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) { -- cgit v0.10.2 From 90130d2e8f75c7181cef514e8a1491925f386a16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 21:38:26 +0100 Subject: ASoC: dmaengine: Use filter_data rather than dma_data for compat requests When using the legacy filter function channel requests we currently pass the audio specific struct snd_dmaengine_dai_dma_data which isn't likely to be helpful for actual filtering. Since there's already a field in the structure called filter_data clearly intended for use here convert the driver to use that. All existing users of plain filter functions have been converted to use an explicit compat function to override this behaviour except i.MX which is working around this issue in its filter function and is updated to just use filter_data directly here. Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 4dc1296..aee2307 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -25,12 +25,10 @@ static bool filter(struct dma_chan *chan, void *param) { - struct snd_dmaengine_dai_dma_data *dma_data = param; - if (!imx_dma_is_general_purpose(chan)) return false; - chan->private = dma_data->filter_data; + chan->private = param; return true; } diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 793cd6c..0c469cb 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -168,6 +168,9 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( struct snd_pcm_substream *substream) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct snd_dmaengine_dai_dma_data *dma_data; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0]) return pcm->chan[0]; @@ -176,7 +179,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( return pcm->config->compat_request_channel(rtd, substream); return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn, - snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); + dma_data->filter_data); } static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) -- cgit v0.10.2 From 1abe729f783fece81d93e9a0253fd8079f19d7f6 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Thu, 24 Oct 2013 18:15:29 +0800 Subject: ASoC: fsl: Add missing pm to current machine drivers Add missing pm to current machine drivers so that all of them would correctly do suspend/resume. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index a2fd732..79cee78 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -160,6 +160,7 @@ static struct platform_driver imx_mc13783_audio_driver = { .driver = { .name = "imx_mc13783", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = imx_mc13783_probe, .remove = imx_mc13783_remove diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index ca1be1d..73da709 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -202,6 +202,7 @@ static struct platform_driver imx_sgtl5000_driver = { .driver = { .name = "imx-sgtl5000", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, .of_match_table = imx_sgtl5000_dt_ids, }, .probe = imx_sgtl5000_probe, diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 722afe6..8e5b2c6 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -311,6 +311,7 @@ static struct platform_driver imx_wm8962_driver = { .driver = { .name = "imx-wm8962", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, .of_match_table = imx_wm8962_dt_ids, }, .probe = imx_wm8962_probe, -- cgit v0.10.2 From 63e6d43bf80d3861dcda7ff4f37590f8de583156 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 19 Nov 2013 10:58:17 +0000 Subject: ASoC: ab8500: Revert to using custom I/O functions It's been reported that these break audio on Snowball so revert them until a Snowball user has time to investigate. Signed-off-by: Lee Jones Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index a0394a8..7990217 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -126,8 +126,6 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { - struct regmap *regmap; - /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; @@ -168,34 +166,48 @@ static inline const char *amic_type_str(enum amic_type type) */ /* Read a register from the audio-bank of AB8500 */ -static int ab8500_codec_read_reg(void *context, unsigned int reg, - unsigned int *value) +static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, + unsigned int reg) { - struct device *dev = context; int status; + unsigned int value = 0; u8 value8; - status = abx500_get_register_interruptible(dev, AB8500_AUDIO, - reg, &value8); - *value = (unsigned int)value8; + status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, + reg, &value8); + if (status < 0) { + dev_err(codec->dev, + "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", + __func__, (u8)AB8500_AUDIO, (u8)reg, status); + } else { + dev_dbg(codec->dev, + "%s: Read 0x%02x from register 0x%02x:0x%02x\n", + __func__, value8, (u8)AB8500_AUDIO, (u8)reg); + value = (unsigned int)value8; + } - return status; + return value; } /* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(void *context, unsigned int reg, - unsigned int value) +static int ab8500_codec_write_reg(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) { - struct device *dev = context; + int status; - return abx500_set_register_interruptible(dev, AB8500_AUDIO, - reg, value); -} + status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, + reg, value); + if (status < 0) + dev_err(codec->dev, + "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", + __func__, (u8)AB8500_AUDIO, (u8)reg, status); + else + dev_dbg(codec->dev, + "%s: Wrote 0x%02x into register %02x:%02x\n", + __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); -static const struct regmap_config ab8500_codec_regmap = { - .reg_read = ab8500_codec_read_reg, - .reg_write = ab8500_codec_write_reg, -}; + return status; +} /* * Controls - DAPM @@ -2473,13 +2485,9 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) dev_dbg(dev, "%s: Enter.\n", __func__); - snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); - /* Setup AB8500 according to board-settings */ pdata = dev_get_platdata(dev->parent); - codec->control_data = drvdata->regmap; - if (np) { if (!pdata) pdata = devm_kzalloc(dev, @@ -2557,6 +2565,9 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, + .read = ab8500_codec_read_reg, + .write = ab8500_codec_write_reg, + .reg_word_size = sizeof(u8), .controls = ab8500_ctrls, .num_controls = ARRAY_SIZE(ab8500_ctrls), .dapm_widgets = ab8500_dapm_widgets, @@ -2579,15 +2590,6 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); - drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, - &ab8500_codec_regmap); - if (IS_ERR(drvdata->regmap)) { - status = PTR_ERR(drvdata->regmap); - dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", - __func__, status); - return status; - } - dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, ab8500_codec_dai, -- cgit v0.10.2