wm_hubs.c (b74b953b998bcc2db91b694446f3a2619ec32de6) wm_hubs.c (fec6dd833e733b5d9588a1f1e4d81118b79b5774)
1/*
2 * wm_hubs.c -- WM8993/4 common code
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 *

--- 80 unchanged lines hidden (view full) ---

89/*
90 * Startup calibration of the DC servo
91 */
92static void calibrate_dc_servo(struct snd_soc_codec *codec)
93{
94 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
95 u16 reg, reg_l, reg_r, dcs_cfg;
96
1/*
2 * wm_hubs.c -- WM8993/4 common code
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 *

--- 80 unchanged lines hidden (view full) ---

89/*
90 * Startup calibration of the DC servo
91 */
92static void calibrate_dc_servo(struct snd_soc_codec *codec)
93{
94 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
95 u16 reg, reg_l, reg_r, dcs_cfg;
96
97 /* If we're using a digital only path and have a previously
98 * callibrated DC servo offset stored then use that. */
99 if (hubs->class_w && hubs->class_w_dcs) {
100 dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
101 hubs->class_w_dcs);
102 snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs);
103 wait_for_dc_servo(codec,
104 WM8993_DCS_TRIG_DAC_WR_0 |
105 WM8993_DCS_TRIG_DAC_WR_1);
106 return;
107 }
108
97 /* Set for 32 series updates */
98 snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
99 WM8993_DCS_SERIES_NO_01_MASK,
100 32 << WM8993_DCS_SERIES_NO_01_SHIFT);
101 wait_for_dc_servo(codec,
102 WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1);
103
109 /* Set for 32 series updates */
110 snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
111 WM8993_DCS_SERIES_NO_01_MASK,
112 32 << WM8993_DCS_SERIES_NO_01_SHIFT);
113 wait_for_dc_servo(codec,
114 WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1);
115
116 /* Different chips in the family support different readback
117 * methods.
118 */
119 switch (hubs->dcs_readback_mode) {
120 case 0:
121 reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
122 & WM8993_DCS_INTEG_CHAN_0_MASK;;
123 reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
124 & WM8993_DCS_INTEG_CHAN_1_MASK;
125 break;
126 case 1:
127 reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
128 reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
129 >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
130 reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
131 break;
132 default:
133 WARN(1, "Unknown DCS readback method");
134 break;
135 }
136
137 dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
138
104 /* Apply correction to DC servo result */
105 if (hubs->dcs_codes) {
106 dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
107 hubs->dcs_codes);
108
139 /* Apply correction to DC servo result */
140 if (hubs->dcs_codes) {
141 dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
142 hubs->dcs_codes);
143
109 /* Different chips in the family support different
110 * readback methods.
111 */
112 switch (hubs->dcs_readback_mode) {
113 case 0:
114 reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
115 & WM8993_DCS_INTEG_CHAN_0_MASK;;
116 reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
117 & WM8993_DCS_INTEG_CHAN_1_MASK;
118 break;
119 case 1:
120 reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
121 reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
122 >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
123 reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
124 break;
125 default:
126 WARN(1, "Unknown DCS readback method");
127 break;
128 }
129
130 dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
131
132 /* HPOUT1L */
133 if (reg_l + hubs->dcs_codes > 0 &&
134 reg_l + hubs->dcs_codes < 0xff)
135 reg_l += hubs->dcs_codes;
136 dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
137
138 /* HPOUT1R */
139 if (reg_r + hubs->dcs_codes > 0 &&
140 reg_r + hubs->dcs_codes < 0xff)
141 reg_r += hubs->dcs_codes;
142 dcs_cfg |= reg_r;
143
144 dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
145
146 /* Do it */
147 snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
148 wait_for_dc_servo(codec,
149 WM8993_DCS_TRIG_DAC_WR_0 |
150 WM8993_DCS_TRIG_DAC_WR_1);
144 /* HPOUT1L */
145 if (reg_l + hubs->dcs_codes > 0 &&
146 reg_l + hubs->dcs_codes < 0xff)
147 reg_l += hubs->dcs_codes;
148 dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
149
150 /* HPOUT1R */
151 if (reg_r + hubs->dcs_codes > 0 &&
152 reg_r + hubs->dcs_codes < 0xff)
153 reg_r += hubs->dcs_codes;
154 dcs_cfg |= reg_r;
155
156 dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
157
158 /* Do it */
159 snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
160 wait_for_dc_servo(codec,
161 WM8993_DCS_TRIG_DAC_WR_0 |
162 WM8993_DCS_TRIG_DAC_WR_1);
163 } else {
164 dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
165 dcs_cfg |= reg_r;
151 }
166 }
167
168 /* Save the callibrated offset if we're in class W mode and
169 * therefore don't have any analogue signal mixed in. */
170 if (hubs->class_w)
171 hubs->class_w_dcs = dcs_cfg;
152}
153
154/*
155 * Update the DC servo calibration on gain changes
156 */
157static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
158 struct snd_ctl_elem_value *ucontrol)
159{
160 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
161 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
162 int ret;
163
164 ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
165
172}
173
174/*
175 * Update the DC servo calibration on gain changes
176 */
177static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
181 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
182 int ret;
183
184 ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
185
186 /* Updating the analogue gains invalidates the DC servo cache */
187 hubs->class_w_dcs = 0;
188
166 /* If we're applying an offset correction then updating the
167 * callibration would be likely to introduce further offsets. */
168 if (hubs->dcs_codes)
169 return ret;
170
171 /* Only need to do this if the outputs are active */
172 if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1)
173 & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))

--- 726 unchanged lines hidden ---
189 /* If we're applying an offset correction then updating the
190 * callibration would be likely to introduce further offsets. */
191 if (hubs->dcs_codes)
192 return ret;
193
194 /* Only need to do this if the outputs are active */
195 if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1)
196 & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))

--- 726 unchanged lines hidden ---