162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * stac9766.c  --  ALSA SoC STAC9766 codec support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2009 Jon Smirl, Digispeaker
662306a36Sopenharmony_ci * Author: Jon Smirl <jonsmirl@gmail.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Features:-
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *   o Support for AC97 Codec, S/PDIF
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/device.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <sound/core.h>
1962306a36Sopenharmony_ci#include <sound/pcm.h>
2062306a36Sopenharmony_ci#include <sound/ac97_codec.h>
2162306a36Sopenharmony_ci#include <sound/initval.h>
2262306a36Sopenharmony_ci#include <sound/pcm_params.h>
2362306a36Sopenharmony_ci#include <sound/soc.h>
2462306a36Sopenharmony_ci#include <sound/tlv.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define STAC9766_VENDOR_ID 0x83847666
2762306a36Sopenharmony_ci#define STAC9766_VENDOR_ID_MASK 0xffffffff
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define AC97_STAC_DA_CONTROL 0x6A
3062306a36Sopenharmony_ci#define AC97_STAC_ANALOG_SPECIAL 0x6E
3162306a36Sopenharmony_ci#define AC97_STAC_STEREO_MIC 0x78
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic const struct reg_default stac9766_reg_defaults[] = {
3462306a36Sopenharmony_ci	{ 0x02, 0x8000 },
3562306a36Sopenharmony_ci	{ 0x04, 0x8000 },
3662306a36Sopenharmony_ci	{ 0x06, 0x8000 },
3762306a36Sopenharmony_ci	{ 0x0a, 0x0000 },
3862306a36Sopenharmony_ci	{ 0x0c, 0x8008 },
3962306a36Sopenharmony_ci	{ 0x0e, 0x8008 },
4062306a36Sopenharmony_ci	{ 0x10, 0x8808 },
4162306a36Sopenharmony_ci	{ 0x12, 0x8808 },
4262306a36Sopenharmony_ci	{ 0x14, 0x8808 },
4362306a36Sopenharmony_ci	{ 0x16, 0x8808 },
4462306a36Sopenharmony_ci	{ 0x18, 0x8808 },
4562306a36Sopenharmony_ci	{ 0x1a, 0x0000 },
4662306a36Sopenharmony_ci	{ 0x1c, 0x8000 },
4762306a36Sopenharmony_ci	{ 0x20, 0x0000 },
4862306a36Sopenharmony_ci	{ 0x22, 0x0000 },
4962306a36Sopenharmony_ci	{ 0x28, 0x0a05 },
5062306a36Sopenharmony_ci	{ 0x2c, 0xbb80 },
5162306a36Sopenharmony_ci	{ 0x32, 0xbb80 },
5262306a36Sopenharmony_ci	{ 0x3a, 0x2000 },
5362306a36Sopenharmony_ci	{ 0x3e, 0x0100 },
5462306a36Sopenharmony_ci	{ 0x4c, 0x0300 },
5562306a36Sopenharmony_ci	{ 0x4e, 0xffff },
5662306a36Sopenharmony_ci	{ 0x50, 0x0000 },
5762306a36Sopenharmony_ci	{ 0x52, 0x0000 },
5862306a36Sopenharmony_ci	{ 0x54, 0x0000 },
5962306a36Sopenharmony_ci	{ 0x6a, 0x0000 },
6062306a36Sopenharmony_ci	{ 0x6e, 0x1000 },
6162306a36Sopenharmony_ci	{ 0x72, 0x0000 },
6262306a36Sopenharmony_ci	{ 0x78, 0x0000 },
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic const struct regmap_config stac9766_regmap_config = {
6662306a36Sopenharmony_ci	.reg_bits = 16,
6762306a36Sopenharmony_ci	.reg_stride = 2,
6862306a36Sopenharmony_ci	.val_bits = 16,
6962306a36Sopenharmony_ci	.max_register = 0x78,
7062306a36Sopenharmony_ci	.cache_type = REGCACHE_MAPLE,
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	.volatile_reg = regmap_ac97_default_volatile,
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	.reg_defaults = stac9766_reg_defaults,
7562306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults),
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX",
7962306a36Sopenharmony_ci			"Line", "Stereo Mix", "Mono Mix", "Phone"};
8062306a36Sopenharmony_cistatic const char *stac9766_mono_mux[] = {"Mix", "Mic"};
8162306a36Sopenharmony_cistatic const char *stac9766_mic_mux[] = {"Mic1", "Mic2"};
8262306a36Sopenharmony_cistatic const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"};
8362306a36Sopenharmony_cistatic const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"};
8462306a36Sopenharmony_cistatic const char *stac9766_record_all_mux[] = {"All analog",
8562306a36Sopenharmony_ci	"Analog plus DAC"};
8662306a36Sopenharmony_cistatic const char *stac9766_boost1[] = {"0dB", "10dB"};
8762306a36Sopenharmony_cistatic const char *stac9766_boost2[] = {"0dB", "20dB"};
8862306a36Sopenharmony_cistatic const char *stac9766_stereo_mic[] = {"Off", "On"};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(stac9766_record_enum,
9162306a36Sopenharmony_ci			    AC97_REC_SEL, 8, 0, stac9766_record_mux);
9262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_mono_enum,
9362306a36Sopenharmony_ci			    AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux);
9462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_mic_enum,
9562306a36Sopenharmony_ci			    AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux);
9662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum,
9762306a36Sopenharmony_ci			    AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux);
9862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum,
9962306a36Sopenharmony_ci			    AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux);
10062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum,
10162306a36Sopenharmony_ci			    AC97_STAC_ANALOG_SPECIAL, 12,
10262306a36Sopenharmony_ci			    stac9766_record_all_mux);
10362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum,
10462306a36Sopenharmony_ci			    AC97_MIC, 6, stac9766_boost1); /* 0/10dB */
10562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum,
10662306a36Sopenharmony_ci			    AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */
10762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum,
10862306a36Sopenharmony_ci			    AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0);
11162306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv,     0, 150, 0);
11262306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv,   -4500, 300, 0);
11362306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv,    -3450, 150, 0);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
11662306a36Sopenharmony_ci	SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv),
11762306a36Sopenharmony_ci	SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1),
11862306a36Sopenharmony_ci	SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1,
11962306a36Sopenharmony_ci		       master_tlv),
12062306a36Sopenharmony_ci	SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1),
12162306a36Sopenharmony_ci	SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1,
12262306a36Sopenharmony_ci		       master_tlv),
12362306a36Sopenharmony_ci	SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1),
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv),
12662306a36Sopenharmony_ci	SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1),
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv),
13062306a36Sopenharmony_ci	SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1),
13162306a36Sopenharmony_ci	SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1),
13262306a36Sopenharmony_ci	SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv),
13362306a36Sopenharmony_ci	SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1),
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	SOC_ENUM("Mic Boost1", stac9766_boost1_enum),
13662306a36Sopenharmony_ci	SOC_ENUM("Mic Boost2", stac9766_boost2_enum),
13762306a36Sopenharmony_ci	SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv),
13862306a36Sopenharmony_ci	SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
13962306a36Sopenharmony_ci	SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum),
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv),
14262306a36Sopenharmony_ci	SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1),
14362306a36Sopenharmony_ci	SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv),
14462306a36Sopenharmony_ci	SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1),
14562306a36Sopenharmony_ci	SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv),
14662306a36Sopenharmony_ci	SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1),
14762306a36Sopenharmony_ci	SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv),
14862306a36Sopenharmony_ci	SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1),
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv),
15162306a36Sopenharmony_ci	SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1),
15262306a36Sopenharmony_ci	SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0),
15362306a36Sopenharmony_ci	SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1),
15462306a36Sopenharmony_ci	SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum),
15762306a36Sopenharmony_ci	SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum),
15862306a36Sopenharmony_ci	SOC_ENUM("Record All Mux", stac9766_record_all_enum),
15962306a36Sopenharmony_ci	SOC_ENUM("Record Mux", stac9766_record_enum),
16062306a36Sopenharmony_ci	SOC_ENUM("Mono Mux", stac9766_mono_enum),
16162306a36Sopenharmony_ci	SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic int ac97_analog_prepare(struct snd_pcm_substream *substream,
16562306a36Sopenharmony_ci			       struct snd_soc_dai *dai)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
16862306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
16962306a36Sopenharmony_ci	unsigned short reg;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* enable variable rate audio, disable SPDIF output */
17262306a36Sopenharmony_ci	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x5, 0x1);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
17562306a36Sopenharmony_ci		reg = AC97_PCM_FRONT_DAC_RATE;
17662306a36Sopenharmony_ci	else
17762306a36Sopenharmony_ci		reg = AC97_PCM_LR_ADC_RATE;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return snd_soc_component_write(component, reg, runtime->rate);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int ac97_digital_prepare(struct snd_pcm_substream *substream,
18362306a36Sopenharmony_ci				struct snd_soc_dai *dai)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
18662306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
18762306a36Sopenharmony_ci	unsigned short reg;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	snd_soc_component_write(component, AC97_SPDIF, 0x2002);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* Enable VRA and SPDIF out */
19262306a36Sopenharmony_ci	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x5, 0x5);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	reg = AC97_PCM_FRONT_DAC_RATE;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return snd_soc_component_write(component, reg, runtime->rate);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int stac9766_set_bias_level(struct snd_soc_component *component,
20062306a36Sopenharmony_ci				   enum snd_soc_bias_level level)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	switch (level) {
20362306a36Sopenharmony_ci	case SND_SOC_BIAS_ON: /* full On */
20462306a36Sopenharmony_ci	case SND_SOC_BIAS_PREPARE: /* partial On */
20562306a36Sopenharmony_ci	case SND_SOC_BIAS_STANDBY: /* Off, with power */
20662306a36Sopenharmony_ci		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
20762306a36Sopenharmony_ci		break;
20862306a36Sopenharmony_ci	case SND_SOC_BIAS_OFF: /* Off, without power */
20962306a36Sopenharmony_ci		/* disable everything including AC link */
21062306a36Sopenharmony_ci		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
21162306a36Sopenharmony_ci		break;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	return 0;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int stac9766_component_resume(struct snd_soc_component *component)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID,
22162306a36Sopenharmony_ci		STAC9766_VENDOR_ID_MASK);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic const struct snd_soc_dai_ops stac9766_dai_ops_analog = {
22562306a36Sopenharmony_ci	.prepare = ac97_analog_prepare,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct snd_soc_dai_ops stac9766_dai_ops_digital = {
22962306a36Sopenharmony_ci	.prepare = ac97_digital_prepare,
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic struct snd_soc_dai_driver stac9766_dai[] = {
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	.name = "stac9766-hifi-analog",
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* stream cababilities */
23762306a36Sopenharmony_ci	.playback = {
23862306a36Sopenharmony_ci		.stream_name = "stac9766 analog",
23962306a36Sopenharmony_ci		.channels_min = 1,
24062306a36Sopenharmony_ci		.channels_max = 2,
24162306a36Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000_48000,
24262306a36Sopenharmony_ci		.formats = SND_SOC_STD_AC97_FMTS,
24362306a36Sopenharmony_ci	},
24462306a36Sopenharmony_ci	.capture = {
24562306a36Sopenharmony_ci		.stream_name = "stac9766 analog",
24662306a36Sopenharmony_ci		.channels_min = 1,
24762306a36Sopenharmony_ci		.channels_max = 2,
24862306a36Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000_48000,
24962306a36Sopenharmony_ci		.formats = SND_SOC_STD_AC97_FMTS,
25062306a36Sopenharmony_ci	},
25162306a36Sopenharmony_ci	/* alsa ops */
25262306a36Sopenharmony_ci	.ops = &stac9766_dai_ops_analog,
25362306a36Sopenharmony_ci},
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	.name = "stac9766-hifi-IEC958",
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* stream cababilities */
25862306a36Sopenharmony_ci	.playback = {
25962306a36Sopenharmony_ci		.stream_name = "stac9766 IEC958",
26062306a36Sopenharmony_ci		.channels_min = 1,
26162306a36Sopenharmony_ci		.channels_max = 2,
26262306a36Sopenharmony_ci		.rates = SNDRV_PCM_RATE_32000 | \
26362306a36Sopenharmony_ci			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
26462306a36Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
26562306a36Sopenharmony_ci	},
26662306a36Sopenharmony_ci	/* alsa ops */
26762306a36Sopenharmony_ci	.ops = &stac9766_dai_ops_digital,
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int stac9766_component_probe(struct snd_soc_component *component)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct snd_ac97 *ac97;
27462306a36Sopenharmony_ci	struct regmap *regmap;
27562306a36Sopenharmony_ci	int ret;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ac97 = snd_soc_new_ac97_component(component, STAC9766_VENDOR_ID,
27862306a36Sopenharmony_ci			STAC9766_VENDOR_ID_MASK);
27962306a36Sopenharmony_ci	if (IS_ERR(ac97))
28062306a36Sopenharmony_ci		return PTR_ERR(ac97);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	regmap = regmap_init_ac97(ac97, &stac9766_regmap_config);
28362306a36Sopenharmony_ci	if (IS_ERR(regmap)) {
28462306a36Sopenharmony_ci		ret = PTR_ERR(regmap);
28562306a36Sopenharmony_ci		goto err_free_ac97;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	snd_soc_component_init_regmap(component, regmap);
28962306a36Sopenharmony_ci	snd_soc_component_set_drvdata(component, ac97);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_cierr_free_ac97:
29362306a36Sopenharmony_ci	snd_soc_free_ac97_component(ac97);
29462306a36Sopenharmony_ci	return ret;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void stac9766_component_remove(struct snd_soc_component *component)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	snd_soc_component_exit_regmap(component);
30262306a36Sopenharmony_ci	snd_soc_free_ac97_component(ac97);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_stac9766 = {
30662306a36Sopenharmony_ci	.controls		= stac9766_snd_ac97_controls,
30762306a36Sopenharmony_ci	.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),
30862306a36Sopenharmony_ci	.set_bias_level		= stac9766_set_bias_level,
30962306a36Sopenharmony_ci	.probe			= stac9766_component_probe,
31062306a36Sopenharmony_ci	.remove			= stac9766_component_remove,
31162306a36Sopenharmony_ci	.resume			= stac9766_component_resume,
31262306a36Sopenharmony_ci	.suspend_bias_off	= 1,
31362306a36Sopenharmony_ci	.idle_bias_on		= 1,
31462306a36Sopenharmony_ci	.use_pmdown_time	= 1,
31562306a36Sopenharmony_ci	.endianness		= 1,
31662306a36Sopenharmony_ci};
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int stac9766_probe(struct platform_device *pdev)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	return devm_snd_soc_register_component(&pdev->dev,
32162306a36Sopenharmony_ci			&soc_component_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic struct platform_driver stac9766_codec_driver = {
32562306a36Sopenharmony_ci	.driver = {
32662306a36Sopenharmony_ci			.name = "stac9766-codec",
32762306a36Sopenharmony_ci	},
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	.probe = stac9766_probe,
33062306a36Sopenharmony_ci};
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cimodule_platform_driver(stac9766_codec_driver);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC stac9766 driver");
33562306a36Sopenharmony_ciMODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
33662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
337