aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_ca0132.c
diff options
context:
space:
mode:
authorIan Minett <ian_minett@creativelabs.com>2012-12-20 21:53:37 -0500
committerTakashi Iwai <tiwai@suse.de>2013-01-15 10:59:56 -0500
commita73d511c4867c5aa75a9ab50f7e73d5086c48cda (patch)
treeb0f29d27834eab0d50a173dd152d279244cbd3e0 /sound/pci/hda/patch_ca0132.c
parent825315bc5b5c33e5af5124ff100ef05a30ad722f (diff)
ALSA: hda/ca0132: Add unsol handler for DSP and jack detection
This patch adds the unsolicited response handler for incoming DSP responses and jack detection reporting, and routines for reading the incoming DSP response. Signed-off-by: Ian Minett <ian_minett@creativelabs.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_ca0132.c')
-rw-r--r--sound/pci/hda/patch_ca0132.c142
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
1175static 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
1194static 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
1287static 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
1298static 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
3831static 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
3746static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir) 3837static 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
4246static 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
4259static 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
4155static int ca0132_init(struct hda_codec *codec) 4287static 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
4216static int patch_ca0132(struct hda_codec *codec) 4353static 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;