diff options
-rw-r--r-- | sound/pci/hda/patch_ca0132.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 748fca78131c..9ea5660e1a3a 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c | |||
@@ -1172,6 +1172,59 @@ static int dspio_write_multiple(struct hda_codec *codec, | |||
1172 | return status; | 1172 | return status; |
1173 | } | 1173 | } |
1174 | 1174 | ||
1175 | static int dspio_read(struct hda_codec *codec, unsigned int *data) | ||
1176 | { | ||
1177 | int status; | ||
1178 | |||
1179 | status = dspio_send(codec, VENDOR_DSPIO_SCP_POST_READ_DATA, 0); | ||
1180 | if (status == -EIO) | ||
1181 | return status; | ||
1182 | |||
1183 | status = dspio_send(codec, VENDOR_DSPIO_STATUS, 0); | ||
1184 | if (status == -EIO || | ||
1185 | status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY) | ||
1186 | return -EIO; | ||
1187 | |||
1188 | *data = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, | ||
1189 | VENDOR_DSPIO_SCP_READ_DATA, 0); | ||
1190 | |||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1194 | static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer, | ||
1195 | unsigned int *buf_size, unsigned int size_count) | ||
1196 | { | ||
1197 | int status = 0; | ||
1198 | unsigned int size = *buf_size; | ||
1199 | unsigned int count; | ||
1200 | unsigned int skip_count; | ||
1201 | unsigned int dummy; | ||
1202 | |||
1203 | if ((buffer == NULL)) | ||
1204 | return -1; | ||
1205 | |||
1206 | count = 0; | ||
1207 | while (count < size && count < size_count) { | ||
1208 | status = dspio_read(codec, buffer++); | ||
1209 | if (status != 0) | ||
1210 | break; | ||
1211 | count++; | ||
1212 | } | ||
1213 | |||
1214 | skip_count = count; | ||
1215 | if (status == 0) { | ||
1216 | while (skip_count < size) { | ||
1217 | status = dspio_read(codec, &dummy); | ||
1218 | if (status != 0) | ||
1219 | break; | ||
1220 | skip_count++; | ||
1221 | } | ||
1222 | } | ||
1223 | *buf_size = count; | ||
1224 | |||
1225 | return status; | ||
1226 | } | ||
1227 | |||
1175 | /* | 1228 | /* |
1176 | * Construct the SCP header using corresponding fields | 1229 | * Construct the SCP header using corresponding fields |
1177 | */ | 1230 | */ |
@@ -1231,6 +1284,38 @@ struct scp_msg { | |||
1231 | unsigned int data[SCP_MAX_DATA_WORDS]; | 1284 | unsigned int data[SCP_MAX_DATA_WORDS]; |
1232 | }; | 1285 | }; |
1233 | 1286 | ||
1287 | static void dspio_clear_response_queue(struct hda_codec *codec) | ||
1288 | { | ||
1289 | unsigned int dummy = 0; | ||
1290 | int status = -1; | ||
1291 | |||
1292 | /* clear all from the response queue */ | ||
1293 | do { | ||
1294 | status = dspio_read(codec, &dummy); | ||
1295 | } while (status == 0); | ||
1296 | } | ||
1297 | |||
1298 | static int dspio_get_response_data(struct hda_codec *codec) | ||
1299 | { | ||
1300 | struct ca0132_spec *spec = codec->spec; | ||
1301 | unsigned int data = 0; | ||
1302 | unsigned int count; | ||
1303 | |||
1304 | if (dspio_read(codec, &data) < 0) | ||
1305 | return -EIO; | ||
1306 | |||
1307 | if ((data & 0x00ffffff) == spec->wait_scp_header) { | ||
1308 | spec->scp_resp_header = data; | ||
1309 | spec->scp_resp_count = data >> 27; | ||
1310 | count = spec->wait_num_data; | ||
1311 | dspio_read_multiple(codec, spec->scp_resp_data, | ||
1312 | &spec->scp_resp_count, count); | ||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | return -EIO; | ||
1317 | } | ||
1318 | |||
1234 | /* | 1319 | /* |
1235 | * Send SCP message to DSP | 1320 | * Send SCP message to DSP |
1236 | */ | 1321 | */ |
@@ -3743,6 +3828,12 @@ static int ca0132_build_controls(struct hda_codec *codec) | |||
3743 | return 0; | 3828 | return 0; |
3744 | } | 3829 | } |
3745 | 3830 | ||
3831 | static void ca0132_init_unsol(struct hda_codec *codec) | ||
3832 | { | ||
3833 | snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP); | ||
3834 | snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1, UNSOL_TAG_AMIC1); | ||
3835 | } | ||
3836 | |||
3746 | static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir) | 3837 | static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir) |
3747 | { | 3838 | { |
3748 | unsigned int caps; | 3839 | unsigned int caps; |
@@ -4152,6 +4243,47 @@ static void ca0132_download_dsp(struct hda_codec *codec) | |||
4152 | ca0132_set_dsp_msr(codec, true); | 4243 | ca0132_set_dsp_msr(codec, true); |
4153 | } | 4244 | } |
4154 | 4245 | ||
4246 | static void ca0132_process_dsp_response(struct hda_codec *codec) | ||
4247 | { | ||
4248 | struct ca0132_spec *spec = codec->spec; | ||
4249 | |||
4250 | snd_printdd(KERN_INFO "ca0132_process_dsp_response\n"); | ||
4251 | if (spec->wait_scp) { | ||
4252 | if (dspio_get_response_data(codec) >= 0) | ||
4253 | spec->wait_scp = 0; | ||
4254 | } | ||
4255 | |||
4256 | dspio_clear_response_queue(codec); | ||
4257 | } | ||
4258 | |||
4259 | static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4260 | { | ||
4261 | snd_printdd(KERN_INFO "ca0132_unsol_event: 0x%x\n", res); | ||
4262 | |||
4263 | |||
4264 | if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) { | ||
4265 | ca0132_process_dsp_response(codec); | ||
4266 | } else { | ||
4267 | res = snd_hda_jack_get_action(codec, | ||
4268 | (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f); | ||
4269 | |||
4270 | snd_printdd(KERN_INFO "snd_hda_jack_get_action: 0x%x\n", res); | ||
4271 | |||
4272 | switch (res) { | ||
4273 | case UNSOL_TAG_HP: | ||
4274 | ca0132_select_out(codec); | ||
4275 | snd_hda_jack_report_sync(codec); | ||
4276 | break; | ||
4277 | case UNSOL_TAG_AMIC1: | ||
4278 | ca0132_select_mic(codec); | ||
4279 | snd_hda_jack_report_sync(codec); | ||
4280 | break; | ||
4281 | default: | ||
4282 | break; | ||
4283 | } | ||
4284 | } | ||
4285 | } | ||
4286 | |||
4155 | static int ca0132_init(struct hda_codec *codec) | 4287 | static int ca0132_init(struct hda_codec *codec) |
4156 | { | 4288 | { |
4157 | struct ca0132_spec *spec = codec->spec; | 4289 | struct ca0132_spec *spec = codec->spec; |
@@ -4187,9 +4319,13 @@ static int ca0132_init(struct hda_codec *codec) | |||
4187 | for (i = 0; i < spec->num_init_verbs; i++) | 4319 | for (i = 0; i < spec->num_init_verbs; i++) |
4188 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | 4320 | snd_hda_sequence_write(codec, spec->init_verbs[i]); |
4189 | 4321 | ||
4322 | ca0132_init_unsol(codec); | ||
4323 | |||
4190 | ca0132_select_out(codec); | 4324 | ca0132_select_out(codec); |
4191 | ca0132_select_mic(codec); | 4325 | ca0132_select_mic(codec); |
4192 | 4326 | ||
4327 | snd_hda_jack_report_sync(codec); | ||
4328 | |||
4193 | snd_hda_power_down(codec); | 4329 | snd_hda_power_down(codec); |
4194 | 4330 | ||
4195 | return 0; | 4331 | return 0; |
@@ -4211,11 +4347,13 @@ static struct hda_codec_ops ca0132_patch_ops = { | |||
4211 | .build_pcms = ca0132_build_pcms, | 4347 | .build_pcms = ca0132_build_pcms, |
4212 | .init = ca0132_init, | 4348 | .init = ca0132_init, |
4213 | .free = ca0132_free, | 4349 | .free = ca0132_free, |
4350 | .unsol_event = ca0132_unsol_event, | ||
4214 | }; | 4351 | }; |
4215 | 4352 | ||
4216 | static int patch_ca0132(struct hda_codec *codec) | 4353 | static int patch_ca0132(struct hda_codec *codec) |
4217 | { | 4354 | { |
4218 | struct ca0132_spec *spec; | 4355 | struct ca0132_spec *spec; |
4356 | int err; | ||
4219 | 4357 | ||
4220 | snd_printdd("patch_ca0132\n"); | 4358 | snd_printdd("patch_ca0132\n"); |
4221 | 4359 | ||
@@ -4237,6 +4375,10 @@ static int patch_ca0132(struct hda_codec *codec) | |||
4237 | 4375 | ||
4238 | ca0132_config(codec); | 4376 | ca0132_config(codec); |
4239 | 4377 | ||
4378 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
4379 | if (err < 0) | ||
4380 | return err; | ||
4381 | |||
4240 | codec->patch_ops = ca0132_patch_ops; | 4382 | codec->patch_ops = ca0132_patch_ops; |
4241 | 4383 | ||
4242 | return 0; | 4384 | return 0; |