Commit 4ef61076 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-3.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "The significant part here is a few security fixes for ALSA core
  control API by Lars.  Besides that, there are a few fixes for ASoC
  sigmadsp (again by Lars) for building properly, and small fixes for
  ASoC rsnd, MMP, PXA and FSL, in addition to a fix for bogus WARNING in
  i915/HD-audio binding"

* tag 'sound-3.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: control: Make sure that id->index does not overflow
  ALSA: control: Handle numid overflow
  ALSA: control: Don't access controls outside of protected regions
  ALSA: control: Fix replacing user controls
  ALSA: control: Protect user controls against concurrent access
  drm/i915, HD-audio: Don't continue probing when nomodeset is given
  ASoC: fsl: Fix build problem
  ASoC: rsnd: fixup index of src/dst mod when capture
  ASoC: fsl_spdif: Fix integer overflow when calculating divisors
  ASoC: fsl_spdif: Fix incorrect usage of regmap_read()
  ASoC: dapm: Make sure register value is in sync with DAPM kcontrol state
  ASoC: sigmadsp: Split regmap and I2C support into separate modules
  ASoC: MMP audio needs sram support
  ASoC: pxa: add I2C dependencies as needed
parents 0c9bc275 8d42fda9
...@@ -6019,30 +6019,32 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, ...@@ -6019,30 +6019,32 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
static struct i915_power_domains *hsw_pwr; static struct i915_power_domains *hsw_pwr;
/* Display audio driver power well request */ /* Display audio driver power well request */
void i915_request_power_well(void) int i915_request_power_well(void)
{ {
struct drm_i915_private *dev_priv; struct drm_i915_private *dev_priv;
if (WARN_ON(!hsw_pwr)) if (!hsw_pwr)
return; return -ENODEV;
dev_priv = container_of(hsw_pwr, struct drm_i915_private, dev_priv = container_of(hsw_pwr, struct drm_i915_private,
power_domains); power_domains);
intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
return 0;
} }
EXPORT_SYMBOL_GPL(i915_request_power_well); EXPORT_SYMBOL_GPL(i915_request_power_well);
/* Display audio driver power well release */ /* Display audio driver power well release */
void i915_release_power_well(void) int i915_release_power_well(void)
{ {
struct drm_i915_private *dev_priv; struct drm_i915_private *dev_priv;
if (WARN_ON(!hsw_pwr)) if (!hsw_pwr)
return; return -ENODEV;
dev_priv = container_of(hsw_pwr, struct drm_i915_private, dev_priv = container_of(hsw_pwr, struct drm_i915_private,
power_domains); power_domains);
intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
return 0;
} }
EXPORT_SYMBOL_GPL(i915_release_power_well); EXPORT_SYMBOL_GPL(i915_release_power_well);
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#define _I915_POWERWELL_H_ #define _I915_POWERWELL_H_
/* For use by hda_i915 driver */ /* For use by hda_i915 driver */
extern void i915_request_power_well(void); extern int i915_request_power_well(void);
extern void i915_release_power_well(void); extern int i915_release_power_well(void);
#endif /* _I915_POWERWELL_H_ */ #endif /* _I915_POWERWELL_H_ */
...@@ -116,6 +116,8 @@ struct snd_card { ...@@ -116,6 +116,8 @@ struct snd_card {
int user_ctl_count; /* count of all user controls */ int user_ctl_count; /* count of all user controls */
struct list_head controls; /* all controls for this card */ struct list_head controls; /* all controls for this card */
struct list_head ctl_files; /* active control files */ struct list_head ctl_files; /* active control files */
struct mutex user_ctl_lock; /* protects user controls against
concurrent access */
struct snd_info_entry *proc_root; /* root for soundcard specific files */ struct snd_info_entry *proc_root; /* root for soundcard specific files */
struct snd_info_entry *proc_id; /* the card id */ struct snd_info_entry *proc_id; /* the card id */
......
...@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card, ...@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
{ {
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
/* Make sure that the ids assigned to the control do not wrap around */
if (card->last_numid >= UINT_MAX - count)
card->last_numid = 0;
list_for_each_entry(kctl, &card->controls, list) { list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid < card->last_numid + 1 + count && if (kctl->id.numid < card->last_numid + 1 + count &&
kctl->id.numid + kctl->count > card->last_numid + 1) { kctl->id.numid + kctl->count > card->last_numid + 1) {
...@@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) ...@@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
{ {
struct snd_ctl_elem_id id; struct snd_ctl_elem_id id;
unsigned int idx; unsigned int idx;
unsigned int count;
int err = -EINVAL; int err = -EINVAL;
if (! kcontrol) if (! kcontrol)
...@@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) ...@@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
if (snd_BUG_ON(!card || !kcontrol->info)) if (snd_BUG_ON(!card || !kcontrol->info))
goto error; goto error;
id = kcontrol->id; id = kcontrol->id;
if (id.index > UINT_MAX - kcontrol->count)
goto error;
down_write(&card->controls_rwsem); down_write(&card->controls_rwsem);
if (snd_ctl_find_id(card, &id)) { if (snd_ctl_find_id(card, &id)) {
up_write(&card->controls_rwsem); up_write(&card->controls_rwsem);
...@@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) ...@@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
card->controls_count += kcontrol->count; card->controls_count += kcontrol->count;
kcontrol->id.numid = card->last_numid + 1; kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count; card->last_numid += kcontrol->count;
count = kcontrol->count;
up_write(&card->controls_rwsem); up_write(&card->controls_rwsem);
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) for (idx = 0; idx < count; idx++, id.index++, id.numid++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
return 0; return 0;
...@@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, ...@@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
bool add_on_replace) bool add_on_replace)
{ {
struct snd_ctl_elem_id id; struct snd_ctl_elem_id id;
unsigned int count;
unsigned int idx; unsigned int idx;
struct snd_kcontrol *old; struct snd_kcontrol *old;
int ret; int ret;
...@@ -423,8 +433,9 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, ...@@ -423,8 +433,9 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
card->controls_count += kcontrol->count; card->controls_count += kcontrol->count;
kcontrol->id.numid = card->last_numid + 1; kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count; card->last_numid += kcontrol->count;
count = kcontrol->count;
up_write(&card->controls_rwsem); up_write(&card->controls_rwsem);
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) for (idx = 0; idx < count; idx++, id.index++, id.numid++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
return 0; return 0;
...@@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, ...@@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
result = kctl->put(kctl, control); result = kctl->put(kctl, control);
} }
if (result > 0) { if (result > 0) {
struct snd_ctl_elem_id id = control->id;
up_read(&card->controls_rwsem); up_read(&card->controls_rwsem);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
&control->id);
return 0; return 0;
} }
} }
...@@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, ...@@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
struct user_element { struct user_element {
struct snd_ctl_elem_info info; struct snd_ctl_elem_info info;
struct snd_card *card;
void *elem_data; /* element data */ void *elem_data; /* element data */
unsigned long elem_data_size; /* size of element data in bytes */ unsigned long elem_data_size; /* size of element data in bytes */
void *tlv_data; /* TLV data */ void *tlv_data; /* TLV data */
...@@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, ...@@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
{ {
struct user_element *ue = kcontrol->private_data; struct user_element *ue = kcontrol->private_data;
mutex_lock(&ue->card->user_ctl_lock);
memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
mutex_unlock(&ue->card->user_ctl_lock);
return 0; return 0;
} }
...@@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, ...@@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
{ {
int change; int change;
struct user_element *ue = kcontrol->private_data; struct user_element *ue = kcontrol->private_data;
mutex_lock(&ue->card->user_ctl_lock);
change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
if (change) if (change)
memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
mutex_unlock(&ue->card->user_ctl_lock);
return change; return change;
} }
...@@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, ...@@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
new_data = memdup_user(tlv, size); new_data = memdup_user(tlv, size);
if (IS_ERR(new_data)) if (IS_ERR(new_data))
return PTR_ERR(new_data); return PTR_ERR(new_data);
mutex_lock(&ue->card->user_ctl_lock);
change = ue->tlv_data_size != size; change = ue->tlv_data_size != size;
if (!change) if (!change)
change = memcmp(ue->tlv_data, new_data, size); change = memcmp(ue->tlv_data, new_data, size);
kfree(ue->tlv_data); kfree(ue->tlv_data);
ue->tlv_data = new_data; ue->tlv_data = new_data;
ue->tlv_data_size = size; ue->tlv_data_size = size;
mutex_unlock(&ue->card->user_ctl_lock);
} else { } else {
if (! ue->tlv_data_size || ! ue->tlv_data) int ret = 0;
return -ENXIO;
if (size < ue->tlv_data_size) mutex_lock(&ue->card->user_ctl_lock);
return -ENOSPC; if (!ue->tlv_data_size || !ue->tlv_data) {
ret = -ENXIO;
goto err_unlock;
}
if (size < ue->tlv_data_size) {
ret = -ENOSPC;
goto err_unlock;
}
if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
return -EFAULT; ret = -EFAULT;
err_unlock:
mutex_unlock(&ue->card->user_ctl_lock);
if (ret)
return ret;
} }
return change; return change;
} }
...@@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, ...@@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
struct user_element *ue; struct user_element *ue;
int idx, err; int idx, err;
if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
return -ENOMEM;
if (info->count < 1) if (info->count < 1)
return -EINVAL; return -EINVAL;
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
...@@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, ...@@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
info->id.numid = 0; info->id.numid = 0;
memset(&kctl, 0, sizeof(kctl)); memset(&kctl, 0, sizeof(kctl));
down_write(&card->controls_rwsem);
_kctl = snd_ctl_find_id(card, &info->id); if (replace) {
err = 0; err = snd_ctl_remove_user_ctl(file, &info->id);
if (_kctl) { if (err)
if (replace) return err;
err = snd_ctl_remove(card, _kctl);
else
err = -EBUSY;
} else {
if (replace)
err = -ENOENT;
} }
up_write(&card->controls_rwsem);
if (err < 0) if (card->user_ctl_count >= MAX_USER_CONTROLS)
return err; return -ENOMEM;
memcpy(&kctl.id, &info->id, sizeof(info->id)); memcpy(&kctl.id, &info->id, sizeof(info->id));
kctl.count = info->owner ? info->owner : 1; kctl.count = info->owner ? info->owner : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER; access |= SNDRV_CTL_ELEM_ACCESS_USER;
...@@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, ...@@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
if (ue == NULL) if (ue == NULL)
return -ENOMEM; return -ENOMEM;
ue->card = card;
ue->info = *info; ue->info = *info;
ue->info.access = 0; ue->info.access = 0;
ue->elem_data = (char *)ue + sizeof(*ue); ue->elem_data = (char *)ue + sizeof(*ue);
...@@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, ...@@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
} }
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
if (err > 0) { if (err > 0) {
struct snd_ctl_elem_id id = kctl->id;
up_read(&card->controls_rwsem); up_read(&card->controls_rwsem);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
return 0; return 0;
} }
} else { } else {
......
...@@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, ...@@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
INIT_LIST_HEAD(&card->devices); INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem); init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock); rwlock_init(&card->ctl_files_rwlock);
mutex_init(&card->user_ctl_lock);
INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files); INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock); spin_lock_init(&card->files_lock);
......
...@@ -22,20 +22,20 @@ ...@@ -22,20 +22,20 @@
#include <drm/i915_powerwell.h> #include <drm/i915_powerwell.h>
#include "hda_i915.h" #include "hda_i915.h"
static void (*get_power)(void); static int (*get_power)(void);
static void (*put_power)(void); static int (*put_power)(void);
void hda_display_power(bool enable) int hda_display_power(bool enable)
{ {
if (!get_power || !put_power) if (!get_power || !put_power)
return; return -ENODEV;
pr_debug("HDA display power %s \n", pr_debug("HDA display power %s \n",
enable ? "Enable" : "Disable"); enable ? "Enable" : "Disable");
if (enable) if (enable)
get_power(); return get_power();
else else
put_power(); return put_power();
} }
int hda_i915_init(void) int hda_i915_init(void)
......
...@@ -17,11 +17,11 @@ ...@@ -17,11 +17,11 @@
#define __SOUND_HDA_I915_H #define __SOUND_HDA_I915_H
#ifdef CONFIG_SND_HDA_I915 #ifdef CONFIG_SND_HDA_I915
void hda_display_power(bool enable); int hda_display_power(bool enable);
int hda_i915_init(void); int hda_i915_init(void);
int hda_i915_exit(void); int hda_i915_exit(void);
#else #else
static inline void hda_display_power(bool enable) {} static inline int hda_display_power(bool enable) { return 0; }
static inline int hda_i915_init(void) static inline int hda_i915_init(void)
{ {
return -ENODEV; return -ENODEV;
......
...@@ -1656,8 +1656,13 @@ static int azx_probe_continue(struct azx *chip) ...@@ -1656,8 +1656,13 @@ static int azx_probe_continue(struct azx *chip)
"Error request power-well from i915\n"); "Error request power-well from i915\n");
goto out_free; goto out_free;
} }
err = hda_display_power(true);
if (err < 0) {
dev_err(chip->card->dev,
"Cannot turn on display power on i915\n");
goto out_free;
}
#endif #endif
hda_display_power(true);
} }
err = azx_first_init(chip); err = azx_first_init(chip);
......
...@@ -225,11 +225,11 @@ config SND_SOC_ADAU1373 ...@@ -225,11 +225,11 @@ config SND_SOC_ADAU1373
config SND_SOC_ADAU1701 config SND_SOC_ADAU1701
tristate "Analog Devices ADAU1701 CODEC" tristate "Analog Devices ADAU1701 CODEC"
depends on I2C depends on I2C
select SND_SOC_SIGMADSP select SND_SOC_SIGMADSP_I2C
config SND_SOC_ADAU17X1 config SND_SOC_ADAU17X1
tristate tristate
select SND_SOC_SIGMADSP select SND_SOC_SIGMADSP_REGMAP
config SND_SOC_ADAU1761 config SND_SOC_ADAU1761
tristate tristate
...@@ -476,6 +476,14 @@ config SND_SOC_SIGMADSP ...@@ -476,6 +476,14 @@ config SND_SOC_SIGMADSP
tristate tristate
select CRC32 select CRC32
config SND_SOC_SIGMADSP_I2C
tristate
select SND_SOC_SIGMADSP
config SND_SOC_SIGMADSP_REGMAP
tristate
select SND_SOC_SIGMADSP
config SND_SOC_SIRF_AUDIO_CODEC config SND_SOC_SIRF_AUDIO_CODEC
tristate "SiRF SoC internal audio codec" tristate "SiRF SoC internal audio codec"
select REGMAP_MMIO select REGMAP_MMIO
......
...@@ -77,6 +77,8 @@ snd-soc-sgtl5000-objs := sgtl5000.o ...@@ -77,6 +77,8 @@ snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o snd-soc-alc5632-objs := alc5632.o
snd-soc-sigmadsp-objs := sigmadsp.o snd-soc-sigmadsp-objs := sigmadsp.o
snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
snd-soc-si476x-objs := si476x.o snd-soc-si476x-objs := si476x.o
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
snd-soc-sn95031-objs := sn95031.o snd-soc-sn95031-objs := sn95031.o
...@@ -240,6 +242,8 @@ obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o ...@@ -240,6 +242,8 @@ obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
......
/*
* Load Analog Devices SigmaStudio firmware files
*
* Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/i2c.h>
#include <linux/export.h>
#include <linux/module.h>
#include "sigmadsp.h"
static int sigma_action_write_i2c(void *control_data,
const struct sigma_action *sa, size_t len)
{
return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
len);
}
int process_sigma_firmware(struct i2c_client *client, const char *name)
{
struct sigma_firmware ssfw;
ssfw.control_data = client;
ssfw.write = sigma_action_write_i2c;
return _process_sigma_firmware(&client->dev, &ssfw, name);
}
EXPORT_SYMBOL(process_sigma_firmware);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");
MODULE_LICENSE("GPL");
/*
* Load Analog Devices SigmaStudio firmware files
*
* Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/regmap.h>
#include <linux/export.h>
#include <linux/module.h>
#include "sigmadsp.h"
static int sigma_action_write_regmap(void *control_data,
const struct sigma_action *sa, size_t len)
{
return regmap_raw_write(control_data, be16_to_cpu(sa->addr),
sa->payload, len - 2);
}
int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
const char *name)
{
struct sigma_firmware ssfw;
ssfw.control_data = regmap;
ssfw.write = sigma_action_write_regmap;
return _process_sigma_firmware(dev, &ssfw, name);
}
EXPORT_SYMBOL(process_sigma_firmware_regmap);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");
MODULE_LICENSE("GPL");
...@@ -34,23 +34,6 @@ enum { ...@@ -34,23 +34,6 @@ enum {
SIGMA_ACTION_END, SIGMA_ACTION_END,
}; };
struct sigma_action {
u8 instr;
u8 len_hi;
__le16 len;
__be16 addr;
unsigned char payload[];
} __packed;
struct sigma_firmware {
const struct firmware *fw;
size_t pos;
void *control_data;
int (*write)(void *control_data, const struct sigma_action *sa,
size_t len);
};
static inline u32 sigma_action_len(struct sigma_action *sa) static inline u32 sigma_action_len(struct sigma_action *sa)
{ {
return (sa->len_hi << 16) | le16_to_cpu(sa->len); return (sa->len_hi << 16) | le16_to_cpu(sa->len);
...@@ -138,7 +121,7 @@ process_sigma_actions(struct sigma_firmware *ssfw) ...@@ -138,7 +121,7 @@ process_sigma_actions(struct sigma_firmware *ssfw)
return 0; return 0;
} }
static int _process_sigma_firmware(struct device *dev, int _process_sigma_firmware(struct device *dev,
struct sigma_firmware *ssfw, const char *name) struct sigma_firmware *ssfw, const char *name)
{ {
int ret; int ret;
...@@ -197,50 +180,6 @@ static int _process_sigma_firmware(struct device *dev, ...@@ -197,50 +180,6 @@ static int _process_sigma_firmware(struct device *dev,
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(_process_sigma_firmware);
#if IS_ENABLED(CONFIG_I2C)
static int sigma_action_write_i2c(void *control_data,
const struct sigma_action *sa, size_t len)
{
return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
len);
}
int process_sigma_firmware(struct i2c_client *client, const char *name)
{
struct sigma_firmware ssfw;
ssfw.control_data = client;
ssfw.write = sigma_action_write_i2c;
return _process_sigma_firmware(&client->dev, &ssfw, name);
}
EXPORT_SYMBOL(process_sigma_firmware);
#endif
#if IS_ENABLED(CONFIG_REGMAP)
static int sigma_action_write_regmap(void *control_data,
const struct sigma_action *sa, size_t len)
{
return regmap_raw_write(control_data, be16_to_cpu(sa->addr),
sa->payload, len - 2);
}
int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
const char *name)
{
struct sigma_firmware ssfw;
ssfw.control_data = regmap;
ssfw.write = sigma_action_write_regmap;
return _process_sigma_firmware(dev, &ssfw, name);
}
EXPORT_SYMBOL(process_sigma_firmware_regmap);
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -12,6 +12,26 @@ ...@@ -12,6 +12,26 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
struct sigma_action {
u8 instr;
u8 len_hi;
__le16 len;
__be16 addr;
unsigned char payload[];
} __packed;
struct sigma_firmware {
const struct firmware *fw;
size_t pos;
void *control_data;
int (*write)(void *control_data, const struct sigma_action *sa,
size_t len);
};
int _process_sigma_firmware(struct device *dev,
struct sigma_firmware *ssfw, const char *name);
struct i2c_client; struct i2c_client;
extern int process_sigma_firmware(struct i2c_client *client, const char *name); extern int process_sigma_firmware(struct i2c_client *client, const char *name);
......
...@@ -923,8 +923,8 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) ...@@ -923,8 +923,8 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
dma->dai.pcm_free = fsl_dma_free_dma_buffers; dma->dai.pcm_free = fsl_dma_free_dma_buffers;
/* Store the SSI-specific information that we need */ /* Store the SSI-specific information that we need */
dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0); dma->ssi_stx_phys = res.start + CCSR_SSI_STX0;
dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0); dma->ssi_srx_phys = res.start + CCSR_SSI_SRX0;
iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
if (iprop) if (iprop)
......
...@@ -762,7 +762,7 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, ...@@ -762,7 +762,7 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol,
struct regmap *regmap = spdif_priv->regmap; struct regmap *regmap = spdif_priv->regmap;
u32 val; u32 val;
val = regmap_read(regmap, REG_SPDIF_SIS, &val); regmap_read(regmap, REG_SPDIF_SIS, &val);
ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0;
regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD);
...@@ -1076,7 +1076,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, ...@@ -1076,7 +1076,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
goto out; goto out;
} else if (arate / rate[index] == 1) { } else if (arate / rate[index] == 1) {
/* A little bigger than expect */ /* A little bigger than expect */
sub = (arate - rate[index]) * 100000; sub = (u64)(arate - rate[index]) * 100000;
do_div(sub, rate[index]); do_div(sub, rate[index]);
if (sub >= savesub) if (sub >= savesub)
continue; continue;
...@@ -1086,7 +1086,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, ...@@ -1086,7 +1086,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
spdif_priv->txrate[index] = arate; spdif_priv->txrate[index] = arate;
} else if (rate[index] / arate == 1) { } else if (rate[index] / arate == 1) {
/* A little smaller than expect */ /* A little smaller than expect */
sub = (rate[index] - arate) * 100000; sub = (u64)(rate[index] - arate) * 100000;
do_div(sub, rate[index]); do_div(sub, rate[index]);
if (sub >= savesub) if (sub >= savesub)
continue; continue;
......
...@@ -11,6 +11,7 @@ config SND_PXA2XX_SOC ...@@ -11,6 +11,7 @@ config SND_PXA2XX_SOC
config SND_MMP_SOC config SND_MMP_SOC
bool "Soc Audio for Marvell MMP chips" bool "Soc Audio for Marvell MMP chips"
depends on ARCH_MMP depends on ARCH_MMP
select MMP_SRAM
select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM
select SND_ARM select SND_ARM
help help
...@@ -40,7 +41,7 @@ config SND_MMP_SOC_SSPA ...@@ -40,7 +41,7 @@ config SND_MMP_SOC_SSPA
config SND_PXA2XX_SOC_CORGI config SND_PXA2XX_SOC_CORGI
tristate "SoC Audio support for Sharp Zaurus SL-C7x0" tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx && I2C
select SND_PXA2XX_SOC_I2S select SND_PXA2XX_SOC_I2S
select SND_SOC_WM8731 select SND_SOC_WM8731
help help
...@@ -49,7 +50,7 @@ config SND_PXA2XX_SOC_CORGI ...@@ -49,7 +50,7 @@ config SND_PXA2XX_SOC_CORGI
config SND_PXA2XX_SOC_SPITZ config SND_PXA2XX_SOC_SPITZ
tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" tristate "SoC Audio support for Sharp Zaurus SL-Cxx00"
depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 && I2C
select SND_PXA2XX_SOC_I2S select SND_PXA2XX_SOC_I2S
select SND_SOC_WM8750 select SND_SOC_WM8750
help help
...@@ -58,7 +59,7 @@ config SND_PXA2XX_SOC_SPITZ ...@@ -58,7 +59,7 @@ config SND_PXA2XX_SOC_SPITZ
config SND_PXA2XX_SOC_Z2 config SND_PXA2XX_SOC_Z2
tristate "SoC Audio support for Zipit Z2" tristate "SoC Audio support for Zipit Z2"
depends on SND_PXA2XX_SOC && MACH_ZIPIT2 depends on SND_PXA2XX_SOC && MACH_ZIPIT2 && I2C
select SND_PXA2XX_SOC_I2S select SND_PXA2XX_SOC_I2S
select SND_SOC_WM8750 select SND_SOC_WM8750
help help
...@@ -66,7 +67,7 @@ config SND_PXA2XX_SOC_Z2 ...@@ -66,7 +67,7 @@ config SND_PXA2XX_SOC_Z2
config SND_PXA2XX_SOC_POODLE config SND_PXA2XX_SOC_POODLE
tristate "SoC Audio support for Poodle" tristate "SoC Audio support for Poodle"
depends on SND_PXA2XX_SOC && MACH_POODLE depends on SND_PXA2XX_SOC && MACH_POODLE && I2C
select SND_PXA2XX_SOC_I2S select SND_PXA2XX_SOC_I2S
select SND_SOC_WM8731 select SND_SOC_WM8731
help help
...@@ -181,7 +182,7 @@ config SND_PXA2XX_SOC_HX4700 ...@@ -181,7 +182,7 @@ config SND_PXA2XX_SOC_HX4700
config SND_PXA2XX_SOC_MAGICIAN config SND_PXA2XX_SOC_MAGICIAN
tristate "SoC Audio support for HTC Magician" tristate "SoC Audio support for HTC Magician"
depends on SND_PXA2XX_SOC && MACH_MAGICIAN depends on SND_PXA2XX_SOC && MACH_MAGICIAN && I2C
select SND_PXA2XX_SOC_I2S select SND_PXA2XX_SOC_I2S
select SND_PXA_SOC_SSP select SND_PXA_SOC_SSP
select SND_SOC_UDA1380 select SND_SOC_UDA1380
......
...@@ -315,7 +315,7 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, ...@@ -315,7 +315,7 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
dst_mod = mod[index]; dst_mod = mod[index];
} else { } else {
src_mod = mod[index]; src_mod = mod[index];
dst_mod = mod[index + 1]; dst_mod = mod[index - 1];
} }
index = 0; index = 0;
......
...@@ -2755,7 +2755,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -2755,7 +2755,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert; unsigned int invert = mc->invert;
unsigned int val; unsigned int val;
int connect, change; int connect, change, reg_change = 0;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int ret = 0; int ret = 0;
...@@ -2773,20 +2773,23 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -2773,20 +2773,23 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = dapm_kcontrol_set_value(kcontrol, val); change = dapm_kcontrol_set_value(kcontrol, val);
if (change) {
if (reg != SND_SOC_NOPM) {
mask = mask << shift;
val = val << shift;
if (snd_soc_test_bits(codec, reg, mask, val)) {
update.kcontrol = kcontrol;
update.reg = reg;
update.mask = mask;
update.val = val;
card->update = &update;
}
if (reg != SND_SOC_NOPM) {
mask = mask << shift;
val = val << shift;
reg_change = snd_soc_test_bits(codec, reg, mask, val);
}
if (change || reg_change) {
if (reg_change) {
update.kcontrol = kcontrol;
update.reg = reg;
update.mask = mask;
update.val = val;
card->update = &update;
} }
change |= reg_change;
ret = soc_dapm_mixer_update_power(card, kcontrol, connect); ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment