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 --- |