Skip to content

Commit

Permalink
Sound Control: (Optional) work around for Nexus 4/5 audio issues
Browse files Browse the repository at this point in the history
(Use this only for devices with audio reset issues)

Also bump version to 3.1

Signed-off-by: Paul Reioux <reioux@gmail.com>

wcd9xxx-core: add register write without mutex protection

This is assuming the calling function will take care of the mutex.

Signed-off-by: Paul Reioux <reioux@gmail.com>
  • Loading branch information
faux123 committed Nov 25, 2013
1 parent 2a77a58 commit 33407fd
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 29 deletions.
16 changes: 16 additions & 0 deletions drivers/mfd/wcd9xxx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@ int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
}
EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);

#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
int wcd9xxx_reg_read_safe(struct wcd9xxx *wcd9xxx, unsigned short reg)
{
u8 val;
int ret;

ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, false);

if (ret < 0)
return ret;
else
return val;
}
EXPORT_SYMBOL_GPL(wcd9xxx_reg_read_safe);
#endif

static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg)
{
Expand Down
3 changes: 3 additions & 0 deletions include/linux/mfd/wcd9xxx/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ struct wcd9xxx {
};

int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
int wcd9xxx_reg_read_safe(struct wcd9xxx *wcd9xxx, unsigned short reg);
#endif
int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
u8 val);
int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
Expand Down
73 changes: 67 additions & 6 deletions sound/soc/codecs/sound_control_3_gpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,48 @@
#include <linux/mfd/wcd9xxx/wcd9320_registers.h>

#define SOUND_CONTROL_MAJOR_VERSION 3
#define SOUND_CONTROL_MINOR_VERSION 0
#define SOUND_CONTROL_MINOR_VERSION 1

extern struct snd_soc_codec *fauxsound_codec_ptr;

static int snd_ctrl_locked = 0;

unsigned int taiko_read(struct snd_soc_codec *codec, unsigned int reg);
int taiko_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value);

int reg_access(unsigned int reg)
{
int ret = 1;

switch (reg) {
case TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL:
case TAIKO_A_CDC_TX1_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX2_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX3_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX4_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX5_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX6_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX7_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX8_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX9_VOL_CTL_GAIN:
case TAIKO_A_CDC_TX10_VOL_CTL_GAIN:
if (snd_ctrl_locked)
ret = 0;
break;
default:
break;
}
return ret;
}
EXPORT_SYMBOL(reg_access);

static bool calc_checksum(unsigned int a, unsigned int b, unsigned int c)
{
unsigned char chksum = 0;
Expand All @@ -46,7 +80,7 @@ static bool calc_checksum(unsigned int a, unsigned int b, unsigned int c)
static ssize_t cam_mic_gain_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u",
return sprintf(buf, "%u\n",
taiko_read(fauxsound_codec_ptr,
TAIKO_A_CDC_TX6_VOL_CTL_GAIN));

Expand All @@ -69,7 +103,7 @@ static ssize_t cam_mic_gain_store(struct kobject *kobj,
static ssize_t mic_gain_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u",
return sprintf(buf, "%u\n",
taiko_read(fauxsound_codec_ptr,
TAIKO_A_CDC_TX7_VOL_CTL_GAIN));
}
Expand All @@ -92,7 +126,7 @@ static ssize_t mic_gain_store(struct kobject *kobj,
static ssize_t speaker_gain_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u %u",
return sprintf(buf, "%u %u\n",
taiko_read(fauxsound_codec_ptr,
TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL),
taiko_read(fauxsound_codec_ptr,
Expand All @@ -119,7 +153,7 @@ static ssize_t speaker_gain_store(struct kobject *kobj,
static ssize_t headphone_gain_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u %u",
return sprintf(buf, "%u %u\n",
taiko_read(fauxsound_codec_ptr,
TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL),
taiko_read(fauxsound_codec_ptr,
Expand All @@ -145,7 +179,7 @@ static ssize_t headphone_gain_store(struct kobject *kobj,
static ssize_t headphone_pa_gain_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%u %u",
return sprintf(buf, "%u %u\n",
taiko_read(fauxsound_codec_ptr, TAIKO_A_RX_HPH_L_GAIN),
taiko_read(fauxsound_codec_ptr, TAIKO_A_RX_HPH_R_GAIN));
}
Expand Down Expand Up @@ -186,6 +220,26 @@ static ssize_t sound_control_version_show(struct kobject *kobj, struct kobj_attr
SOUND_CONTROL_MINOR_VERSION);
}

static ssize_t sound_control_locked_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int inp;

sscanf(buf, "%d", &inp);

if (inp == 0)
snd_ctrl_locked = 0;
else
snd_ctrl_locked = 1;

return count;
}

static ssize_t sound_control_locked_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", snd_ctrl_locked);
}

static struct kobj_attribute cam_mic_gain_attribute =
__ATTR(gpl_cam_mic_gain,
0666,
Expand Down Expand Up @@ -216,6 +270,12 @@ static struct kobj_attribute headphone_pa_gain_attribute =
headphone_pa_gain_show,
headphone_pa_gain_store);

static struct kobj_attribute sound_control_locked_attribute =
__ATTR(gpl_sound_control_locked,
0666,
sound_control_locked_show,
sound_control_locked_store);

static struct kobj_attribute sound_control_version_attribute =
__ATTR(gpl_sound_control_version,
0444,
Expand All @@ -228,6 +288,7 @@ static struct attribute *sound_control_attrs[] =
&speaker_gain_attribute.attr,
&headphone_gain_attribute.attr,
&headphone_pa_gain_attribute.attr,
&sound_control_locked_attribute.attr,
&sound_control_version_attribute.attr,
NULL,
};
Expand Down
61 changes: 38 additions & 23 deletions sound/soc/codecs/wcd9320.c
Original file line number Diff line number Diff line change
Expand Up @@ -4010,61 +4010,76 @@ static int taiko_volatile(struct snd_soc_codec *ssc, unsigned int reg)
return 0;
}

#ifndef CONFIG_SOUND_CONTROL_HAX_3_GPL
#ifndef CONFIG_SOUND_CONTROL_HAX_3_GPL
static
#endif
int taiko_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
unsigned int taiko_read(struct snd_soc_codec *codec,
unsigned int reg)
{
unsigned int val;
int ret;

if (reg == SND_SOC_NOPM)
return 0;

BUG_ON(reg > TAIKO_MAX_REGISTER);

if (!taiko_volatile(codec, reg)) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret != 0)
dev_err(codec->dev, "Cache write to %x failed: %d\n",
if (!taiko_volatile(codec, reg) && taiko_readable(codec, reg) &&
reg < codec->driver->reg_cache_size) {
ret = snd_soc_cache_read(codec, reg, &val);
if (ret >= 0) {
return val;
} else
dev_err(codec->dev, "Cache read from %x failed: %d\n",
reg, ret);
}

return wcd9xxx_reg_write(codec->control_data, reg, value);
val = wcd9xxx_reg_read(codec->control_data, reg);
return val;
}
#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
EXPORT_SYMBOL(taiko_write);
EXPORT_SYMBOL(taiko_read);
#endif

#ifndef CONFIG_SOUND_CONTROL_HAX_3_GPL
#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
extern int reg_access(unsigned int);
#endif

#ifndef CONFIG_SOUND_CONTROL_HAX_3_GPL
static
#endif
unsigned int taiko_read(struct snd_soc_codec *codec,
unsigned int reg)
int taiko_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
unsigned int val;
int ret;
#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
int val;
#endif

if (reg == SND_SOC_NOPM)
return 0;

BUG_ON(reg > TAIKO_MAX_REGISTER);

if (!taiko_volatile(codec, reg) && taiko_readable(codec, reg) &&
reg < codec->driver->reg_cache_size) {
ret = snd_soc_cache_read(codec, reg, &val);
if (ret >= 0) {
return val;
} else
dev_err(codec->dev, "Cache read from %x failed: %d\n",
if (!taiko_volatile(codec, reg)) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret != 0)
dev_err(codec->dev, "Cache write to %x failed: %d\n",
reg, ret);
}

val = wcd9xxx_reg_read(codec->control_data, reg);
return val;
#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
if (!reg_access(reg))
val = wcd9xxx_reg_read_safe(codec->control_data, reg);
else
val = value;
return wcd9xxx_reg_write(codec->control_data, reg, val);
#else
return wcd9xxx_reg_write(codec->control_data, reg, value);
#endif
}
#ifdef CONFIG_SOUND_CONTROL_HAX_3_GPL
EXPORT_SYMBOL(taiko_read);
EXPORT_SYMBOL(taiko_write);
#endif

static int taiko_startup(struct snd_pcm_substream *substream,
Expand Down

0 comments on commit 33407fd

Please sign in to comment.