1 /*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for Realtek ALC codecs
5 *
6 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
8 * Takashi Iwai <tiwai@suse.de>
9 * Jonathan Woithe <jwoithe@just42.net>
10 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * Taken from linux's patch_realtek.c
26 */
27
28 #ifdef HAVE_KERNEL_OPTION_HEADERS
29 #include "opt_snd.h"
30 #endif
31
32 #include <dev/sound/pcm/sound.h>
33
34 #include <sys/ctype.h>
35
36 #include <dev/sound/pci/hda/hdac.h>
37 #include <dev/sound/pci/hda/hdaa.h>
38 #include <dev/sound/pci/hda/hda_reg.h>
39 #include <dev/sound/pci/hda/hdaa_patches.h>
40
41 void
hdaa_patch_direct_acer_c720(struct hdaa_devinfo * devinfo)42 hdaa_patch_direct_acer_c720(struct hdaa_devinfo *devinfo)
43 {
44 struct hdaa_widget *w;
45 device_t dev = devinfo->dev;
46 uint32_t val;
47
48 kprintf("Acer C720 patch\n");
49
50 /* power down control */
51 hda_write_coef_idx(dev, 0x20, 0x03, 0x0002);
52 /* FIFO and filter clock */
53 hda_write_coef_idx(dev, 0x20, 0x05, 0x0700);
54 /* DMIC control */
55 hda_write_coef_idx(dev, 0x20, 0x07, 0x0200);
56 /* Analog clock */
57 val = hda_read_coef_idx(dev, 0x20, 0x06);
58 hda_write_coef_idx(dev, 0x20, 0x06, (val & ~0x00f0) | 0x0);
59
60 /* JD */
61 val = hda_read_coef_idx(dev, 0x20, 0x08);
62 hda_write_coef_idx(dev, 0x20, 0x08, (val & ~0xfffc) | 0x0c2c);
63 /* JD offset1 */
64 hda_write_coef_idx(dev, 0x20, 0x0a, 0xcccc);
65 /* JD offset2 */
66 hda_write_coef_idx(dev, 0x20, 0x0b, 0xcccc);
67 /* LD0/1/2/3, DAC/ADC */
68 hda_write_coef_idx(dev, 0x20, 0x0e, 0x6fc0);
69 /* JD */
70 val = hda_read_coef_idx(dev, 0x20, 0x0f);
71 hda_write_coef_idx(dev, 0x20, 0x0f, (val & ~0xf800) | 0x1000);
72
73 /* Capless */
74 val = hda_read_coef_idx(dev, 0x20, 0x10);
75 hda_write_coef_idx(dev, 0x20, 0x10, (val & ~0xfc00) | 0x0c00);
76 /* Class D test 4 */
77 hda_write_coef_idx(dev, 0x20, 0x3a, 0x0);
78 /* IO power down directly */
79 val = hda_read_coef_idx(dev, 0x20, 0x0c);
80 hda_write_coef_idx(dev, 0x20, 0x0c, (val & ~0xfe00) | 0x0);
81 /* ANC */
82 hda_write_coef_idx(dev, 0x20, 0x22, 0xa0c0);
83 /* AGC MUX */
84 val = hda_read_coef_idx(dev, 0x53, 0x01);
85 hda_write_coef_idx(dev, 0x53, 0x01, (val & ~0x000f) | 0x0008);
86
87 /* DAC simple content protection */
88 val = hda_read_coef_idx(dev, 0x20, 0x1d);
89 hda_write_coef_idx(dev, 0x20, 0x1d, (val & ~0x00e0) | 0x0);
90 /* ADC simple content protection */
91 val = hda_read_coef_idx(dev, 0x20, 0x1f);
92 hda_write_coef_idx(dev, 0x20, 0x1f, (val & ~0x00e0) | 0x0);
93 /* DAC ADC Zero Detection */
94 hda_write_coef_idx(dev, 0x20, 0x21, 0x8804);
95 /* PLL */
96 hda_write_coef_idx(dev, 0x20, 0x2e, 0x2902);
97 /* capless control 2 */
98 hda_write_coef_idx(dev, 0x20, 0x33, 0xa080);
99 /* capless control 3 */
100 hda_write_coef_idx(dev, 0x20, 0x34, 0x3400);
101 /* capless control 4 */
102 hda_write_coef_idx(dev, 0x20, 0x35, 0x2f3e);
103 /* capless control 5 */
104 hda_write_coef_idx(dev, 0x20, 0x36, 0x0);
105 /* class D test 2 */
106 val = hda_read_coef_idx(dev, 0x20, 0x38);
107 hda_write_coef_idx(dev, 0x20, 0x38, (val & ~0x0fff) | 0x0900);
108
109 /* class D test 3 */
110 hda_write_coef_idx(dev, 0x20, 0x39, 0x110a);
111 /* class D test 5 */
112 val = hda_read_coef_idx(dev, 0x20, 0x3b);
113 hda_write_coef_idx(dev, 0x20, 0x3b, (val & ~0x00f8) | 0x00d8);
114 /* class D test 6 */
115 hda_write_coef_idx(dev, 0x20, 0x3c, 0x0014);
116 /* classD OCP */
117 hda_write_coef_idx(dev, 0x20, 0x3d, 0xc2ba);
118 /* classD pure DC test */
119 val = hda_read_coef_idx(dev, 0x20, 0x42);
120 hda_write_coef_idx(dev, 0x20, 0x42, (val & ~0x0f80) | 0x0);
121 /* test mode */
122 hda_write_coef_idx(dev, 0x20, 0x49, 0x0);
123 /* Class D DC enable */
124 val = hda_read_coef_idx(dev, 0x20, 0x40);
125 hda_write_coef_idx(dev, 0x20, 0x40, (val & ~0xf800) | 0x9800);
126 /* DC offset */
127 val = hda_read_coef_idx(dev, 0x20, 0x42);
128 hda_write_coef_idx(dev, 0x20, 0x42, (val & ~0xf000) | 0x2000);
129 /* Class D amp control */
130 hda_write_coef_idx(dev, 0x20, 0x37, 0xfc06);
131
132 /* Index 0x43 direct drive HP AMP LPM Control 1 */
133 /* Headphone capless set to high power mode */
134 hda_write_coef_idx(dev, 0x20, 0x43, 0x9004);
135
136 #if 0
137 /*
138 * This has to do with the 'mute internal speaker when
139 * ext headphone out jack is plugged' function. nid 27
140 * comes from the special config bits (XXX currently hardwired)
141 *
142 * XXX doesn't apply to chromebook where we just have to change
143 * the mixer selection for nid 33.
144 */
145 int dummy;
146 hda_command(dev, HDA_CMD_SET_AMP_GAIN_MUTE(0, 27, 0xb080));
147 tsleep(&dummy, 0, "hdaslp", hz / 10);
148 hda_command(dev, HDA_CMD_SET_PIN_WIDGET_CTRL(0, 27,
149 HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE));
150 tsleep(&dummy, 0, "hdaslp", hz / 10);
151 #endif
152
153 /* 0x46 combo jack auto switch control 2 */
154 /* 3k pull-down control for headset jack. */
155 val = hda_read_coef_idx(dev, 0x20, 0x46);
156 hda_write_coef_idx(dev, 0x20, 0x46, val & ~(3 << 12));
157 /* headphone capless set to normal mode */
158 hda_write_coef_idx(dev, 0x20, 0x43, 0x9614);
159
160 #if 0
161 /*
162 * Fixup chromebook (? which chromebook?)
163 */
164 /* MIC2-VREF control */
165 /* set to manual mode */
166 val = hda_read_coef_idx(dev, 0x20, 0x06);
167 hda_write_coef_idx(dev, 0x20, 0x06, val & ~0x000c);
168 /* enable line1 input control by verb */
169 val = hda_read_coef_idx(dev, 0x20, 0x1a);
170 hda_write_coef_idx(dev, 0x20, 0x1a, val | (1 << 4));
171 #endif
172
173 /*
174 * 31-30 : port connectivity
175 * 29-21 : reserved
176 * 20 : PCBEEP input
177 * 19-16 : checksum (15:1)
178 * 15-1 : Custom
179 * 0 : Override
180 *
181 * XXX this needs code from linux patch_realtek.c alc_subsystem_id().
182 * Chromebook: 0x4015812d
183 * bit 30 physical connection present
184 * bit 15 if set we want the 'mute internal speaker when
185 * ext headphone out jack is plugged' function
186 * bit 14:13 reserved
187 * bit 12:11 headphone out 00: PortA, 01: PortE, 02: PortD,
188 * 03: Reserved (for C720 this is 0)
189 * bit 10:8 jack location (for c720 this is 1)
190 * 0, 0x1b, 0x14, 0x21 - nnid 27 is jack?
191 *
192 * bit 5:3 -> 101 (5). ALC_INIT_DEFAULT (default ext amp ctl)
193 * bit 0 override (is set)
194 */
195 if ((w = hdaa_widget_get(devinfo, 0x1d)) != NULL) {
196 kprintf("WIDGET SPECIAL: %08x\n", w->wclass.pin.config);
197 /* XXX currently in hdaa_patch_direct_acer_c720(devinfo); */
198 }
199 }
200