Skip to content

Commit

Permalink
Merge remote-tracking branches 'asoc/topic/88pm860x', 'asoc/topic/ac9…
Browse files Browse the repository at this point in the history
…7', 'asoc/topic/ak4542', 'asoc/topic/arizona' and 'asoc/topic/atmel' into asoc-next
  • Loading branch information
broonie committed Aug 30, 2015
6 parents 28becbd + 93ec3a1 + 310398f + f8ea6ce + d90c6cc + 56113f6 commit 21af109
Show file tree
Hide file tree
Showing 18 changed files with 296 additions and 242 deletions.
2 changes: 2 additions & 0 deletions include/sound/ac97_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,8 @@ static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg,
void snd_ac97_suspend(struct snd_ac97 *ac97);
void snd_ac97_resume(struct snd_ac97 *ac97);
#endif
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
unsigned int id_mask);

/* quirk types */
enum {
Expand Down
3 changes: 2 additions & 1 deletion include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,

#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
unsigned int id, unsigned int id_mask);
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);

int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
Expand Down
62 changes: 62 additions & 0 deletions sound/ac97_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,68 @@
#include <linux/string.h>
#include <sound/ac97_codec.h>

/*
* snd_ac97_check_id() - Reads and checks the vendor ID of the device
* @ac97: The AC97 device to check
* @id: The ID to compare to
* @id_mask: Mask that is applied to the device ID before comparing to @id
*
* If @id is 0 this function returns true if the read device vendor ID is
* a valid ID. If @id is non 0 this functions returns true if @id
* matches the read vendor ID. Otherwise the function returns false.
*/
static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,
unsigned int id_mask)
{
ac97->id = ac97->bus->ops->read(ac97, AC97_VENDOR_ID1) << 16;
ac97->id |= ac97->bus->ops->read(ac97, AC97_VENDOR_ID2);

if (ac97->id == 0x0 || ac97->id == 0xffffffff)
return false;

if (id != 0 && id != (ac97->id & id_mask))
return false;

return true;
}

/**
* snd_ac97_reset() - Reset AC'97 device
* @ac97: The AC'97 device to reset
* @try_warm: Try a warm reset first
* @id: Expected device vendor ID
* @id_mask: Mask that is applied to the device ID before comparing to @id
*
* This function resets the AC'97 device. If @try_warm is true the function
* first performs a warm reset. If the warm reset is successful the function
* returns 1. Otherwise or if @try_warm is false the function issues cold reset
* followed by a warm reset. If this is successful the function returns 0,
* otherwise a negative error code. If @id is 0 any valid device ID will be
* accepted, otherwise only the ID that matches @id and @id_mask is accepted.
*/
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
unsigned int id_mask)
{
struct snd_ac97_bus_ops *ops = ac97->bus->ops;

if (try_warm && ops->warm_reset) {
ops->warm_reset(ac97);
if (snd_ac97_check_id(ac97, id, id_mask))
return 1;
}

if (ops->reset)
ops->reset(ac97);
if (ops->warm_reset)
ops->warm_reset(ac97);

if (snd_ac97_check_id(ac97, id, id_mask))
return 0;

return -ENODEV;
}
EXPORT_SYMBOL_GPL(snd_ac97_reset);

/*
* Let drivers decide whether they want to support given codec from their
* probe method. Drivers have direct access to the struct snd_ac97
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/atmel/atmel_ssc_dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
int dir, dir_mask;
int ret;

pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
pr_debug("atmel_ssc_startup: SSC_SR=0x%x\n",
ssc_readl(ssc_p->ssc->regs, SR));

/* Enable PMC peripheral clock for this SSC */
Expand Down
4 changes: 1 addition & 3 deletions sound/soc/codecs/88pm860x-codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,10 +1028,8 @@ static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,

if (dir == PM860X_CLK_DIR_OUT)
pm860x->dir = PM860X_CLK_DIR_OUT;
else {
pm860x->dir = PM860X_CLK_DIR_IN;
else /* Slave mode is not supported */
return -EINVAL;
}

return 0;
}
Expand Down
36 changes: 12 additions & 24 deletions sound/soc/codecs/ad1980.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,21 @@ static struct snd_soc_dai_driver ad1980_dai = {
.formats = SND_SOC_STD_AC97_FMTS, },
};

#define AD1980_VENDOR_ID 0x41445300
#define AD1980_VENDOR_MASK 0xffffff00

static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
unsigned int retry_cnt = 0;
int ret;

do {
if (try_warm && soc_ac97_ops->warm_reset) {
soc_ac97_ops->warm_reset(ac97);
if (snd_soc_read(codec, AC97_RESET) == 0x0090)
return 1;
}
ret = snd_ac97_reset(ac97, true, AD1980_VENDOR_ID,
AD1980_VENDOR_MASK);
if (ret >= 0)
return 0;

soc_ac97_ops->reset(ac97);
/*
* Set bit 16slot in register 74h, then every slot will has only
* 16 bits. This command is sent out in 20bit mode, in which
Expand All @@ -223,8 +225,6 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
*/
snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);

if (snd_soc_read(codec, AC97_RESET) == 0x0090)
return 0;
} while (retry_cnt++ < 10);

dev_err(codec->dev, "Failed to reset: AC97 link error\n");
Expand All @@ -240,7 +240,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
u16 vendor_id2;
u16 ext_status;

ac97 = snd_soc_new_ac97_codec(codec);
ac97 = snd_soc_new_ac97_codec(codec, 0, 0);
if (IS_ERR(ac97)) {
ret = PTR_ERR(ac97);
dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
Expand All @@ -260,22 +260,10 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
if (ret < 0)
goto reset_err;

/* Read out vendor ID to make sure it is ad1980 */
if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) {
ret = -ENODEV;
goto reset_err;
}

vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);

if (vendor_id2 != 0x5370) {
if (vendor_id2 != 0x5374) {
ret = -ENODEV;
goto reset_err;
} else {
dev_warn(codec->dev,
"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
}
if (vendor_id2 == 0x5374) {
dev_warn(codec->dev,
"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
}

/* unmute captures and playbacks volume */
Expand Down
33 changes: 26 additions & 7 deletions sound/soc/codecs/ak4642.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,15 @@
#define FIL1_0 0x1c
#define FIL1_1 0x1d
#define FIL1_2 0x1e
#define FIL1_3 0x1f
#define FIL1_3 0x1f /* The maximum valid register for ak4642 */
#define PW_MGMT4 0x20
#define MD_CTL5 0x21
#define LO_MS 0x22
#define HP_MS 0x23
#define SPK_MS 0x24
#define SPK_MS 0x24 /* The maximum valid register for ak4643 */
#define EQ_FBEQAB 0x25
#define EQ_FBEQCD 0x26
#define EQ_FBEQE 0x27 /* The maximum valid register for ak4648 */

/* PW_MGMT1*/
#define PMVCM (1 << 6) /* VCOM Power Management */
Expand Down Expand Up @@ -241,7 +244,7 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
/*
* ak4642 register cache
*/
static const struct reg_default ak4642_reg[] = {
static const struct reg_default ak4643_reg[] = {
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
{ 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
Expand All @@ -254,6 +257,14 @@ static const struct reg_default ak4642_reg[] = {
{ 36, 0x00 },
};

/* The default settings for 0x0 ~ 0x1f registers are the same for ak4642
and ak4643. So we reuse the ak4643 reg_default for ak4642.
The valid registers for ak4642 are 0x0 ~ 0x1f which is a subset of ak4643,
so define NUM_AK4642_REG_DEFAULTS for ak4642.
*/
#define ak4642_reg ak4643_reg
#define NUM_AK4642_REG_DEFAULTS (FIL1_3 + 1)

static const struct reg_default ak4648_reg[] = {
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
Expand Down Expand Up @@ -535,15 +546,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
static const struct regmap_config ak4642_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ARRAY_SIZE(ak4642_reg) + 1,
.max_register = FIL1_3,
.reg_defaults = ak4642_reg,
.num_reg_defaults = ARRAY_SIZE(ak4642_reg),
.num_reg_defaults = NUM_AK4642_REG_DEFAULTS,
};

static const struct regmap_config ak4643_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SPK_MS,
.reg_defaults = ak4643_reg,
.num_reg_defaults = ARRAY_SIZE(ak4643_reg),
};

static const struct regmap_config ak4648_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ARRAY_SIZE(ak4648_reg) + 1,
.max_register = EQ_FBEQE,
.reg_defaults = ak4648_reg,
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
};
Expand All @@ -553,7 +572,7 @@ static const struct ak4642_drvdata ak4642_drvdata = {
};

static const struct ak4642_drvdata ak4643_drvdata = {
.regmap_config = &ak4642_regmap,
.regmap_config = &ak4643_regmap,
};

static const struct ak4642_drvdata ak4648_drvdata = {
Expand Down
78 changes: 77 additions & 1 deletion sound/soc/codecs/arizona.c
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
else
rates = &arizona_48k_bclk_rates[0];

wl = snd_pcm_format_width(params_format(params));
wl = params_width(params);

if (tdm_slots) {
arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
Expand Down Expand Up @@ -2304,6 +2304,82 @@ const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
};
EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);

static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
{
s16 a = be16_to_cpu(_a);
s16 b = be16_to_cpu(_b);

if (!mode) {
return abs(a) >= 4096;
} else {
if (abs(b) >= 4096)
return true;

return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
}
}

int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct soc_bytes *params = (void *)kcontrol->private_value;
unsigned int val;
__be16 *data;
int len;
int ret;

len = params->num_regs * regmap_get_val_bytes(arizona->regmap);

data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
if (!data)
return -ENOMEM;

data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);

if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
arizona_eq_filter_unstable(true, data[4], data[5]) ||
arizona_eq_filter_unstable(true, data[8], data[9]) ||
arizona_eq_filter_unstable(true, data[12], data[13]) ||
arizona_eq_filter_unstable(false, data[16], data[17])) {
dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
ret = -EINVAL;
goto out;
}

ret = regmap_read(arizona->regmap, params->base, &val);
if (ret != 0)
goto out;

val &= ~ARIZONA_EQ1_B1_MODE;
data[0] |= cpu_to_be16(val);

ret = regmap_raw_write(arizona->regmap, params->base, data, len);

out:
kfree(data);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);

int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
__be16 *data = (__be16 *)ucontrol->value.bytes.data;
s16 val = be16_to_cpu(*data);

if (abs(val) >= 4096) {
dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
return -EINVAL;
}

return snd_soc_bytes_put(kcontrol, ucontrol);
}
EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);

MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <[email protected]>");
MODULE_LICENSE("GPL");
19 changes: 19 additions & 0 deletions sound/soc/codecs/arizona.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
ARIZONA_MIXER_ROUTES(name " Preloader", name "R")

#define ARIZONA_EQ_CONTROL(xname, xbase) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
.put = arizona_eq_coeff_put, .private_value = \
((unsigned long)&(struct soc_bytes) { .base = xbase, \
.num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) }

#define ARIZONA_LHPF_CONTROL(xname, xbase) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
.put = arizona_lhpf_coeff_put, .private_value = \
((unsigned long)&(struct soc_bytes) { .base = xbase, \
.num_regs = 1 }) }

#define ARIZONA_RATE_ENUM_SIZE 4
extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
Expand Down Expand Up @@ -229,6 +243,11 @@ extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);

extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);

extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir);

Expand Down
Loading

0 comments on commit 21af109

Please sign in to comment.