Skip to content

Commit

Permalink
Merge branch 'topic/hda' into for-linus
Browse files Browse the repository at this point in the history
  • Loading branch information
Takashi Iwai committed Aug 5, 2010
2 parents 9fe6206 + fc09176 commit 2603798
Show file tree
Hide file tree
Showing 13 changed files with 897 additions and 147 deletions.
6 changes: 6 additions & 0 deletions Documentation/sound/alsa/HD-Audio-Models.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ ALC662/663/272
samsung-nc10 Samsung NC10 mini notebook
auto auto-config reading BIOS (default)

ALC680
======
base Base model (ASUS NX90)
auto auto-config reading BIOS (default)

ALC882/883/885/888/889
======================
3stack-dig 3-jack with SPDIF I/O
Expand Down Expand Up @@ -282,6 +287,7 @@ Conexant 5051
hp HP Spartan laptop
hp-dv6736 HP dv6736
hp-f700 HP Compaq Presario F700
ideapad Lenovo IdeaPad laptop
lenovo-x200 Lenovo X200 laptop
toshiba Toshiba Satellite M300

Expand Down
87 changes: 55 additions & 32 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,15 +396,18 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
}
for (n = prev_nid + 1; n <= val; n++) {
if (conns >= max_conns) {
snd_printk(KERN_ERR
"Too many connections\n");
snd_printk(KERN_ERR "hda_codec: "
"Too many connections %d for NID 0x%x\n",
conns, nid);
return -EINVAL;
}
conn_list[conns++] = n;
}
} else {
if (conns >= max_conns) {
snd_printk(KERN_ERR "Too many connections\n");
snd_printk(KERN_ERR "hda_codec: "
"Too many connections %d for NID 0x%x\n",
conns, nid);
return -EINVAL;
}
conn_list[conns++] = val;
Expand Down Expand Up @@ -1565,6 +1568,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
#endif /* SND_HDA_NEEDS_RESUME */

static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int ofs)
{
u32 caps = query_amp_caps(codec, nid, dir);
/* get num steps */
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
if (ofs < caps)
caps -= ofs;
return caps;
}

/**
* snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
*
Expand All @@ -1579,23 +1593,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
u8 chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol);
u32 caps;

caps = query_amp_caps(codec, nid, dir);
/* num steps */
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
if (!caps) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = chs == 3 ? 2 : 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
if (!uinfo->value.integer.max) {
printk(KERN_WARNING "hda_codec: "
"num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
kcontrol->id.name);
return -EINVAL;
}
if (ofs < caps)
caps -= ofs;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = chs == 3 ? 2 : 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = caps;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
Expand All @@ -1620,8 +1628,14 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
int ch, int dir, int idx, unsigned int ofs,
unsigned int val)
{
unsigned int maxval;

if (val > 0)
val += ofs;
/* ofs = 0: raw max value */
maxval = get_amp_max_value(codec, nid, dir, 0);
if (val > maxval)
val = maxval;
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
HDA_AMP_VOLMASK, val);
}
Expand Down Expand Up @@ -2999,26 +3013,31 @@ struct hda_rate_tbl {
unsigned int hda_fmt;
};

/* rate = base * mult / div */
#define HDA_RATE(base, mult, div) \
(AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \
(((div) - 1) << AC_FMT_DIV_SHIFT))

static struct hda_rate_tbl rate_bits[] = {
/* rate in Hz, ALSA rate bitmask, HDA format value */

/* autodetected value used in snd_hda_query_supported_pcm */
{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
{ 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */
{ 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */
{ 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */
{ 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */
{ 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */
{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
{ 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) },
{ 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) },
{ 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) },
{ 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) },
{ 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) },
{ 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) },
{ 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) },
{ 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) },
{ 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) },
{ 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) },
{ 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) },
#define AC_PAR_PCM_RATE_BITS 11
/* up to bits 10, 384kHZ isn't supported properly */

/* not autodetected value */
{ 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
{ 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) },

{ 0 } /* terminator */
};
Expand All @@ -3037,7 +3056,8 @@ static struct hda_rate_tbl rate_bits[] = {
unsigned int snd_hda_calc_stream_format(unsigned int rate,
unsigned int channels,
unsigned int format,
unsigned int maxbps)
unsigned int maxbps,
unsigned short spdif_ctls)
{
int i;
unsigned int val = 0;
Expand All @@ -3060,27 +3080,30 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,

switch (snd_pcm_format_width(format)) {
case 8:
val |= 0x00;
val |= AC_FMT_BITS_8;
break;
case 16:
val |= 0x10;
val |= AC_FMT_BITS_16;
break;
case 20:
case 24:
case 32:
if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
val |= 0x40;
val |= AC_FMT_BITS_32;
else if (maxbps >= 24)
val |= 0x30;
val |= AC_FMT_BITS_24;
else
val |= 0x20;
val |= AC_FMT_BITS_20;
break;
default:
snd_printdd("invalid format width %d\n",
snd_pcm_format_width(format));
return 0;
}

if (spdif_ctls & AC_DIG1_NONAUDIO)
val |= AC_FMT_TYPE_NON_PCM;

return val;
}
EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
Expand Down
27 changes: 26 additions & 1 deletion sound/pci/hda/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,27 @@ enum {
/* Input converter SDI select */
#define AC_SDI_SELECT (0xf<<0)

/* stream format id */
#define AC_FMT_CHAN_SHIFT 0
#define AC_FMT_CHAN_MASK (0x0f << 0)
#define AC_FMT_BITS_SHIFT 4
#define AC_FMT_BITS_MASK (7 << 4)
#define AC_FMT_BITS_8 (0 << 4)
#define AC_FMT_BITS_16 (1 << 4)
#define AC_FMT_BITS_20 (2 << 4)
#define AC_FMT_BITS_24 (3 << 4)
#define AC_FMT_BITS_32 (4 << 4)
#define AC_FMT_DIV_SHIFT 8
#define AC_FMT_DIV_MASK (7 << 8)
#define AC_FMT_MULT_SHIFT 11
#define AC_FMT_MULT_MASK (7 << 11)
#define AC_FMT_BASE_SHIFT 14
#define AC_FMT_BASE_48K (0 << 14)
#define AC_FMT_BASE_44K (1 << 14)
#define AC_FMT_TYPE_SHIFT 15
#define AC_FMT_TYPE_PCM (0 << 15)
#define AC_FMT_TYPE_NON_PCM (1 << 15)

/* Unsolicited response control */
#define AC_UNSOL_TAG (0x3f<<0)
#define AC_UNSOL_ENABLED (1<<7)
Expand Down Expand Up @@ -364,6 +385,9 @@ enum {
#define AC_DIG2_CC (0x7f<<0)

/* Pin widget control - 8bit */
#define AC_PINCTL_EPT (0x3<<0)
#define AC_PINCTL_EPT_NATIVE 0
#define AC_PINCTL_EPT_HBR 3
#define AC_PINCTL_VREFEN (0x7<<0)
#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
#define AC_PINCTL_VREF_50 1 /* 50% */
Expand Down Expand Up @@ -928,7 +952,8 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid);
unsigned int snd_hda_calc_stream_format(unsigned int rate,
unsigned int channels,
unsigned int format,
unsigned int maxbps);
unsigned int maxbps,
unsigned short spdif_ctls);
int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
unsigned int format);

Expand Down
4 changes: 3 additions & 1 deletion sound/pci/hda/hda_hwdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,9 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
*codecp = NULL;
if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
list_for_each_entry(codec, &bus->codec_list, list) {
if (codec->addr == caddr) {
if (codec->vendor_id == vendorid &&
codec->subsystem_id == subid &&
codec->addr == caddr) {
*codecp = codec;
break;
}
Expand Down
5 changes: 3 additions & 2 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1653,7 +1653,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
hinfo->maxbps);
hinfo->maxbps,
apcm->codec->spdif_ctls);
if (!format_val) {
snd_printk(KERN_ERR SFX
"invalid format_val, rate=%d, ch=%d, format=%d\n",
Expand Down Expand Up @@ -1960,7 +1961,7 @@ static void azx_irq_pending_work(struct work_struct *work)
spin_unlock_irq(&chip->reg_lock);
if (!pending)
return;
cond_resched();
msleep(1);
}
}

Expand Down
7 changes: 6 additions & 1 deletion sound/pci/hda/patch_analog.c
Original file line number Diff line number Diff line change
Expand Up @@ -3662,7 +3662,12 @@ static int patch_ad1984(struct hda_codec *codec)
codec->patch_ops.build_pcms = ad1984_build_pcms;
break;
case AD1984_THINKPAD:
spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
if (codec->subsystem_id == 0x17aa20fb) {
/* Thinpad X300 does not have the ability to do SPDIF,
or attach to docking station to use SPDIF */
spec->multiout.dig_out_nid = 0;
} else
spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
spec->input_mux = &ad1984_thinkpad_capture_source;
spec->mixers[0] = ad1984_thinkpad_mixers;
spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
Expand Down
Loading

0 comments on commit 2603798

Please sign in to comment.