Commit fc0daafe authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda-power' into for-next

parents b24062bd 5ccf835c
...@@ -33,30 +33,36 @@ enum { ...@@ -33,30 +33,36 @@ enum {
DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */
}; };
static void snd_hda_generate_beep(struct work_struct *work) /* generate or stop tone */
static void generate_tone(struct hda_beep *beep, int tone)
{ {
struct hda_beep *beep =
container_of(work, struct hda_beep, beep_work);
struct hda_codec *codec = beep->codec; struct hda_codec *codec = beep->codec;
int tone;
if (!beep->enabled)
return;
tone = beep->tone;
if (tone && !beep->playing) { if (tone && !beep->playing) {
snd_hda_power_up(codec); snd_hda_power_up(codec);
if (beep->power_hook)
beep->power_hook(beep, true);
beep->playing = 1; beep->playing = 1;
} }
/* generate tone */
snd_hda_codec_write(codec, beep->nid, 0, snd_hda_codec_write(codec, beep->nid, 0,
AC_VERB_SET_BEEP_CONTROL, tone); AC_VERB_SET_BEEP_CONTROL, tone);
if (!tone && beep->playing) { if (!tone && beep->playing) {
beep->playing = 0; beep->playing = 0;
if (beep->power_hook)
beep->power_hook(beep, false);
snd_hda_power_down(codec); snd_hda_power_down(codec);
} }
} }
static void snd_hda_generate_beep(struct work_struct *work)
{
struct hda_beep *beep =
container_of(work, struct hda_beep, beep_work);
if (beep->enabled)
generate_tone(beep, beep->tone);
}
/* (non-standard) Linear beep tone calculation for IDT/STAC codecs /* (non-standard) Linear beep tone calculation for IDT/STAC codecs
* *
* The tone frequency of beep generator on IDT/STAC codecs is * The tone frequency of beep generator on IDT/STAC codecs is
...@@ -130,10 +136,7 @@ static void turn_off_beep(struct hda_beep *beep) ...@@ -130,10 +136,7 @@ static void turn_off_beep(struct hda_beep *beep)
cancel_work_sync(&beep->beep_work); cancel_work_sync(&beep->beep_work);
if (beep->playing) { if (beep->playing) {
/* turn off beep */ /* turn off beep */
snd_hda_codec_write(beep->codec, beep->nid, 0, generate_tone(beep, 0);
AC_VERB_SET_BEEP_CONTROL, 0);
beep->playing = 0;
snd_hda_power_down(beep->codec);
} }
} }
......
...@@ -40,6 +40,7 @@ struct hda_beep { ...@@ -40,6 +40,7 @@ struct hda_beep {
unsigned int playing:1; unsigned int playing:1;
struct work_struct beep_work; /* scheduled task for beep event */ struct work_struct beep_work; /* scheduled task for beep event */
struct mutex mutex; struct mutex mutex;
void (*power_hook)(struct hda_beep *beep, bool on);
}; };
#ifdef CONFIG_SND_HDA_INPUT_BEEP #ifdef CONFIG_SND_HDA_INPUT_BEEP
......
...@@ -1502,6 +1502,8 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, ...@@ -1502,6 +1502,8 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
if (!p) if (!p)
return; return;
if (codec->patch_ops.stream_pm)
codec->patch_ops.stream_pm(codec, nid, true);
if (codec->pcm_format_first) if (codec->pcm_format_first)
update_pcm_format(codec, p, nid, format); update_pcm_format(codec, p, nid, format);
update_pcm_stream_id(codec, p, nid, stream_tag, channel_id); update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
...@@ -1570,6 +1572,8 @@ static void really_cleanup_stream(struct hda_codec *codec, ...@@ -1570,6 +1572,8 @@ static void really_cleanup_stream(struct hda_codec *codec,
); );
memset(q, 0, sizeof(*q)); memset(q, 0, sizeof(*q));
q->nid = nid; q->nid = nid;
if (codec->patch_ops.stream_pm)
codec->patch_ops.stream_pm(codec, nid, false);
} }
/* clean up the all conflicting obsolete streams */ /* clean up the all conflicting obsolete streams */
......
...@@ -200,6 +200,7 @@ struct hda_codec_ops { ...@@ -200,6 +200,7 @@ struct hda_codec_ops {
int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
#endif #endif
void (*reboot_notify)(struct hda_codec *codec); void (*reboot_notify)(struct hda_codec *codec);
void (*stream_pm)(struct hda_codec *codec, hda_nid_t nid, bool on);
}; };
/* record for amp information cache */ /* record for amp information cache */
...@@ -370,6 +371,7 @@ struct hda_codec { ...@@ -370,6 +371,7 @@ struct hda_codec {
unsigned int cached_write:1; /* write only to caches */ unsigned int cached_write:1; /* write only to caches */
unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
unsigned int power_mgmt:1; /* advanced PM for each widget */
#ifdef CONFIG_PM #ifdef CONFIG_PM
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
atomic_t in_pm; /* suspend/resume being performed */ atomic_t in_pm; /* suspend/resume being performed */
......
This diff is collapsed.
...@@ -46,7 +46,9 @@ struct nid_path { ...@@ -46,7 +46,9 @@ struct nid_path {
unsigned char idx[MAX_NID_PATH_DEPTH]; unsigned char idx[MAX_NID_PATH_DEPTH];
unsigned char multi[MAX_NID_PATH_DEPTH]; unsigned char multi[MAX_NID_PATH_DEPTH];
unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */ unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
bool active; bool active:1; /* activated by driver */
bool pin_enabled:1; /* pins are enabled */
bool stream_enabled:1; /* stream is active */
}; };
/* mic/line-in auto switching entry */ /* mic/line-in auto switching entry */
...@@ -340,5 +342,6 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid); ...@@ -340,5 +342,6 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid, hda_nid_t nid,
unsigned int power_state); unsigned int power_state);
void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
#endif /* __SOUND_HDA_GENERIC_H */ #endif /* __SOUND_HDA_GENERIC_H */
...@@ -2602,53 +2602,12 @@ static int patch_alc268(struct hda_codec *codec) ...@@ -2602,53 +2602,12 @@ static int patch_alc268(struct hda_codec *codec)
* ALC269 * ALC269
*/ */
static int playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct hda_gen_spec *spec = codec->spec;
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo);
}
static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct hda_gen_spec *spec = codec->spec;
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
stream_tag, format, substream);
}
static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct hda_gen_spec *spec = codec->spec;
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_44100, /* fixed rate */ .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
/* NID is set in alc_build_pcms */
.ops = {
.open = playback_pcm_open,
.prepare = playback_pcm_prepare,
.cleanup = playback_pcm_cleanup
},
}; };
static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_44100, /* fixed rate */ .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
/* NID is set in alc_build_pcms */
}; };
/* different alc269-variants */ /* different alc269-variants */
......
...@@ -4394,6 +4394,7 @@ static const struct hda_codec_ops stac_patch_ops = { ...@@ -4394,6 +4394,7 @@ static const struct hda_codec_ops stac_patch_ops = {
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = stac_suspend, .suspend = stac_suspend,
#endif #endif
.stream_pm = snd_hda_gen_stream_pm,
.reboot_notify = stac_shutup, .reboot_notify = stac_shutup,
}; };
...@@ -4487,6 +4488,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) ...@@ -4487,6 +4488,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
return err; return err;
spec = codec->spec; spec = codec->spec;
codec->power_mgmt = 1;
spec->linear_tone_beep = 0; spec->linear_tone_beep = 0;
spec->gen.mixer_nid = 0x1d; spec->gen.mixer_nid = 0x1d;
spec->have_spdif_mux = 1; spec->have_spdif_mux = 1;
...@@ -4592,6 +4594,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) ...@@ -4592,6 +4594,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
codec->epss = 0; /* longer delay needed for D3 */ codec->epss = 0; /* longer delay needed for D3 */
spec = codec->spec; spec = codec->spec;
codec->power_mgmt = 1;
spec->linear_tone_beep = 0; spec->linear_tone_beep = 0;
spec->gen.own_eapd_ctl = 1; spec->gen.own_eapd_ctl = 1;
spec->gen.power_down_unused = 1; spec->gen.power_down_unused = 1;
...@@ -4641,6 +4644,7 @@ static int patch_stac92hd95(struct hda_codec *codec) ...@@ -4641,6 +4644,7 @@ static int patch_stac92hd95(struct hda_codec *codec)
codec->epss = 0; /* longer delay needed for D3 */ codec->epss = 0; /* longer delay needed for D3 */
spec = codec->spec; spec = codec->spec;
codec->power_mgmt = 1;
spec->linear_tone_beep = 0; spec->linear_tone_beep = 0;
spec->gen.own_eapd_ctl = 1; spec->gen.own_eapd_ctl = 1;
spec->gen.power_down_unused = 1; spec->gen.power_down_unused = 1;
...@@ -4682,6 +4686,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) ...@@ -4682,6 +4686,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
return err; return err;
spec = codec->spec; spec = codec->spec;
codec->power_mgmt = 1;
spec->linear_tone_beep = 0; spec->linear_tone_beep = 0;
spec->gen.own_eapd_ctl = 1; spec->gen.own_eapd_ctl = 1;
spec->gen.power_down_unused = 1; spec->gen.power_down_unused = 1;
......
This diff is collapsed.
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