ad1980.c (8896B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * ad1980.c -- ALSA Soc AD1980 codec support 4 * 5 * Copyright: Analog Devices Inc. 6 * Author: Roy Huang <roy.huang@analog.com> 7 * Cliff Cai <cliff.cai@analog.com> 8 */ 9 10/* 11 * WARNING: 12 * 13 * Because Analog Devices Inc. discontinued the ad1980 sound chip since 14 * Sep. 2009, this ad1980 driver is not maintained, tested and supported 15 * by ADI now. 16 */ 17 18#include <linux/init.h> 19#include <linux/slab.h> 20#include <linux/module.h> 21#include <linux/kernel.h> 22#include <linux/device.h> 23#include <linux/regmap.h> 24#include <sound/core.h> 25#include <sound/pcm.h> 26#include <sound/ac97_codec.h> 27#include <sound/initval.h> 28#include <sound/soc.h> 29 30static const struct reg_default ad1980_reg_defaults[] = { 31 { 0x02, 0x8000 }, 32 { 0x04, 0x8000 }, 33 { 0x06, 0x8000 }, 34 { 0x0c, 0x8008 }, 35 { 0x0e, 0x8008 }, 36 { 0x10, 0x8808 }, 37 { 0x12, 0x8808 }, 38 { 0x16, 0x8808 }, 39 { 0x18, 0x8808 }, 40 { 0x1a, 0x0000 }, 41 { 0x1c, 0x8000 }, 42 { 0x20, 0x0000 }, 43 { 0x28, 0x03c7 }, 44 { 0x2c, 0xbb80 }, 45 { 0x2e, 0xbb80 }, 46 { 0x30, 0xbb80 }, 47 { 0x32, 0xbb80 }, 48 { 0x36, 0x8080 }, 49 { 0x38, 0x8080 }, 50 { 0x3a, 0x2000 }, 51 { 0x60, 0x0000 }, 52 { 0x62, 0x0000 }, 53 { 0x72, 0x0000 }, 54 { 0x74, 0x1001 }, 55 { 0x76, 0x0000 }, 56}; 57 58static bool ad1980_readable_reg(struct device *dev, unsigned int reg) 59{ 60 switch (reg) { 61 case AC97_RESET ... AC97_MASTER_MONO: 62 case AC97_PHONE ... AC97_CD: 63 case AC97_AUX ... AC97_GENERAL_PURPOSE: 64 case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE: 65 case AC97_SPDIF: 66 case AC97_CODEC_CLASS_REV: 67 case AC97_PCI_SVID: 68 case AC97_AD_CODEC_CFG: 69 case AC97_AD_JACK_SPDIF: 70 case AC97_AD_SERIAL_CFG: 71 case AC97_VENDOR_ID1: 72 case AC97_VENDOR_ID2: 73 return true; 74 default: 75 return false; 76 } 77} 78 79static bool ad1980_writeable_reg(struct device *dev, unsigned int reg) 80{ 81 switch (reg) { 82 case AC97_VENDOR_ID1: 83 case AC97_VENDOR_ID2: 84 return false; 85 default: 86 return ad1980_readable_reg(dev, reg); 87 } 88} 89 90static const struct regmap_config ad1980_regmap_config = { 91 .reg_bits = 16, 92 .reg_stride = 2, 93 .val_bits = 16, 94 .max_register = 0x7e, 95 .cache_type = REGCACHE_RBTREE, 96 97 .volatile_reg = regmap_ac97_default_volatile, 98 .readable_reg = ad1980_readable_reg, 99 .writeable_reg = ad1980_writeable_reg, 100 101 .reg_defaults = ad1980_reg_defaults, 102 .num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults), 103}; 104 105static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", 106 "Stereo Mix", "Mono Mix", "Phone"}; 107 108static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src, 109 AC97_REC_SEL, 8, 0, ad1980_rec_sel); 110 111static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { 112SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), 113SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1), 114 115SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), 116SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1), 117 118SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1), 119SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1), 120 121SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0), 122SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1), 123 124SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), 125SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), 126 127SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1), 128SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1), 129 130SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1), 131SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), 132 133SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0), 134SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), 135 136SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), 137SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), 138 139SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1), 140SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1), 141 142SOC_ENUM("Capture Source", ad1980_cap_src), 143 144SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), 145}; 146 147static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = { 148SND_SOC_DAPM_INPUT("MIC1"), 149SND_SOC_DAPM_INPUT("MIC2"), 150SND_SOC_DAPM_INPUT("CD_L"), 151SND_SOC_DAPM_INPUT("CD_R"), 152SND_SOC_DAPM_INPUT("AUX_L"), 153SND_SOC_DAPM_INPUT("AUX_R"), 154SND_SOC_DAPM_INPUT("LINE_IN_L"), 155SND_SOC_DAPM_INPUT("LINE_IN_R"), 156 157SND_SOC_DAPM_OUTPUT("LFE_OUT"), 158SND_SOC_DAPM_OUTPUT("CENTER_OUT"), 159SND_SOC_DAPM_OUTPUT("LINE_OUT_L"), 160SND_SOC_DAPM_OUTPUT("LINE_OUT_R"), 161SND_SOC_DAPM_OUTPUT("MONO_OUT"), 162SND_SOC_DAPM_OUTPUT("HP_OUT_L"), 163SND_SOC_DAPM_OUTPUT("HP_OUT_R"), 164}; 165 166static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { 167 { "Capture", NULL, "MIC1" }, 168 { "Capture", NULL, "MIC2" }, 169 { "Capture", NULL, "CD_L" }, 170 { "Capture", NULL, "CD_R" }, 171 { "Capture", NULL, "AUX_L" }, 172 { "Capture", NULL, "AUX_R" }, 173 { "Capture", NULL, "LINE_IN_L" }, 174 { "Capture", NULL, "LINE_IN_R" }, 175 176 { "LFE_OUT", NULL, "Playback" }, 177 { "CENTER_OUT", NULL, "Playback" }, 178 { "LINE_OUT_L", NULL, "Playback" }, 179 { "LINE_OUT_R", NULL, "Playback" }, 180 { "MONO_OUT", NULL, "Playback" }, 181 { "HP_OUT_L", NULL, "Playback" }, 182 { "HP_OUT_R", NULL, "Playback" }, 183}; 184 185static struct snd_soc_dai_driver ad1980_dai = { 186 .name = "ad1980-hifi", 187 .playback = { 188 .stream_name = "Playback", 189 .channels_min = 2, 190 .channels_max = 6, 191 .rates = SNDRV_PCM_RATE_48000, 192 .formats = SND_SOC_STD_AC97_FMTS, }, 193 .capture = { 194 .stream_name = "Capture", 195 .channels_min = 2, 196 .channels_max = 2, 197 .rates = SNDRV_PCM_RATE_48000, 198 .formats = SND_SOC_STD_AC97_FMTS, }, 199}; 200 201#define AD1980_VENDOR_ID 0x41445300 202#define AD1980_VENDOR_MASK 0xffffff00 203 204static int ad1980_reset(struct snd_soc_component *component, int try_warm) 205{ 206 struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component); 207 unsigned int retry_cnt = 0; 208 int ret; 209 210 do { 211 ret = snd_ac97_reset(ac97, true, AD1980_VENDOR_ID, 212 AD1980_VENDOR_MASK); 213 if (ret >= 0) 214 return 0; 215 216 /* 217 * Set bit 16slot in register 74h, then every slot will has only 218 * 16 bits. This command is sent out in 20bit mode, in which 219 * case the first nibble of data is eaten by the addr. (Tag is 220 * always 16 bit) 221 */ 222 snd_soc_component_write(component, AC97_AD_SERIAL_CFG, 0x9900); 223 224 } while (retry_cnt++ < 10); 225 226 dev_err(component->dev, "Failed to reset: AC97 link error\n"); 227 228 return -EIO; 229} 230 231static int ad1980_soc_probe(struct snd_soc_component *component) 232{ 233 struct snd_ac97 *ac97; 234 struct regmap *regmap; 235 int ret; 236 u16 vendor_id2; 237 u16 ext_status; 238 239 ac97 = snd_soc_new_ac97_component(component, 0, 0); 240 if (IS_ERR(ac97)) { 241 ret = PTR_ERR(ac97); 242 dev_err(component->dev, "Failed to register AC97 component: %d\n", ret); 243 return ret; 244 } 245 246 regmap = regmap_init_ac97(ac97, &ad1980_regmap_config); 247 if (IS_ERR(regmap)) { 248 ret = PTR_ERR(regmap); 249 goto err_free_ac97; 250 } 251 252 snd_soc_component_init_regmap(component, regmap); 253 snd_soc_component_set_drvdata(component, ac97); 254 255 ret = ad1980_reset(component, 0); 256 if (ret < 0) 257 goto reset_err; 258 259 vendor_id2 = snd_soc_component_read(component, AC97_VENDOR_ID2); 260 if (vendor_id2 == 0x5374) { 261 dev_warn(component->dev, 262 "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); 263 } 264 265 /* unmute captures and playbacks volume */ 266 snd_soc_component_write(component, AC97_MASTER, 0x0000); 267 snd_soc_component_write(component, AC97_PCM, 0x0000); 268 snd_soc_component_write(component, AC97_REC_GAIN, 0x0000); 269 snd_soc_component_write(component, AC97_CENTER_LFE_MASTER, 0x0000); 270 snd_soc_component_write(component, AC97_SURROUND_MASTER, 0x0000); 271 272 /*power on LFE/CENTER/Surround DACs*/ 273 ext_status = snd_soc_component_read(component, AC97_EXTENDED_STATUS); 274 snd_soc_component_write(component, AC97_EXTENDED_STATUS, ext_status&~0x3800); 275 276 return 0; 277 278reset_err: 279 snd_soc_component_exit_regmap(component); 280err_free_ac97: 281 snd_soc_free_ac97_component(ac97); 282 return ret; 283} 284 285static void ad1980_soc_remove(struct snd_soc_component *component) 286{ 287 struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component); 288 289 snd_soc_component_exit_regmap(component); 290 snd_soc_free_ac97_component(ac97); 291} 292 293static const struct snd_soc_component_driver soc_component_dev_ad1980 = { 294 .probe = ad1980_soc_probe, 295 .remove = ad1980_soc_remove, 296 .controls = ad1980_snd_ac97_controls, 297 .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), 298 .dapm_widgets = ad1980_dapm_widgets, 299 .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), 300 .dapm_routes = ad1980_dapm_routes, 301 .num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes), 302 .idle_bias_on = 1, 303 .use_pmdown_time = 1, 304 .endianness = 1, 305 .non_legacy_dai_naming = 1, 306}; 307 308static int ad1980_probe(struct platform_device *pdev) 309{ 310 return devm_snd_soc_register_component(&pdev->dev, 311 &soc_component_dev_ad1980, &ad1980_dai, 1); 312} 313 314static struct platform_driver ad1980_codec_driver = { 315 .driver = { 316 .name = "ad1980", 317 }, 318 319 .probe = ad1980_probe, 320}; 321 322module_platform_driver(ad1980_codec_driver); 323 324MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)"); 325MODULE_AUTHOR("Roy Huang, Cliff Cai"); 326MODULE_LICENSE("GPL");