Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: hda/cmedia: Rewrite to new probe method

Convert the C-Media codec driver to use the new hda_codec_ops probe.

Since the CM9825 uses a completely different probe and codec ops,
factor out to an individual codec driver, snd-hda-codec-cm9825.

Other than that, no functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250709160434.1859-13-tiwai@suse.de

+365 -331
+10
sound/hda/codecs/Kconfig
··· 99 99 comment "Set to Y if you want auto-loading the codec driver" 100 100 depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m 101 101 102 + config SND_HDA_CODEC_CM9825 103 + tristate "Build C-Media CM9825 HD-audio codec support" 104 + select SND_HDA_GENERIC 105 + help 106 + Say Y or M here to include C-Media CM9825 HD-audio codec support in 107 + snd-hda-intel driver 108 + 109 + comment "Set to Y if you want auto-loading the codec driver" 110 + depends on SND_HDA=y && SND_HDA_CODEC_CM9825=m 111 + 102 112 config SND_HDA_CODEC_SI3054 103 113 tristate "Build Silicon Labs 3054 HD-modem codec support" 104 114 help
+2
sound/hda/codecs/Makefile
··· 3 3 4 4 snd-hda-codec-generic-y := generic.o 5 5 snd-hda-codec-cmedia-y := cmedia.o 6 + snd-hda-codec-cm9825-y := cm9825.o 6 7 snd-hda-codec-analog-y := analog.o 7 8 snd-hda-codec-ca0110-y := ca0110.o 8 9 snd-hda-codec-ca0132-y := ca0132.o ··· 22 21 # codec drivers 23 22 obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o 24 23 obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o 24 + obj-$(CONFIG_SND_HDA_CODEC_CM9825) += snd-hda-codec-cm9825.o 25 25 obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o 26 26 obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o 27 27 obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
+312
sound/hda/codecs/cm9825.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * CM9825 HD-audio codec 4 + */ 5 + 6 + #include <linux/init.h> 7 + #include <linux/slab.h> 8 + #include <linux/module.h> 9 + #include <sound/core.h> 10 + #include <sound/hda_codec.h> 11 + #include "hda_local.h" 12 + #include "hda_auto_parser.h" 13 + #include "hda_jack.h" 14 + #include "generic.h" 15 + 16 + /* CM9825 Offset Definitions */ 17 + 18 + #define CM9825_VERB_SET_HPF_1 0x781 19 + #define CM9825_VERB_SET_HPF_2 0x785 20 + #define CM9825_VERB_SET_PLL 0x7a0 21 + #define CM9825_VERB_SET_NEG 0x7a1 22 + #define CM9825_VERB_SET_ADCL 0x7a2 23 + #define CM9825_VERB_SET_DACL 0x7a3 24 + #define CM9825_VERB_SET_MBIAS 0x7a4 25 + #define CM9825_VERB_SET_VNEG 0x7a8 26 + #define CM9825_VERB_SET_D2S 0x7a9 27 + #define CM9825_VERB_SET_DACTRL 0x7aa 28 + #define CM9825_VERB_SET_PDNEG 0x7ac 29 + #define CM9825_VERB_SET_VDO 0x7ad 30 + #define CM9825_VERB_SET_CDALR 0x7b0 31 + #define CM9825_VERB_SET_MTCBA 0x7b1 32 + #define CM9825_VERB_SET_OTP 0x7b2 33 + #define CM9825_VERB_SET_OCP 0x7b3 34 + #define CM9825_VERB_SET_GAD 0x7b4 35 + #define CM9825_VERB_SET_TMOD 0x7b5 36 + #define CM9825_VERB_SET_SNR 0x7b6 37 + 38 + struct cmi_spec { 39 + struct hda_gen_spec gen; 40 + const struct hda_verb *chip_d0_verbs; 41 + const struct hda_verb *chip_d3_verbs; 42 + const struct hda_verb *chip_hp_present_verbs; 43 + const struct hda_verb *chip_hp_remove_verbs; 44 + struct hda_codec *codec; 45 + struct delayed_work unsol_hp_work; 46 + int quirk; 47 + }; 48 + 49 + static const struct hda_verb cm9825_std_d3_verbs[] = { 50 + /* chip sleep verbs */ 51 + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ 52 + {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */ 53 + {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */ 54 + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ 55 + {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ 56 + {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */ 57 + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ 58 + {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */ 59 + {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */ 60 + {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ 61 + {} 62 + }; 63 + 64 + static const struct hda_verb cm9825_std_d0_verbs[] = { 65 + /* chip init verbs */ 66 + {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */ 67 + {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */ 68 + {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */ 69 + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ 70 + {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ 71 + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ 72 + {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */ 73 + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ 74 + {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ 75 + {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */ 76 + {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ 77 + {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */ 78 + {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ 79 + {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */ 80 + {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */ 81 + {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */ 82 + {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */ 83 + {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | 84 + AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */ 85 + {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | 86 + AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */ 87 + {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */ 88 + {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */ 89 + {} 90 + }; 91 + 92 + static const struct hda_verb cm9825_hp_present_verbs[] = { 93 + {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */ 94 + {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */ 95 + {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */ 96 + {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */ 97 + {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */ 98 + {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ 99 + {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */ 100 + {} 101 + }; 102 + 103 + static const struct hda_verb cm9825_hp_remove_verbs[] = { 104 + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ 105 + {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */ 106 + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ 107 + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ 108 + {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */ 109 + {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ 110 + {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */ 111 + {} 112 + }; 113 + 114 + static void cm9825_unsol_hp_delayed(struct work_struct *work) 115 + { 116 + struct cmi_spec *spec = 117 + container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work); 118 + struct hda_jack_tbl *jack; 119 + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; 120 + bool hp_jack_plugin = false; 121 + int err = 0; 122 + 123 + hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); 124 + 125 + codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", 126 + (int)hp_jack_plugin, hp_pin); 127 + 128 + if (!hp_jack_plugin) { 129 + err = 130 + snd_hda_codec_write(spec->codec, 0x42, 0, 131 + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); 132 + if (err) 133 + codec_dbg(spec->codec, "codec_write err %d\n", err); 134 + 135 + snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs); 136 + } else { 137 + snd_hda_sequence_write(spec->codec, 138 + spec->chip_hp_present_verbs); 139 + } 140 + 141 + jack = snd_hda_jack_tbl_get(spec->codec, hp_pin); 142 + if (jack) { 143 + jack->block_report = 0; 144 + snd_hda_jack_report_sync(spec->codec); 145 + } 146 + } 147 + 148 + static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) 149 + { 150 + struct cmi_spec *spec = codec->spec; 151 + struct hda_jack_tbl *tbl; 152 + 153 + /* Delay enabling the HP amp, to let the mic-detection 154 + * state machine run. 155 + */ 156 + 157 + codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid); 158 + 159 + tbl = snd_hda_jack_tbl_get(codec, cb->nid); 160 + if (tbl) 161 + tbl->block_report = 1; 162 + schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200)); 163 + } 164 + 165 + static void cm9825_setup_unsol(struct hda_codec *codec) 166 + { 167 + struct cmi_spec *spec = codec->spec; 168 + 169 + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; 170 + 171 + snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback); 172 + } 173 + 174 + static int cm9825_init(struct hda_codec *codec) 175 + { 176 + snd_hda_gen_init(codec); 177 + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); 178 + 179 + return 0; 180 + } 181 + 182 + static void cm9825_remove(struct hda_codec *codec) 183 + { 184 + struct cmi_spec *spec = codec->spec; 185 + 186 + cancel_delayed_work_sync(&spec->unsol_hp_work); 187 + snd_hda_gen_remove(codec); 188 + } 189 + 190 + static int cm9825_suspend(struct hda_codec *codec) 191 + { 192 + struct cmi_spec *spec = codec->spec; 193 + 194 + cancel_delayed_work_sync(&spec->unsol_hp_work); 195 + 196 + snd_hda_sequence_write(codec, spec->chip_d3_verbs); 197 + 198 + return 0; 199 + } 200 + 201 + static int cm9825_resume(struct hda_codec *codec) 202 + { 203 + struct cmi_spec *spec = codec->spec; 204 + hda_nid_t hp_pin = 0; 205 + bool hp_jack_plugin = false; 206 + int err; 207 + 208 + err = 209 + snd_hda_codec_write(spec->codec, 0x42, 0, 210 + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00); 211 + if (err) 212 + codec_dbg(codec, "codec_write err %d\n", err); 213 + 214 + msleep(150); /* for depop noise */ 215 + 216 + snd_hda_codec_init(codec); 217 + 218 + hp_pin = spec->gen.autocfg.hp_pins[0]; 219 + hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); 220 + 221 + codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", 222 + (int)hp_jack_plugin, hp_pin); 223 + 224 + if (!hp_jack_plugin) { 225 + err = 226 + snd_hda_codec_write(spec->codec, 0x42, 0, 227 + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); 228 + 229 + if (err) 230 + codec_dbg(codec, "codec_write err %d\n", err); 231 + 232 + snd_hda_sequence_write(codec, cm9825_hp_remove_verbs); 233 + } 234 + 235 + snd_hda_regmap_sync(codec); 236 + hda_call_check_power_status(codec, 0x01); 237 + 238 + return 0; 239 + } 240 + 241 + static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id) 242 + { 243 + struct cmi_spec *spec; 244 + struct auto_pin_cfg *cfg; 245 + int err; 246 + 247 + spec = kzalloc(sizeof(*spec), GFP_KERNEL); 248 + if (spec == NULL) 249 + return -ENOMEM; 250 + 251 + INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed); 252 + codec->spec = spec; 253 + spec->codec = codec; 254 + cfg = &spec->gen.autocfg; 255 + snd_hda_gen_spec_init(&spec->gen); 256 + spec->chip_d0_verbs = cm9825_std_d0_verbs; 257 + spec->chip_d3_verbs = cm9825_std_d3_verbs; 258 + spec->chip_hp_present_verbs = cm9825_hp_present_verbs; 259 + spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs; 260 + 261 + snd_hda_sequence_write(codec, spec->chip_d0_verbs); 262 + 263 + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); 264 + if (err < 0) 265 + goto error; 266 + err = snd_hda_gen_parse_auto_config(codec, cfg); 267 + if (err < 0) 268 + goto error; 269 + 270 + cm9825_setup_unsol(codec); 271 + 272 + return 0; 273 + 274 + error: 275 + cm9825_remove(codec); 276 + 277 + codec_info(codec, "Enter err %d\n", err); 278 + 279 + return err; 280 + } 281 + 282 + static const struct hda_codec_ops cm9825_codec_ops = { 283 + .probe = cm9825_probe, 284 + .remove = cm9825_remove, 285 + .build_controls = snd_hda_gen_build_controls, 286 + .build_pcms = snd_hda_gen_build_pcms, 287 + .init = cm9825_init, 288 + .unsol_event = snd_hda_jack_unsol_event, 289 + .suspend = cm9825_suspend, 290 + .resume = cm9825_resume, 291 + .check_power_status = snd_hda_gen_check_power_status, 292 + .stream_pm = snd_hda_gen_stream_pm, 293 + }; 294 + 295 + /* 296 + * driver entries 297 + */ 298 + static const struct hda_device_id snd_hda_id_cm9825[] = { 299 + HDA_CODEC_ID(0x13f69825, "CM9825"), 300 + {} /* terminator */ 301 + }; 302 + MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825); 303 + 304 + MODULE_LICENSE("GPL"); 305 + MODULE_DESCRIPTION("CM9825 HD-audio codec"); 306 + 307 + static struct hda_codec_driver cm9825_driver = { 308 + .id = snd_hda_id_cm9825, 309 + .ops = &cm9825_codec_ops, 310 + }; 311 + 312 + module_hda_codec_driver(cm9825_driver);
+41 -331
sound/hda/codecs/cmedia.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * Universal Interface for Intel High Definition Audio Codec 3 + * Universal codec driver for Intel High Definition Audio Codec 4 4 * 5 - * HD audio interface patch for C-Media CMI9880 5 + * HD audio codec driver for C-Media CMI9880 6 6 * 7 7 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 8 8 */ ··· 17 17 #include "hda_jack.h" 18 18 #include "generic.h" 19 19 20 - /* CM9825 Offset Definitions */ 21 - 22 - #define CM9825_VERB_SET_HPF_1 0x781 23 - #define CM9825_VERB_SET_HPF_2 0x785 24 - #define CM9825_VERB_SET_PLL 0x7a0 25 - #define CM9825_VERB_SET_NEG 0x7a1 26 - #define CM9825_VERB_SET_ADCL 0x7a2 27 - #define CM9825_VERB_SET_DACL 0x7a3 28 - #define CM9825_VERB_SET_MBIAS 0x7a4 29 - #define CM9825_VERB_SET_VNEG 0x7a8 30 - #define CM9825_VERB_SET_D2S 0x7a9 31 - #define CM9825_VERB_SET_DACTRL 0x7aa 32 - #define CM9825_VERB_SET_PDNEG 0x7ac 33 - #define CM9825_VERB_SET_VDO 0x7ad 34 - #define CM9825_VERB_SET_CDALR 0x7b0 35 - #define CM9825_VERB_SET_MTCBA 0x7b1 36 - #define CM9825_VERB_SET_OTP 0x7b2 37 - #define CM9825_VERB_SET_OCP 0x7b3 38 - #define CM9825_VERB_SET_GAD 0x7b4 39 - #define CM9825_VERB_SET_TMOD 0x7b5 40 - #define CM9825_VERB_SET_SNR 0x7b6 41 - 42 - struct cmi_spec { 43 - struct hda_gen_spec gen; 44 - const struct hda_verb *chip_d0_verbs; 45 - const struct hda_verb *chip_d3_verbs; 46 - const struct hda_verb *chip_hp_present_verbs; 47 - const struct hda_verb *chip_hp_remove_verbs; 48 - struct hda_codec *codec; 49 - struct delayed_work unsol_hp_work; 50 - int quirk; 51 - }; 52 - 53 - static const struct hda_verb cm9825_std_d3_verbs[] = { 54 - /* chip sleep verbs */ 55 - {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ 56 - {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */ 57 - {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */ 58 - {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ 59 - {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ 60 - {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */ 61 - {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ 62 - {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */ 63 - {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */ 64 - {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ 65 - {} 66 - }; 67 - 68 - static const struct hda_verb cm9825_std_d0_verbs[] = { 69 - /* chip init verbs */ 70 - {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */ 71 - {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */ 72 - {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */ 73 - {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ 74 - {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ 75 - {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ 76 - {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */ 77 - {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ 78 - {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ 79 - {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */ 80 - {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ 81 - {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */ 82 - {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ 83 - {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */ 84 - {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */ 85 - {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */ 86 - {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */ 87 - {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | 88 - AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */ 89 - {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | 90 - AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */ 91 - {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */ 92 - {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */ 93 - {} 94 - }; 95 - 96 - static const struct hda_verb cm9825_hp_present_verbs[] = { 97 - {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */ 98 - {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */ 99 - {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */ 100 - {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */ 101 - {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */ 102 - {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ 103 - {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */ 104 - {} 105 - }; 106 - 107 - static const struct hda_verb cm9825_hp_remove_verbs[] = { 108 - {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ 109 - {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */ 110 - {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ 111 - {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ 112 - {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */ 113 - {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ 114 - {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */ 115 - {} 116 - }; 117 - 118 - static void cm9825_unsol_hp_delayed(struct work_struct *work) 20 + static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id) 119 21 { 120 - struct cmi_spec *spec = 121 - container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work); 122 - struct hda_jack_tbl *jack; 123 - hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; 124 - bool hp_jack_plugin = false; 125 - int err = 0; 126 - 127 - hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); 128 - 129 - codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", 130 - (int)hp_jack_plugin, hp_pin); 131 - 132 - if (!hp_jack_plugin) { 133 - err = 134 - snd_hda_codec_write(spec->codec, 0x42, 0, 135 - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); 136 - if (err) 137 - codec_dbg(spec->codec, "codec_write err %d\n", err); 138 - 139 - snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs); 140 - } else { 141 - snd_hda_sequence_write(spec->codec, 142 - spec->chip_hp_present_verbs); 143 - } 144 - 145 - jack = snd_hda_jack_tbl_get(spec->codec, hp_pin); 146 - if (jack) { 147 - jack->block_report = 0; 148 - snd_hda_jack_report_sync(spec->codec); 149 - } 150 - } 151 - 152 - static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) 153 - { 154 - struct cmi_spec *spec = codec->spec; 155 - struct hda_jack_tbl *tbl; 156 - 157 - /* Delay enabling the HP amp, to let the mic-detection 158 - * state machine run. 159 - */ 160 - 161 - codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid); 162 - 163 - tbl = snd_hda_jack_tbl_get(codec, cb->nid); 164 - if (tbl) 165 - tbl->block_report = 1; 166 - schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200)); 167 - } 168 - 169 - static void cm9825_setup_unsol(struct hda_codec *codec) 170 - { 171 - struct cmi_spec *spec = codec->spec; 172 - 173 - hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; 174 - 175 - snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback); 176 - } 177 - 178 - static int cm9825_init(struct hda_codec *codec) 179 - { 180 - snd_hda_gen_init(codec); 181 - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); 182 - 183 - return 0; 184 - } 185 - 186 - static void cm9825_free(struct hda_codec *codec) 187 - { 188 - struct cmi_spec *spec = codec->spec; 189 - 190 - cancel_delayed_work_sync(&spec->unsol_hp_work); 191 - snd_hda_gen_free(codec); 192 - } 193 - 194 - static int cm9825_suspend(struct hda_codec *codec) 195 - { 196 - struct cmi_spec *spec = codec->spec; 197 - 198 - cancel_delayed_work_sync(&spec->unsol_hp_work); 199 - 200 - snd_hda_sequence_write(codec, spec->chip_d3_verbs); 201 - 202 - return 0; 203 - } 204 - 205 - static int cm9825_resume(struct hda_codec *codec) 206 - { 207 - struct cmi_spec *spec = codec->spec; 208 - hda_nid_t hp_pin = 0; 209 - bool hp_jack_plugin = false; 210 - int err; 211 - 212 - err = 213 - snd_hda_codec_write(spec->codec, 0x42, 0, 214 - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00); 215 - if (err) 216 - codec_dbg(codec, "codec_write err %d\n", err); 217 - 218 - msleep(150); /* for depop noise */ 219 - 220 - codec->patch_ops.init(codec); 221 - 222 - hp_pin = spec->gen.autocfg.hp_pins[0]; 223 - hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); 224 - 225 - codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", 226 - (int)hp_jack_plugin, hp_pin); 227 - 228 - if (!hp_jack_plugin) { 229 - err = 230 - snd_hda_codec_write(spec->codec, 0x42, 0, 231 - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); 232 - 233 - if (err) 234 - codec_dbg(codec, "codec_write err %d\n", err); 235 - 236 - snd_hda_sequence_write(codec, cm9825_hp_remove_verbs); 237 - } 238 - 239 - snd_hda_regmap_sync(codec); 240 - hda_call_check_power_status(codec, 0x01); 241 - 242 - return 0; 243 - } 244 - 245 - /* 246 - * stuff for auto-parser 247 - */ 248 - static const struct hda_codec_ops cmi_auto_patch_ops = { 249 - .build_controls = snd_hda_gen_build_controls, 250 - .build_pcms = snd_hda_gen_build_pcms, 251 - .init = snd_hda_gen_init, 252 - .free = snd_hda_gen_free, 253 - .unsol_event = snd_hda_jack_unsol_event, 254 - }; 255 - 256 - static int patch_cm9825(struct hda_codec *codec) 257 - { 258 - struct cmi_spec *spec; 22 + struct hda_gen_spec *spec; 259 23 struct auto_pin_cfg *cfg; 260 - int err; 261 - 262 - spec = kzalloc(sizeof(*spec), GFP_KERNEL); 263 - if (spec == NULL) 264 - return -ENOMEM; 265 - 266 - INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed); 267 - codec->spec = spec; 268 - spec->codec = codec; 269 - codec->patch_ops = cmi_auto_patch_ops; 270 - codec->patch_ops.init = cm9825_init; 271 - codec->patch_ops.suspend = cm9825_suspend; 272 - codec->patch_ops.resume = cm9825_resume; 273 - codec->patch_ops.free = cm9825_free; 274 - codec->patch_ops.check_power_status = snd_hda_gen_check_power_status; 275 - cfg = &spec->gen.autocfg; 276 - snd_hda_gen_spec_init(&spec->gen); 277 - spec->chip_d0_verbs = cm9825_std_d0_verbs; 278 - spec->chip_d3_verbs = cm9825_std_d3_verbs; 279 - spec->chip_hp_present_verbs = cm9825_hp_present_verbs; 280 - spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs; 281 - 282 - snd_hda_sequence_write(codec, spec->chip_d0_verbs); 283 - 284 - err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); 285 - if (err < 0) 286 - goto error; 287 - err = snd_hda_gen_parse_auto_config(codec, cfg); 288 - if (err < 0) 289 - goto error; 290 - 291 - cm9825_setup_unsol(codec); 292 - 293 - return 0; 294 - 295 - error: 296 - cm9825_free(codec); 297 - 298 - codec_info(codec, "Enter err %d\n", err); 299 - 300 - return err; 301 - } 302 - 303 - static int patch_cmi9880(struct hda_codec *codec) 304 - { 305 - struct cmi_spec *spec; 306 - struct auto_pin_cfg *cfg; 24 + bool is_cmi8888 = id->vendor_id == 0x13f68888; 307 25 int err; 308 26 309 27 spec = kzalloc(sizeof(*spec), GFP_KERNEL); ··· 29 311 return -ENOMEM; 30 312 31 313 codec->spec = spec; 32 - codec->patch_ops = cmi_auto_patch_ops; 33 - cfg = &spec->gen.autocfg; 34 - snd_hda_gen_spec_init(&spec->gen); 314 + cfg = &spec->autocfg; 315 + snd_hda_gen_spec_init(spec); 316 + 317 + if (is_cmi8888) { 318 + /* mask NID 0x10 from the playback volume selection; 319 + * it's a headphone boost volume handled manually below 320 + */ 321 + spec->out_vol_mask = (1ULL << 0x10); 322 + } 35 323 36 324 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); 37 325 if (err < 0) ··· 46 322 if (err < 0) 47 323 goto error; 48 324 49 - return 0; 50 - 51 - error: 52 - snd_hda_gen_free(codec); 53 - return err; 54 - } 55 - 56 - static int patch_cmi8888(struct hda_codec *codec) 57 - { 58 - struct cmi_spec *spec; 59 - struct auto_pin_cfg *cfg; 60 - int err; 61 - 62 - spec = kzalloc(sizeof(*spec), GFP_KERNEL); 63 - if (!spec) 64 - return -ENOMEM; 65 - 66 - codec->spec = spec; 67 - codec->patch_ops = cmi_auto_patch_ops; 68 - cfg = &spec->gen.autocfg; 69 - snd_hda_gen_spec_init(&spec->gen); 70 - 71 - /* mask NID 0x10 from the playback volume selection; 72 - * it's a headphone boost volume handled manually below 73 - */ 74 - spec->gen.out_vol_mask = (1ULL << 0x10); 75 - 76 325 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); 77 326 if (err < 0) 78 327 goto error; ··· 53 356 if (err < 0) 54 357 goto error; 55 358 56 - if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) == 57 - AC_JACK_HP_OUT) { 58 - static const struct snd_kcontrol_new amp_kctl = 59 - HDA_CODEC_VOLUME("Headphone Amp Playback Volume", 60 - 0x10, 0, HDA_OUTPUT); 61 - if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) { 62 - err = -ENOMEM; 63 - goto error; 359 + if (is_cmi8888) { 360 + if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) == 361 + AC_JACK_HP_OUT) { 362 + static const struct snd_kcontrol_new amp_kctl = 363 + HDA_CODEC_VOLUME("Headphone Amp Playback Volume", 364 + 0x10, 0, HDA_OUTPUT); 365 + if (!snd_hda_gen_add_kctl(spec, NULL, &amp_kctl)) { 366 + err = -ENOMEM; 367 + goto error; 368 + } 64 369 } 65 370 } 66 371 67 372 return 0; 68 373 69 374 error: 70 - snd_hda_gen_free(codec); 375 + snd_hda_gen_remove(codec); 71 376 return err; 72 377 } 73 378 379 + static const struct hda_codec_ops cmedia_codec_ops = { 380 + .probe = cmedia_probe, 381 + .remove = snd_hda_gen_remove, 382 + .build_controls = snd_hda_gen_build_controls, 383 + .build_pcms = snd_hda_gen_build_pcms, 384 + .init = snd_hda_gen_init, 385 + .unsol_event = snd_hda_jack_unsol_event, 386 + .check_power_status = snd_hda_gen_check_power_status, 387 + .stream_pm = snd_hda_gen_stream_pm, 388 + }; 389 + 74 390 /* 75 - * patch entries 391 + * driver entries 76 392 */ 77 393 static const struct hda_device_id snd_hda_id_cmedia[] = { 78 - HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888), 79 - HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880), 80 - HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880), 81 - HDA_CODEC_ENTRY(0x13f69825, "CM9825", patch_cm9825), 394 + HDA_CODEC_ID(0x13f68888, "CMI8888"), 395 + HDA_CODEC_ID(0x13f69880, "CMI9880"), 396 + HDA_CODEC_ID(0x434d4980, "CMI9880"), 82 397 {} /* terminator */ 83 398 }; 84 399 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia); ··· 100 391 101 392 static struct hda_codec_driver cmedia_driver = { 102 393 .id = snd_hda_id_cmedia, 394 + .ops = &cmedia_codec_ops, 103 395 }; 104 396 105 397 module_hda_codec_driver(cmedia_driver);