diff options
Diffstat (limited to 'sound')
131 files changed, 8390 insertions, 2564 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index f038f5afafe2..f0b0e14497a5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card, | |||
288 | { | 288 | { |
289 | struct snd_kcontrol *kctl; | 289 | struct snd_kcontrol *kctl; |
290 | 290 | ||
291 | /* Make sure that the ids assigned to the control do not wrap around */ | ||
292 | if (card->last_numid >= UINT_MAX - count) | ||
293 | card->last_numid = 0; | ||
294 | |||
291 | list_for_each_entry(kctl, &card->controls, list) { | 295 | list_for_each_entry(kctl, &card->controls, list) { |
292 | if (kctl->id.numid < card->last_numid + 1 + count && | 296 | if (kctl->id.numid < card->last_numid + 1 + count && |
293 | kctl->id.numid + kctl->count > card->last_numid + 1) { | 297 | kctl->id.numid + kctl->count > card->last_numid + 1) { |
@@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
330 | { | 334 | { |
331 | struct snd_ctl_elem_id id; | 335 | struct snd_ctl_elem_id id; |
332 | unsigned int idx; | 336 | unsigned int idx; |
337 | unsigned int count; | ||
333 | int err = -EINVAL; | 338 | int err = -EINVAL; |
334 | 339 | ||
335 | if (! kcontrol) | 340 | if (! kcontrol) |
@@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
337 | if (snd_BUG_ON(!card || !kcontrol->info)) | 342 | if (snd_BUG_ON(!card || !kcontrol->info)) |
338 | goto error; | 343 | goto error; |
339 | id = kcontrol->id; | 344 | id = kcontrol->id; |
345 | if (id.index > UINT_MAX - kcontrol->count) | ||
346 | goto error; | ||
347 | |||
340 | down_write(&card->controls_rwsem); | 348 | down_write(&card->controls_rwsem); |
341 | if (snd_ctl_find_id(card, &id)) { | 349 | if (snd_ctl_find_id(card, &id)) { |
342 | up_write(&card->controls_rwsem); | 350 | up_write(&card->controls_rwsem); |
@@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
358 | card->controls_count += kcontrol->count; | 366 | card->controls_count += kcontrol->count; |
359 | kcontrol->id.numid = card->last_numid + 1; | 367 | kcontrol->id.numid = card->last_numid + 1; |
360 | card->last_numid += kcontrol->count; | 368 | card->last_numid += kcontrol->count; |
369 | count = kcontrol->count; | ||
361 | up_write(&card->controls_rwsem); | 370 | up_write(&card->controls_rwsem); |
362 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | 371 | for (idx = 0; idx < count; idx++, id.index++, id.numid++) |
363 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | 372 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); |
364 | return 0; | 373 | return 0; |
365 | 374 | ||
@@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, | |||
388 | bool add_on_replace) | 397 | bool add_on_replace) |
389 | { | 398 | { |
390 | struct snd_ctl_elem_id id; | 399 | struct snd_ctl_elem_id id; |
400 | unsigned int count; | ||
391 | unsigned int idx; | 401 | unsigned int idx; |
392 | struct snd_kcontrol *old; | 402 | struct snd_kcontrol *old; |
393 | int ret; | 403 | int ret; |
@@ -423,8 +433,9 @@ add: | |||
423 | card->controls_count += kcontrol->count; | 433 | card->controls_count += kcontrol->count; |
424 | kcontrol->id.numid = card->last_numid + 1; | 434 | kcontrol->id.numid = card->last_numid + 1; |
425 | card->last_numid += kcontrol->count; | 435 | card->last_numid += kcontrol->count; |
436 | count = kcontrol->count; | ||
426 | up_write(&card->controls_rwsem); | 437 | up_write(&card->controls_rwsem); |
427 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | 438 | for (idx = 0; idx < count; idx++, id.index++, id.numid++) |
428 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | 439 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); |
429 | return 0; | 440 | return 0; |
430 | 441 | ||
@@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | |||
897 | result = kctl->put(kctl, control); | 908 | result = kctl->put(kctl, control); |
898 | } | 909 | } |
899 | if (result > 0) { | 910 | if (result > 0) { |
911 | struct snd_ctl_elem_id id = control->id; | ||
900 | up_read(&card->controls_rwsem); | 912 | up_read(&card->controls_rwsem); |
901 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | 913 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); |
902 | &control->id); | ||
903 | return 0; | 914 | return 0; |
904 | } | 915 | } |
905 | } | 916 | } |
@@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, | |||
991 | 1002 | ||
992 | struct user_element { | 1003 | struct user_element { |
993 | struct snd_ctl_elem_info info; | 1004 | struct snd_ctl_elem_info info; |
1005 | struct snd_card *card; | ||
994 | void *elem_data; /* element data */ | 1006 | void *elem_data; /* element data */ |
995 | unsigned long elem_data_size; /* size of element data in bytes */ | 1007 | unsigned long elem_data_size; /* size of element data in bytes */ |
996 | void *tlv_data; /* TLV data */ | 1008 | void *tlv_data; /* TLV data */ |
@@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, | |||
1034 | { | 1046 | { |
1035 | struct user_element *ue = kcontrol->private_data; | 1047 | struct user_element *ue = kcontrol->private_data; |
1036 | 1048 | ||
1049 | mutex_lock(&ue->card->user_ctl_lock); | ||
1037 | memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); | 1050 | memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); |
1051 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1038 | return 0; | 1052 | return 0; |
1039 | } | 1053 | } |
1040 | 1054 | ||
@@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, | |||
1043 | { | 1057 | { |
1044 | int change; | 1058 | int change; |
1045 | struct user_element *ue = kcontrol->private_data; | 1059 | struct user_element *ue = kcontrol->private_data; |
1046 | 1060 | ||
1061 | mutex_lock(&ue->card->user_ctl_lock); | ||
1047 | change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; | 1062 | change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; |
1048 | if (change) | 1063 | if (change) |
1049 | memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); | 1064 | memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); |
1065 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1050 | return change; | 1066 | return change; |
1051 | } | 1067 | } |
1052 | 1068 | ||
@@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, | |||
1066 | new_data = memdup_user(tlv, size); | 1082 | new_data = memdup_user(tlv, size); |
1067 | if (IS_ERR(new_data)) | 1083 | if (IS_ERR(new_data)) |
1068 | return PTR_ERR(new_data); | 1084 | return PTR_ERR(new_data); |
1085 | mutex_lock(&ue->card->user_ctl_lock); | ||
1069 | change = ue->tlv_data_size != size; | 1086 | change = ue->tlv_data_size != size; |
1070 | if (!change) | 1087 | if (!change) |
1071 | change = memcmp(ue->tlv_data, new_data, size); | 1088 | change = memcmp(ue->tlv_data, new_data, size); |
1072 | kfree(ue->tlv_data); | 1089 | kfree(ue->tlv_data); |
1073 | ue->tlv_data = new_data; | 1090 | ue->tlv_data = new_data; |
1074 | ue->tlv_data_size = size; | 1091 | ue->tlv_data_size = size; |
1092 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1075 | } else { | 1093 | } else { |
1076 | if (! ue->tlv_data_size || ! ue->tlv_data) | 1094 | int ret = 0; |
1077 | return -ENXIO; | 1095 | |
1078 | if (size < ue->tlv_data_size) | 1096 | mutex_lock(&ue->card->user_ctl_lock); |
1079 | return -ENOSPC; | 1097 | if (!ue->tlv_data_size || !ue->tlv_data) { |
1098 | ret = -ENXIO; | ||
1099 | goto err_unlock; | ||
1100 | } | ||
1101 | if (size < ue->tlv_data_size) { | ||
1102 | ret = -ENOSPC; | ||
1103 | goto err_unlock; | ||
1104 | } | ||
1080 | if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) | 1105 | if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) |
1081 | return -EFAULT; | 1106 | ret = -EFAULT; |
1107 | err_unlock: | ||
1108 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1109 | if (ret) | ||
1110 | return ret; | ||
1082 | } | 1111 | } |
1083 | return change; | 1112 | return change; |
1084 | } | 1113 | } |
@@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1136 | struct user_element *ue; | 1165 | struct user_element *ue; |
1137 | int idx, err; | 1166 | int idx, err; |
1138 | 1167 | ||
1139 | if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS) | ||
1140 | return -ENOMEM; | ||
1141 | if (info->count < 1) | 1168 | if (info->count < 1) |
1142 | return -EINVAL; | 1169 | return -EINVAL; |
1143 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 1170 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
@@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1146 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); | 1173 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); |
1147 | info->id.numid = 0; | 1174 | info->id.numid = 0; |
1148 | memset(&kctl, 0, sizeof(kctl)); | 1175 | memset(&kctl, 0, sizeof(kctl)); |
1149 | down_write(&card->controls_rwsem); | 1176 | |
1150 | _kctl = snd_ctl_find_id(card, &info->id); | 1177 | if (replace) { |
1151 | err = 0; | 1178 | err = snd_ctl_remove_user_ctl(file, &info->id); |
1152 | if (_kctl) { | 1179 | if (err) |
1153 | if (replace) | 1180 | return err; |
1154 | err = snd_ctl_remove(card, _kctl); | ||
1155 | else | ||
1156 | err = -EBUSY; | ||
1157 | } else { | ||
1158 | if (replace) | ||
1159 | err = -ENOENT; | ||
1160 | } | 1181 | } |
1161 | up_write(&card->controls_rwsem); | 1182 | |
1162 | if (err < 0) | 1183 | if (card->user_ctl_count >= MAX_USER_CONTROLS) |
1163 | return err; | 1184 | return -ENOMEM; |
1185 | |||
1164 | memcpy(&kctl.id, &info->id, sizeof(info->id)); | 1186 | memcpy(&kctl.id, &info->id, sizeof(info->id)); |
1165 | kctl.count = info->owner ? info->owner : 1; | 1187 | kctl.count = info->owner ? info->owner : 1; |
1166 | access |= SNDRV_CTL_ELEM_ACCESS_USER; | 1188 | access |= SNDRV_CTL_ELEM_ACCESS_USER; |
@@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1210 | ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); | 1232 | ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); |
1211 | if (ue == NULL) | 1233 | if (ue == NULL) |
1212 | return -ENOMEM; | 1234 | return -ENOMEM; |
1235 | ue->card = card; | ||
1213 | ue->info = *info; | 1236 | ue->info = *info; |
1214 | ue->info.access = 0; | 1237 | ue->info.access = 0; |
1215 | ue->elem_data = (char *)ue + sizeof(*ue); | 1238 | ue->elem_data = (char *)ue + sizeof(*ue); |
@@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | |||
1321 | } | 1344 | } |
1322 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); | 1345 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); |
1323 | if (err > 0) { | 1346 | if (err > 0) { |
1347 | struct snd_ctl_elem_id id = kctl->id; | ||
1324 | up_read(&card->controls_rwsem); | 1348 | up_read(&card->controls_rwsem); |
1325 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); | 1349 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id); |
1326 | return 0; | 1350 | return 0; |
1327 | } | 1351 | } |
1328 | } else { | 1352 | } else { |
diff --git a/sound/core/init.c b/sound/core/init.c index 5ee83845c5de..7bdfd19e24a8 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, | |||
232 | INIT_LIST_HEAD(&card->devices); | 232 | INIT_LIST_HEAD(&card->devices); |
233 | init_rwsem(&card->controls_rwsem); | 233 | init_rwsem(&card->controls_rwsem); |
234 | rwlock_init(&card->ctl_files_rwlock); | 234 | rwlock_init(&card->ctl_files_rwlock); |
235 | mutex_init(&card->user_ctl_lock); | ||
235 | INIT_LIST_HEAD(&card->controls); | 236 | INIT_LIST_HEAD(&card->controls); |
236 | INIT_LIST_HEAD(&card->ctl_files); | 237 | INIT_LIST_HEAD(&card->ctl_files); |
237 | spin_lock_init(&card->files_lock); | 238 | spin_lock_init(&card->files_lock); |
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 76cbb9ec953a..6542c4083594 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c | |||
@@ -65,13 +65,15 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, | |||
65 | enum dma_slave_buswidth buswidth; | 65 | enum dma_slave_buswidth buswidth; |
66 | int bits; | 66 | int bits; |
67 | 67 | ||
68 | bits = snd_pcm_format_physical_width(params_format(params)); | 68 | bits = params_physical_width(params); |
69 | if (bits < 8 || bits > 64) | 69 | if (bits < 8 || bits > 64) |
70 | return -EINVAL; | 70 | return -EINVAL; |
71 | else if (bits == 8) | 71 | else if (bits == 8) |
72 | buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; | 72 | buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; |
73 | else if (bits == 16) | 73 | else if (bits == 16) |
74 | buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; | 74 | buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; |
75 | else if (bits == 24) | ||
76 | buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES; | ||
75 | else if (bits <= 32) | 77 | else if (bits <= 32) |
76 | buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; | 78 | buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; |
77 | else | 79 | else |
diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index 6af50eb80ea7..70faa3a32526 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c | |||
@@ -379,11 +379,11 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, | |||
379 | struct special_params *params = bebob->maudio_special_quirk; | 379 | struct special_params *params = bebob->maudio_special_quirk; |
380 | int err, id; | 380 | int err, id; |
381 | 381 | ||
382 | mutex_lock(&bebob->mutex); | ||
383 | |||
384 | id = uval->value.enumerated.item[0]; | 382 | id = uval->value.enumerated.item[0]; |
385 | if (id >= ARRAY_SIZE(special_clk_labels)) | 383 | if (id >= ARRAY_SIZE(special_clk_labels)) |
386 | return 0; | 384 | return -EINVAL; |
385 | |||
386 | mutex_lock(&bebob->mutex); | ||
387 | 387 | ||
388 | err = avc_maudio_set_special_clk(bebob, id, | 388 | err = avc_maudio_set_special_clk(bebob, id, |
389 | params->dig_in_fmt, | 389 | params->dig_in_fmt, |
@@ -391,7 +391,10 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, | |||
391 | params->clk_lock); | 391 | params->clk_lock); |
392 | mutex_unlock(&bebob->mutex); | 392 | mutex_unlock(&bebob->mutex); |
393 | 393 | ||
394 | return err >= 0; | 394 | if (err >= 0) |
395 | err = 1; | ||
396 | |||
397 | return err; | ||
395 | } | 398 | } |
396 | static struct snd_kcontrol_new special_clk_ctl = { | 399 | static struct snd_kcontrol_new special_clk_ctl = { |
397 | .name = "Clock Source", | 400 | .name = "Clock Source", |
@@ -434,8 +437,8 @@ static struct snd_kcontrol_new special_sync_ctl = { | |||
434 | .get = special_sync_ctl_get, | 437 | .get = special_sync_ctl_get, |
435 | }; | 438 | }; |
436 | 439 | ||
437 | /* Digital interface control for special firmware */ | 440 | /* Digital input interface control for special firmware */ |
438 | static char *const special_dig_iface_labels[] = { | 441 | static char *const special_dig_in_iface_labels[] = { |
439 | "S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical" | 442 | "S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical" |
440 | }; | 443 | }; |
441 | static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, | 444 | static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, |
@@ -443,13 +446,13 @@ static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, | |||
443 | { | 446 | { |
444 | einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 447 | einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
445 | einf->count = 1; | 448 | einf->count = 1; |
446 | einf->value.enumerated.items = ARRAY_SIZE(special_dig_iface_labels); | 449 | einf->value.enumerated.items = ARRAY_SIZE(special_dig_in_iface_labels); |
447 | 450 | ||
448 | if (einf->value.enumerated.item >= einf->value.enumerated.items) | 451 | if (einf->value.enumerated.item >= einf->value.enumerated.items) |
449 | einf->value.enumerated.item = einf->value.enumerated.items - 1; | 452 | einf->value.enumerated.item = einf->value.enumerated.items - 1; |
450 | 453 | ||
451 | strcpy(einf->value.enumerated.name, | 454 | strcpy(einf->value.enumerated.name, |
452 | special_dig_iface_labels[einf->value.enumerated.item]); | 455 | special_dig_in_iface_labels[einf->value.enumerated.item]); |
453 | 456 | ||
454 | return 0; | 457 | return 0; |
455 | } | 458 | } |
@@ -491,26 +494,36 @@ static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl, | |||
491 | unsigned int id, dig_in_fmt, dig_in_iface; | 494 | unsigned int id, dig_in_fmt, dig_in_iface; |
492 | int err; | 495 | int err; |
493 | 496 | ||
494 | mutex_lock(&bebob->mutex); | ||
495 | |||
496 | id = uval->value.enumerated.item[0]; | 497 | id = uval->value.enumerated.item[0]; |
498 | if (id >= ARRAY_SIZE(special_dig_in_iface_labels)) | ||
499 | return -EINVAL; | ||
497 | 500 | ||
498 | /* decode user value */ | 501 | /* decode user value */ |
499 | dig_in_fmt = (id >> 1) & 0x01; | 502 | dig_in_fmt = (id >> 1) & 0x01; |
500 | dig_in_iface = id & 0x01; | 503 | dig_in_iface = id & 0x01; |
501 | 504 | ||
505 | mutex_lock(&bebob->mutex); | ||
506 | |||
502 | err = avc_maudio_set_special_clk(bebob, | 507 | err = avc_maudio_set_special_clk(bebob, |
503 | params->clk_src, | 508 | params->clk_src, |
504 | dig_in_fmt, | 509 | dig_in_fmt, |
505 | params->dig_out_fmt, | 510 | params->dig_out_fmt, |
506 | params->clk_lock); | 511 | params->clk_lock); |
507 | if ((err < 0) || (params->dig_in_fmt > 0)) /* ADAT */ | 512 | if (err < 0) |
513 | goto end; | ||
514 | |||
515 | /* For ADAT, optical interface is only available. */ | ||
516 | if (params->dig_in_fmt > 0) { | ||
517 | err = 1; | ||
508 | goto end; | 518 | goto end; |
519 | } | ||
509 | 520 | ||
521 | /* For S/PDIF, optical/coaxial interfaces are selectable. */ | ||
510 | err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface); | 522 | err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface); |
511 | if (err < 0) | 523 | if (err < 0) |
512 | dev_err(&bebob->unit->device, | 524 | dev_err(&bebob->unit->device, |
513 | "fail to set digital input interface: %d\n", err); | 525 | "fail to set digital input interface: %d\n", err); |
526 | err = 1; | ||
514 | end: | 527 | end: |
515 | special_stream_formation_set(bebob); | 528 | special_stream_formation_set(bebob); |
516 | mutex_unlock(&bebob->mutex); | 529 | mutex_unlock(&bebob->mutex); |
@@ -525,18 +538,22 @@ static struct snd_kcontrol_new special_dig_in_iface_ctl = { | |||
525 | .put = special_dig_in_iface_ctl_set | 538 | .put = special_dig_in_iface_ctl_set |
526 | }; | 539 | }; |
527 | 540 | ||
541 | /* Digital output interface control for special firmware */ | ||
542 | static char *const special_dig_out_iface_labels[] = { | ||
543 | "S/PDIF Optical and Coaxial", "ADAT Optical" | ||
544 | }; | ||
528 | static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl, | 545 | static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl, |
529 | struct snd_ctl_elem_info *einf) | 546 | struct snd_ctl_elem_info *einf) |
530 | { | 547 | { |
531 | einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 548 | einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
532 | einf->count = 1; | 549 | einf->count = 1; |
533 | einf->value.enumerated.items = ARRAY_SIZE(special_dig_iface_labels) - 1; | 550 | einf->value.enumerated.items = ARRAY_SIZE(special_dig_out_iface_labels); |
534 | 551 | ||
535 | if (einf->value.enumerated.item >= einf->value.enumerated.items) | 552 | if (einf->value.enumerated.item >= einf->value.enumerated.items) |
536 | einf->value.enumerated.item = einf->value.enumerated.items - 1; | 553 | einf->value.enumerated.item = einf->value.enumerated.items - 1; |
537 | 554 | ||
538 | strcpy(einf->value.enumerated.name, | 555 | strcpy(einf->value.enumerated.name, |
539 | special_dig_iface_labels[einf->value.enumerated.item + 1]); | 556 | special_dig_out_iface_labels[einf->value.enumerated.item]); |
540 | 557 | ||
541 | return 0; | 558 | return 0; |
542 | } | 559 | } |
@@ -558,16 +575,20 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, | |||
558 | unsigned int id; | 575 | unsigned int id; |
559 | int err; | 576 | int err; |
560 | 577 | ||
561 | mutex_lock(&bebob->mutex); | ||
562 | |||
563 | id = uval->value.enumerated.item[0]; | 578 | id = uval->value.enumerated.item[0]; |
579 | if (id >= ARRAY_SIZE(special_dig_out_iface_labels)) | ||
580 | return -EINVAL; | ||
581 | |||
582 | mutex_lock(&bebob->mutex); | ||
564 | 583 | ||
565 | err = avc_maudio_set_special_clk(bebob, | 584 | err = avc_maudio_set_special_clk(bebob, |
566 | params->clk_src, | 585 | params->clk_src, |
567 | params->dig_in_fmt, | 586 | params->dig_in_fmt, |
568 | id, params->clk_lock); | 587 | id, params->clk_lock); |
569 | if (err >= 0) | 588 | if (err >= 0) { |
570 | special_stream_formation_set(bebob); | 589 | special_stream_formation_set(bebob); |
590 | err = 1; | ||
591 | } | ||
571 | 592 | ||
572 | mutex_unlock(&bebob->mutex); | 593 | mutex_unlock(&bebob->mutex); |
573 | return err; | 594 | return err; |
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index b684c6e4f301..dabe41975a9d 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c | |||
@@ -898,6 +898,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec, | |||
898 | if (!strcmp(codec->modelname, models->name)) { | 898 | if (!strcmp(codec->modelname, models->name)) { |
899 | codec->fixup_id = models->id; | 899 | codec->fixup_id = models->id; |
900 | codec->fixup_name = models->name; | 900 | codec->fixup_name = models->name; |
901 | codec->fixup_list = fixlist; | ||
901 | codec->fixup_forced = 1; | 902 | codec->fixup_forced = 1; |
902 | return; | 903 | return; |
903 | } | 904 | } |
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 480bbddbd801..6df04d91c93c 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c | |||
@@ -193,7 +193,8 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) | |||
193 | dsp_unlock(azx_dev); | 193 | dsp_unlock(azx_dev); |
194 | return azx_dev; | 194 | return azx_dev; |
195 | } | 195 | } |
196 | if (!res) | 196 | if (!res || |
197 | (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN)) | ||
197 | res = azx_dev; | 198 | res = azx_dev; |
198 | } | 199 | } |
199 | dsp_unlock(azx_dev); | 200 | dsp_unlock(azx_dev); |
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 9d07e4edacdb..8b4940ba33d6 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c | |||
@@ -20,24 +20,71 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | #include <drm/i915_powerwell.h> | 22 | #include <drm/i915_powerwell.h> |
23 | #include "hda_priv.h" | ||
23 | #include "hda_i915.h" | 24 | #include "hda_i915.h" |
24 | 25 | ||
25 | static void (*get_power)(void); | 26 | /* Intel HSW/BDW display HDA controller Extended Mode registers. |
26 | static void (*put_power)(void); | 27 | * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display |
28 | * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N | ||
29 | * The values will be lost when the display power well is disabled. | ||
30 | */ | ||
31 | #define ICH6_REG_EM4 0x100c | ||
32 | #define ICH6_REG_EM5 0x1010 | ||
33 | |||
34 | static int (*get_power)(void); | ||
35 | static int (*put_power)(void); | ||
36 | static int (*get_cdclk)(void); | ||
27 | 37 | ||
28 | void hda_display_power(bool enable) | 38 | int hda_display_power(bool enable) |
29 | { | 39 | { |
30 | if (!get_power || !put_power) | 40 | if (!get_power || !put_power) |
31 | return; | 41 | return -ENODEV; |
32 | 42 | ||
33 | pr_debug("HDA display power %s \n", | 43 | pr_debug("HDA display power %s \n", |
34 | enable ? "Enable" : "Disable"); | 44 | enable ? "Enable" : "Disable"); |
35 | if (enable) | 45 | if (enable) |
36 | get_power(); | 46 | return get_power(); |
37 | else | 47 | else |
38 | put_power(); | 48 | return put_power(); |
49 | } | ||
50 | |||
51 | void haswell_set_bclk(struct azx *chip) | ||
52 | { | ||
53 | int cdclk_freq; | ||
54 | unsigned int bclk_m, bclk_n; | ||
55 | |||
56 | if (!get_cdclk) | ||
57 | return; | ||
58 | |||
59 | cdclk_freq = get_cdclk(); | ||
60 | switch (cdclk_freq) { | ||
61 | case 337500: | ||
62 | bclk_m = 16; | ||
63 | bclk_n = 225; | ||
64 | break; | ||
65 | |||
66 | case 450000: | ||
67 | default: /* default CDCLK 450MHz */ | ||
68 | bclk_m = 4; | ||
69 | bclk_n = 75; | ||
70 | break; | ||
71 | |||
72 | case 540000: | ||
73 | bclk_m = 4; | ||
74 | bclk_n = 90; | ||
75 | break; | ||
76 | |||
77 | case 675000: | ||
78 | bclk_m = 8; | ||
79 | bclk_n = 225; | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | azx_writew(chip, EM4, bclk_m); | ||
84 | azx_writew(chip, EM5, bclk_n); | ||
39 | } | 85 | } |
40 | 86 | ||
87 | |||
41 | int hda_i915_init(void) | 88 | int hda_i915_init(void) |
42 | { | 89 | { |
43 | int err = 0; | 90 | int err = 0; |
@@ -55,6 +102,10 @@ int hda_i915_init(void) | |||
55 | return -ENODEV; | 102 | return -ENODEV; |
56 | } | 103 | } |
57 | 104 | ||
105 | get_cdclk = symbol_request(i915_get_cdclk_freq); | ||
106 | if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ | ||
107 | pr_warn("hda-i915: get_cdclk symbol get fail\n"); | ||
108 | |||
58 | pr_debug("HDA driver get symbol successfully from i915 module\n"); | 109 | pr_debug("HDA driver get symbol successfully from i915 module\n"); |
59 | 110 | ||
60 | return err; | 111 | return err; |
@@ -70,6 +121,10 @@ int hda_i915_exit(void) | |||
70 | symbol_put(i915_release_power_well); | 121 | symbol_put(i915_release_power_well); |
71 | put_power = NULL; | 122 | put_power = NULL; |
72 | } | 123 | } |
124 | if (get_cdclk) { | ||
125 | symbol_put(i915_get_cdclk_freq); | ||
126 | get_cdclk = NULL; | ||
127 | } | ||
73 | 128 | ||
74 | return 0; | 129 | return 0; |
75 | } | 130 | } |
diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h index 5a63da2c53e5..e6072c627583 100644 --- a/sound/pci/hda/hda_i915.h +++ b/sound/pci/hda/hda_i915.h | |||
@@ -17,11 +17,13 @@ | |||
17 | #define __SOUND_HDA_I915_H | 17 | #define __SOUND_HDA_I915_H |
18 | 18 | ||
19 | #ifdef CONFIG_SND_HDA_I915 | 19 | #ifdef CONFIG_SND_HDA_I915 |
20 | void hda_display_power(bool enable); | 20 | int hda_display_power(bool enable); |
21 | void haswell_set_bclk(struct azx *chip); | ||
21 | int hda_i915_init(void); | 22 | int hda_i915_init(void); |
22 | int hda_i915_exit(void); | 23 | int hda_i915_exit(void); |
23 | #else | 24 | #else |
24 | static inline void hda_display_power(bool enable) {} | 25 | static inline int hda_display_power(bool enable) { return 0; } |
26 | static inline void haswell_set_bclk(struct azx *chip) { return; } | ||
25 | static inline int hda_i915_init(void) | 27 | static inline int hda_i915_init(void) |
26 | { | 28 | { |
27 | return -ENODEV; | 29 | return -ENODEV; |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bb65a124e006..83cd19017cf3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -62,9 +62,9 @@ | |||
62 | #include <linux/vga_switcheroo.h> | 62 | #include <linux/vga_switcheroo.h> |
63 | #include <linux/firmware.h> | 63 | #include <linux/firmware.h> |
64 | #include "hda_codec.h" | 64 | #include "hda_codec.h" |
65 | #include "hda_i915.h" | ||
66 | #include "hda_controller.h" | 65 | #include "hda_controller.h" |
67 | #include "hda_priv.h" | 66 | #include "hda_priv.h" |
67 | #include "hda_i915.h" | ||
68 | 68 | ||
69 | 69 | ||
70 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 70 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
@@ -227,7 +227,7 @@ enum { | |||
227 | /* quirks for Intel PCH */ | 227 | /* quirks for Intel PCH */ |
228 | #define AZX_DCAPS_INTEL_PCH_NOPM \ | 228 | #define AZX_DCAPS_INTEL_PCH_NOPM \ |
229 | (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ | 229 | (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ |
230 | AZX_DCAPS_COUNT_LPIB_DELAY) | 230 | AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_REVERSE_ASSIGN) |
231 | 231 | ||
232 | #define AZX_DCAPS_INTEL_PCH \ | 232 | #define AZX_DCAPS_INTEL_PCH \ |
233 | (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) | 233 | (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) |
@@ -288,6 +288,11 @@ static char *driver_short_names[] = { | |||
288 | [AZX_DRIVER_GENERIC] = "HD-Audio Generic", | 288 | [AZX_DRIVER_GENERIC] = "HD-Audio Generic", |
289 | }; | 289 | }; |
290 | 290 | ||
291 | struct hda_intel { | ||
292 | struct azx chip; | ||
293 | }; | ||
294 | |||
295 | |||
291 | #ifdef CONFIG_X86 | 296 | #ifdef CONFIG_X86 |
292 | static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) | 297 | static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) |
293 | { | 298 | { |
@@ -591,7 +596,7 @@ static int azx_suspend(struct device *dev) | |||
591 | struct azx *chip = card->private_data; | 596 | struct azx *chip = card->private_data; |
592 | struct azx_pcm *p; | 597 | struct azx_pcm *p; |
593 | 598 | ||
594 | if (chip->disabled) | 599 | if (chip->disabled || chip->init_failed) |
595 | return 0; | 600 | return 0; |
596 | 601 | ||
597 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 602 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
@@ -606,6 +611,7 @@ static int azx_suspend(struct device *dev) | |||
606 | free_irq(chip->irq, chip); | 611 | free_irq(chip->irq, chip); |
607 | chip->irq = -1; | 612 | chip->irq = -1; |
608 | } | 613 | } |
614 | |||
609 | if (chip->msi) | 615 | if (chip->msi) |
610 | pci_disable_msi(chip->pci); | 616 | pci_disable_msi(chip->pci); |
611 | pci_disable_device(pci); | 617 | pci_disable_device(pci); |
@@ -622,11 +628,13 @@ static int azx_resume(struct device *dev) | |||
622 | struct snd_card *card = dev_get_drvdata(dev); | 628 | struct snd_card *card = dev_get_drvdata(dev); |
623 | struct azx *chip = card->private_data; | 629 | struct azx *chip = card->private_data; |
624 | 630 | ||
625 | if (chip->disabled) | 631 | if (chip->disabled || chip->init_failed) |
626 | return 0; | 632 | return 0; |
627 | 633 | ||
628 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | 634 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
629 | hda_display_power(true); | 635 | hda_display_power(true); |
636 | haswell_set_bclk(chip); | ||
637 | } | ||
630 | pci_set_power_state(pci, PCI_D0); | 638 | pci_set_power_state(pci, PCI_D0); |
631 | pci_restore_state(pci); | 639 | pci_restore_state(pci); |
632 | if (pci_enable_device(pci) < 0) { | 640 | if (pci_enable_device(pci) < 0) { |
@@ -657,7 +665,7 @@ static int azx_runtime_suspend(struct device *dev) | |||
657 | struct snd_card *card = dev_get_drvdata(dev); | 665 | struct snd_card *card = dev_get_drvdata(dev); |
658 | struct azx *chip = card->private_data; | 666 | struct azx *chip = card->private_data; |
659 | 667 | ||
660 | if (chip->disabled) | 668 | if (chip->disabled || chip->init_failed) |
661 | return 0; | 669 | return 0; |
662 | 670 | ||
663 | if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) | 671 | if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) |
@@ -672,6 +680,7 @@ static int azx_runtime_suspend(struct device *dev) | |||
672 | azx_clear_irq_pending(chip); | 680 | azx_clear_irq_pending(chip); |
673 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | 681 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) |
674 | hda_display_power(false); | 682 | hda_display_power(false); |
683 | |||
675 | return 0; | 684 | return 0; |
676 | } | 685 | } |
677 | 686 | ||
@@ -683,14 +692,16 @@ static int azx_runtime_resume(struct device *dev) | |||
683 | struct hda_codec *codec; | 692 | struct hda_codec *codec; |
684 | int status; | 693 | int status; |
685 | 694 | ||
686 | if (chip->disabled) | 695 | if (chip->disabled || chip->init_failed) |
687 | return 0; | 696 | return 0; |
688 | 697 | ||
689 | if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) | 698 | if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) |
690 | return 0; | 699 | return 0; |
691 | 700 | ||
692 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | 701 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
693 | hda_display_power(true); | 702 | hda_display_power(true); |
703 | haswell_set_bclk(chip); | ||
704 | } | ||
694 | 705 | ||
695 | /* Read STATESTS before controller reset */ | 706 | /* Read STATESTS before controller reset */ |
696 | status = azx_readw(chip, STATESTS); | 707 | status = azx_readw(chip, STATESTS); |
@@ -718,7 +729,7 @@ static int azx_runtime_idle(struct device *dev) | |||
718 | struct snd_card *card = dev_get_drvdata(dev); | 729 | struct snd_card *card = dev_get_drvdata(dev); |
719 | struct azx *chip = card->private_data; | 730 | struct azx *chip = card->private_data; |
720 | 731 | ||
721 | if (chip->disabled) | 732 | if (chip->disabled || chip->init_failed) |
722 | return 0; | 733 | return 0; |
723 | 734 | ||
724 | if (!power_save_controller || | 735 | if (!power_save_controller || |
@@ -883,6 +894,8 @@ static int register_vga_switcheroo(struct azx *chip) | |||
883 | static int azx_free(struct azx *chip) | 894 | static int azx_free(struct azx *chip) |
884 | { | 895 | { |
885 | struct pci_dev *pci = chip->pci; | 896 | struct pci_dev *pci = chip->pci; |
897 | struct hda_intel *hda = container_of(chip, struct hda_intel, chip); | ||
898 | |||
886 | int i; | 899 | int i; |
887 | 900 | ||
888 | if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) | 901 | if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) |
@@ -930,7 +943,7 @@ static int azx_free(struct azx *chip) | |||
930 | hda_display_power(false); | 943 | hda_display_power(false); |
931 | hda_i915_exit(); | 944 | hda_i915_exit(); |
932 | } | 945 | } |
933 | kfree(chip); | 946 | kfree(hda); |
934 | 947 | ||
935 | return 0; | 948 | return 0; |
936 | } | 949 | } |
@@ -1174,6 +1187,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1174 | static struct snd_device_ops ops = { | 1187 | static struct snd_device_ops ops = { |
1175 | .dev_free = azx_dev_free, | 1188 | .dev_free = azx_dev_free, |
1176 | }; | 1189 | }; |
1190 | struct hda_intel *hda; | ||
1177 | struct azx *chip; | 1191 | struct azx *chip; |
1178 | int err; | 1192 | int err; |
1179 | 1193 | ||
@@ -1183,13 +1197,14 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1183 | if (err < 0) | 1197 | if (err < 0) |
1184 | return err; | 1198 | return err; |
1185 | 1199 | ||
1186 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1200 | hda = kzalloc(sizeof(*hda), GFP_KERNEL); |
1187 | if (!chip) { | 1201 | if (!hda) { |
1188 | dev_err(card->dev, "Cannot allocate chip\n"); | 1202 | dev_err(card->dev, "Cannot allocate hda\n"); |
1189 | pci_disable_device(pci); | 1203 | pci_disable_device(pci); |
1190 | return -ENOMEM; | 1204 | return -ENOMEM; |
1191 | } | 1205 | } |
1192 | 1206 | ||
1207 | chip = &hda->chip; | ||
1193 | spin_lock_init(&chip->reg_lock); | 1208 | spin_lock_init(&chip->reg_lock); |
1194 | mutex_init(&chip->open_mutex); | 1209 | mutex_init(&chip->open_mutex); |
1195 | chip->card = card; | 1210 | chip->card = card; |
@@ -1375,6 +1390,10 @@ static int azx_first_init(struct azx *chip) | |||
1375 | 1390 | ||
1376 | /* initialize chip */ | 1391 | /* initialize chip */ |
1377 | azx_init_pci(chip); | 1392 | azx_init_pci(chip); |
1393 | |||
1394 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | ||
1395 | haswell_set_bclk(chip); | ||
1396 | |||
1378 | azx_init_chip(chip, (probe_only[dev] & 2) == 0); | 1397 | azx_init_chip(chip, (probe_only[dev] & 2) == 0); |
1379 | 1398 | ||
1380 | /* codec detection */ | 1399 | /* codec detection */ |
@@ -1656,8 +1675,13 @@ static int azx_probe_continue(struct azx *chip) | |||
1656 | "Error request power-well from i915\n"); | 1675 | "Error request power-well from i915\n"); |
1657 | goto out_free; | 1676 | goto out_free; |
1658 | } | 1677 | } |
1678 | err = hda_display_power(true); | ||
1679 | if (err < 0) { | ||
1680 | dev_err(chip->card->dev, | ||
1681 | "Cannot turn on display power on i915\n"); | ||
1682 | goto out_free; | ||
1683 | } | ||
1659 | #endif | 1684 | #endif |
1660 | hda_display_power(true); | ||
1661 | } | 1685 | } |
1662 | 1686 | ||
1663 | err = azx_first_init(chip); | 1687 | err = azx_first_init(chip); |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index ebd1fa6f015c..4e2d4863daa1 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -417,6 +417,27 @@ struct snd_hda_pin_quirk { | |||
417 | int value; /* quirk value */ | 417 | int value; /* quirk value */ |
418 | }; | 418 | }; |
419 | 419 | ||
420 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
421 | |||
422 | #define SND_HDA_PIN_QUIRK(_codec, _subvendor, _name, _value, _pins...) \ | ||
423 | { .codec = _codec,\ | ||
424 | .subvendor = _subvendor,\ | ||
425 | .name = _name,\ | ||
426 | .value = _value,\ | ||
427 | .pins = (const struct hda_pintbl[]) { _pins } \ | ||
428 | } | ||
429 | #else | ||
430 | |||
431 | #define SND_HDA_PIN_QUIRK(_codec, _subvendor, _name, _value, _pins...) \ | ||
432 | { .codec = _codec,\ | ||
433 | .subvendor = _subvendor,\ | ||
434 | .value = _value,\ | ||
435 | .pins = (const struct hda_pintbl[]) { _pins } \ | ||
436 | } | ||
437 | |||
438 | #endif | ||
439 | |||
440 | |||
420 | /* fixup types */ | 441 | /* fixup types */ |
421 | enum { | 442 | enum { |
422 | HDA_FIXUP_INVALID, | 443 | HDA_FIXUP_INVALID, |
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 4a7cb01fa912..e9d1a5762a55 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h | |||
@@ -186,6 +186,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
186 | #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ | 186 | #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ |
187 | #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ | 187 | #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ |
188 | #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ | 188 | #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ |
189 | #define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ | ||
189 | #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ | 190 | #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ |
190 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ | 191 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ |
191 | #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ | 192 | #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ |
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index a366ba9293a8..358414da6418 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c | |||
@@ -236,6 +236,7 @@ disable_hda: | |||
236 | return rc; | 236 | return rc; |
237 | } | 237 | } |
238 | 238 | ||
239 | #ifdef CONFIG_PM_SLEEP | ||
239 | static void hda_tegra_disable_clocks(struct hda_tegra *data) | 240 | static void hda_tegra_disable_clocks(struct hda_tegra *data) |
240 | { | 241 | { |
241 | clk_disable_unprepare(data->hda2hdmi_clk); | 242 | clk_disable_unprepare(data->hda2hdmi_clk); |
@@ -243,7 +244,6 @@ static void hda_tegra_disable_clocks(struct hda_tegra *data) | |||
243 | clk_disable_unprepare(data->hda_clk); | 244 | clk_disable_unprepare(data->hda_clk); |
244 | } | 245 | } |
245 | 246 | ||
246 | #ifdef CONFIG_PM_SLEEP | ||
247 | /* | 247 | /* |
248 | * power management | 248 | * power management |
249 | */ | 249 | */ |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 3e4417b0ddbe..ba4ca52072ff 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -2204,7 +2204,7 @@ static int generic_hdmi_resume(struct hda_codec *codec) | |||
2204 | struct hdmi_spec *spec = codec->spec; | 2204 | struct hdmi_spec *spec = codec->spec; |
2205 | int pin_idx; | 2205 | int pin_idx; |
2206 | 2206 | ||
2207 | generic_hdmi_init(codec); | 2207 | codec->patch_ops.init(codec); |
2208 | snd_hda_codec_resume_amp(codec); | 2208 | snd_hda_codec_resume_amp(codec); |
2209 | snd_hda_codec_resume_cache(codec); | 2209 | snd_hda_codec_resume_cache(codec); |
2210 | 2210 | ||
@@ -3337,6 +3337,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { | |||
3337 | { .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi }, | 3337 | { .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi }, |
3338 | { .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi }, | 3338 | { .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi }, |
3339 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, | 3339 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, |
3340 | { .id = 0x10de0070, .name = "GPU 70 HDMI/DP", .patch = patch_nvhdmi }, | ||
3340 | { .id = 0x10de0071, .name = "GPU 71 HDMI/DP", .patch = patch_nvhdmi }, | 3341 | { .id = 0x10de0071, .name = "GPU 71 HDMI/DP", .patch = patch_nvhdmi }, |
3341 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, | 3342 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, |
3342 | { .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, | 3343 | { .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, |
@@ -3394,6 +3395,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0044"); | |||
3394 | MODULE_ALIAS("snd-hda-codec-id:10de0051"); | 3395 | MODULE_ALIAS("snd-hda-codec-id:10de0051"); |
3395 | MODULE_ALIAS("snd-hda-codec-id:10de0060"); | 3396 | MODULE_ALIAS("snd-hda-codec-id:10de0060"); |
3396 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); | 3397 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); |
3398 | MODULE_ALIAS("snd-hda-codec-id:10de0070"); | ||
3397 | MODULE_ALIAS("snd-hda-codec-id:10de0071"); | 3399 | MODULE_ALIAS("snd-hda-codec-id:10de0071"); |
3398 | MODULE_ALIAS("snd-hda-codec-id:10de8001"); | 3400 | MODULE_ALIAS("snd-hda-codec-id:10de8001"); |
3399 | MODULE_ALIAS("snd-hda-codec-id:11069f80"); | 3401 | MODULE_ALIAS("snd-hda-codec-id:11069f80"); |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index af76995fa966..b60824e90408 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -4880,6 +4880,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4880 | SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), | 4880 | SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), |
4881 | SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), | 4881 | SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), |
4882 | SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), | 4882 | SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), |
4883 | SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), | ||
4883 | SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4884 | SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
4884 | SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4885 | SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
4885 | SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4886 | SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
@@ -4962,228 +4963,141 @@ static const struct hda_model_fixup alc269_fixup_models[] = { | |||
4962 | }; | 4963 | }; |
4963 | 4964 | ||
4964 | static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | 4965 | static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { |
4965 | { | 4966 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
4966 | .codec = 0x10ec0255, | 4967 | {0x12, 0x90a60140}, |
4967 | .subvendor = 0x1028, | 4968 | {0x14, 0x90170110}, |
4968 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 4969 | {0x17, 0x40000000}, |
4969 | .name = "Dell", | 4970 | {0x18, 0x411111f0}, |
4970 | #endif | 4971 | {0x19, 0x411111f0}, |
4971 | .pins = (const struct hda_pintbl[]) { | 4972 | {0x1a, 0x411111f0}, |
4972 | {0x12, 0x90a60140}, | 4973 | {0x1b, 0x411111f0}, |
4973 | {0x14, 0x90170110}, | 4974 | {0x1d, 0x40700001}, |
4974 | {0x17, 0x40000000}, | 4975 | {0x1e, 0x411111f0}, |
4975 | {0x18, 0x411111f0}, | 4976 | {0x21, 0x02211020}), |
4976 | {0x19, 0x411111f0}, | 4977 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
4977 | {0x1a, 0x411111f0}, | 4978 | {0x12, 0x90a60160}, |
4978 | {0x1b, 0x411111f0}, | 4979 | {0x14, 0x90170120}, |
4979 | {0x1d, 0x40700001}, | 4980 | {0x17, 0x40000000}, |
4980 | {0x1e, 0x411111f0}, | 4981 | {0x18, 0x411111f0}, |
4981 | {0x21, 0x02211020}, | 4982 | {0x19, 0x411111f0}, |
4982 | }, | 4983 | {0x1a, 0x411111f0}, |
4983 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 4984 | {0x1b, 0x411111f0}, |
4984 | }, | 4985 | {0x1d, 0x40700001}, |
4985 | { | 4986 | {0x1e, 0x411111f0}, |
4986 | .codec = 0x10ec0255, | 4987 | {0x21, 0x02211030}), |
4987 | .subvendor = 0x1028, | 4988 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
4988 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 4989 | {0x12, 0x90a60160}, |
4989 | .name = "Dell", | 4990 | {0x14, 0x90170120}, |
4990 | #endif | 4991 | {0x17, 0x90170140}, |
4991 | .pins = (const struct hda_pintbl[]) { | 4992 | {0x18, 0x40000000}, |
4992 | {0x12, 0x90a60160}, | 4993 | {0x19, 0x411111f0}, |
4993 | {0x14, 0x90170120}, | 4994 | {0x1a, 0x411111f0}, |
4994 | {0x17, 0x40000000}, | 4995 | {0x1b, 0x411111f0}, |
4995 | {0x18, 0x411111f0}, | 4996 | {0x1d, 0x41163b05}, |
4996 | {0x19, 0x411111f0}, | 4997 | {0x1e, 0x411111f0}, |
4997 | {0x1a, 0x411111f0}, | 4998 | {0x21, 0x0321102f}), |
4998 | {0x1b, 0x411111f0}, | 4999 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
4999 | {0x1d, 0x40700001}, | 5000 | {0x12, 0x90a60160}, |
5000 | {0x1e, 0x411111f0}, | 5001 | {0x14, 0x90170130}, |
5001 | {0x21, 0x02211030}, | 5002 | {0x17, 0x40000000}, |
5002 | }, | 5003 | {0x18, 0x411111f0}, |
5003 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5004 | {0x19, 0x411111f0}, |
5004 | }, | 5005 | {0x1a, 0x411111f0}, |
5005 | { | 5006 | {0x1b, 0x411111f0}, |
5006 | .codec = 0x10ec0255, | 5007 | {0x1d, 0x40700001}, |
5007 | .subvendor = 0x1028, | 5008 | {0x1e, 0x411111f0}, |
5008 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5009 | {0x21, 0x02211040}), |
5009 | .name = "Dell", | 5010 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
5010 | #endif | 5011 | {0x12, 0x90a60160}, |
5011 | .pins = (const struct hda_pintbl[]) { | 5012 | {0x14, 0x90170140}, |
5012 | {0x12, 0x90a60160}, | 5013 | {0x17, 0x40000000}, |
5013 | {0x14, 0x90170120}, | 5014 | {0x18, 0x411111f0}, |
5014 | {0x17, 0x90170140}, | 5015 | {0x19, 0x411111f0}, |
5015 | {0x18, 0x40000000}, | 5016 | {0x1a, 0x411111f0}, |
5016 | {0x19, 0x411111f0}, | 5017 | {0x1b, 0x411111f0}, |
5017 | {0x1a, 0x411111f0}, | 5018 | {0x1d, 0x40700001}, |
5018 | {0x1b, 0x411111f0}, | 5019 | {0x1e, 0x411111f0}, |
5019 | {0x1d, 0x41163b05}, | 5020 | {0x21, 0x02211050}), |
5020 | {0x1e, 0x411111f0}, | 5021 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
5021 | {0x21, 0x0321102f}, | 5022 | {0x12, 0x90a60170}, |
5022 | }, | 5023 | {0x14, 0x90170120}, |
5023 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5024 | {0x17, 0x40000000}, |
5024 | }, | 5025 | {0x18, 0x411111f0}, |
5025 | { | 5026 | {0x19, 0x411111f0}, |
5026 | .codec = 0x10ec0255, | 5027 | {0x1a, 0x411111f0}, |
5027 | .subvendor = 0x1028, | 5028 | {0x1b, 0x411111f0}, |
5028 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5029 | {0x1d, 0x40700001}, |
5029 | .name = "Dell", | 5030 | {0x1e, 0x411111f0}, |
5030 | #endif | 5031 | {0x21, 0x02211030}), |
5031 | .pins = (const struct hda_pintbl[]) { | 5032 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
5032 | {0x12, 0x90a60160}, | 5033 | {0x12, 0x90a60170}, |
5033 | {0x14, 0x90170130}, | 5034 | {0x14, 0x90170130}, |
5034 | {0x17, 0x40000000}, | 5035 | {0x17, 0x40000000}, |
5035 | {0x18, 0x411111f0}, | 5036 | {0x18, 0x411111f0}, |
5036 | {0x19, 0x411111f0}, | 5037 | {0x19, 0x411111f0}, |
5037 | {0x1a, 0x411111f0}, | 5038 | {0x1a, 0x411111f0}, |
5038 | {0x1b, 0x411111f0}, | 5039 | {0x1b, 0x411111f0}, |
5039 | {0x1d, 0x40700001}, | 5040 | {0x1d, 0x40700001}, |
5040 | {0x1e, 0x411111f0}, | 5041 | {0x1e, 0x411111f0}, |
5041 | {0x21, 0x02211040}, | 5042 | {0x21, 0x02211040}), |
5042 | }, | 5043 | SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, |
5043 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5044 | {0x12, 0x90a60130}, |
5044 | }, | 5045 | {0x14, 0x90170110}, |
5045 | { | 5046 | {0x17, 0x40020008}, |
5046 | .codec = 0x10ec0255, | 5047 | {0x18, 0x411111f0}, |
5047 | .subvendor = 0x1028, | 5048 | {0x19, 0x411111f0}, |
5048 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5049 | {0x1a, 0x411111f0}, |
5049 | .name = "Dell", | 5050 | {0x1b, 0x411111f0}, |
5050 | #endif | 5051 | {0x1d, 0x40e00001}, |
5051 | .pins = (const struct hda_pintbl[]) { | 5052 | {0x1e, 0x411111f0}, |
5052 | {0x12, 0x90a60160}, | 5053 | {0x21, 0x0321101f}), |
5053 | {0x14, 0x90170140}, | 5054 | SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, |
5054 | {0x17, 0x40000000}, | 5055 | {0x12, 0x90a60160}, |
5055 | {0x18, 0x411111f0}, | 5056 | {0x14, 0x90170120}, |
5056 | {0x19, 0x411111f0}, | 5057 | {0x17, 0x40000000}, |
5057 | {0x1a, 0x411111f0}, | 5058 | {0x18, 0x411111f0}, |
5058 | {0x1b, 0x411111f0}, | 5059 | {0x19, 0x411111f0}, |
5059 | {0x1d, 0x40700001}, | 5060 | {0x1a, 0x411111f0}, |
5060 | {0x1e, 0x411111f0}, | 5061 | {0x1b, 0x411111f0}, |
5061 | {0x21, 0x02211050}, | 5062 | {0x1d, 0x40700001}, |
5062 | }, | 5063 | {0x1e, 0x411111f0}, |
5063 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5064 | {0x21, 0x02211030}), |
5064 | }, | 5065 | SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, |
5065 | { | 5066 | {0x12, 0x90a60140}, |
5066 | .codec = 0x10ec0255, | 5067 | {0x13, 0x411111f0}, |
5067 | .subvendor = 0x1028, | 5068 | {0x14, 0x90170110}, |
5068 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5069 | {0x15, 0x0221401f}, |
5069 | .name = "Dell", | 5070 | {0x16, 0x411111f0}, |
5070 | #endif | 5071 | {0x18, 0x411111f0}, |
5071 | .pins = (const struct hda_pintbl[]) { | 5072 | {0x19, 0x411111f0}, |
5072 | {0x12, 0x90a60170}, | 5073 | {0x1a, 0x411111f0}, |
5073 | {0x14, 0x90170120}, | 5074 | {0x1b, 0x411111f0}, |
5074 | {0x17, 0x40000000}, | 5075 | {0x1d, 0x40700001}, |
5075 | {0x18, 0x411111f0}, | 5076 | {0x1e, 0x411111f0}), |
5076 | {0x19, 0x411111f0}, | 5077 | SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, |
5077 | {0x1a, 0x411111f0}, | 5078 | {0x12, 0x40000000}, |
5078 | {0x1b, 0x411111f0}, | 5079 | {0x13, 0x90a60140}, |
5079 | {0x1d, 0x40700001}, | 5080 | {0x14, 0x90170110}, |
5080 | {0x1e, 0x411111f0}, | 5081 | {0x15, 0x0221401f}, |
5081 | {0x21, 0x02211030}, | 5082 | {0x16, 0x21014020}, |
5082 | }, | 5083 | {0x18, 0x411111f0}, |
5083 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5084 | {0x19, 0x21a19030}, |
5084 | }, | 5085 | {0x1a, 0x411111f0}, |
5085 | { | 5086 | {0x1b, 0x411111f0}, |
5086 | .codec = 0x10ec0255, | 5087 | {0x1d, 0x40700001}, |
5087 | .subvendor = 0x1028, | 5088 | {0x1e, 0x411111f0}), |
5088 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5089 | SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, |
5089 | .name = "Dell", | 5090 | {0x12, 0x40000000}, |
5090 | #endif | 5091 | {0x13, 0x90a60140}, |
5091 | .pins = (const struct hda_pintbl[]) { | 5092 | {0x14, 0x90170110}, |
5092 | {0x12, 0x90a60170}, | 5093 | {0x15, 0x0221401f}, |
5093 | {0x14, 0x90170130}, | 5094 | {0x16, 0x411111f0}, |
5094 | {0x17, 0x40000000}, | 5095 | {0x18, 0x411111f0}, |
5095 | {0x18, 0x411111f0}, | 5096 | {0x19, 0x411111f0}, |
5096 | {0x19, 0x411111f0}, | 5097 | {0x1a, 0x411111f0}, |
5097 | {0x1a, 0x411111f0}, | 5098 | {0x1b, 0x411111f0}, |
5098 | {0x1b, 0x411111f0}, | 5099 | {0x1d, 0x40700001}, |
5099 | {0x1d, 0x40700001}, | 5100 | {0x1e, 0x411111f0}), |
5100 | {0x1e, 0x411111f0}, | ||
5101 | {0x21, 0x02211040}, | ||
5102 | }, | ||
5103 | .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5104 | }, | ||
5105 | { | ||
5106 | .codec = 0x10ec0283, | ||
5107 | .subvendor = 0x1028, | ||
5108 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
5109 | .name = "Dell", | ||
5110 | #endif | ||
5111 | .pins = (const struct hda_pintbl[]) { | ||
5112 | {0x12, 0x90a60130}, | ||
5113 | {0x14, 0x90170110}, | ||
5114 | {0x17, 0x40020008}, | ||
5115 | {0x18, 0x411111f0}, | ||
5116 | {0x19, 0x411111f0}, | ||
5117 | {0x1a, 0x411111f0}, | ||
5118 | {0x1b, 0x411111f0}, | ||
5119 | {0x1d, 0x40e00001}, | ||
5120 | {0x1e, 0x411111f0}, | ||
5121 | {0x21, 0x0321101f}, | ||
5122 | }, | ||
5123 | .value = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5124 | }, | ||
5125 | { | ||
5126 | .codec = 0x10ec0283, | ||
5127 | .subvendor = 0x1028, | ||
5128 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
5129 | .name = "Dell", | ||
5130 | #endif | ||
5131 | .pins = (const struct hda_pintbl[]) { | ||
5132 | {0x12, 0x90a60160}, | ||
5133 | {0x14, 0x90170120}, | ||
5134 | {0x17, 0x40000000}, | ||
5135 | {0x18, 0x411111f0}, | ||
5136 | {0x19, 0x411111f0}, | ||
5137 | {0x1a, 0x411111f0}, | ||
5138 | {0x1b, 0x411111f0}, | ||
5139 | {0x1d, 0x40700001}, | ||
5140 | {0x1e, 0x411111f0}, | ||
5141 | {0x21, 0x02211030}, | ||
5142 | }, | ||
5143 | .value = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5144 | }, | ||
5145 | { | ||
5146 | .codec = 0x10ec0292, | ||
5147 | .subvendor = 0x1028, | ||
5148 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
5149 | .name = "Dell", | ||
5150 | #endif | ||
5151 | .pins = (const struct hda_pintbl[]) { | ||
5152 | {0x12, 0x90a60140}, | ||
5153 | {0x13, 0x411111f0}, | ||
5154 | {0x14, 0x90170110}, | ||
5155 | {0x15, 0x0221401f}, | ||
5156 | {0x16, 0x411111f0}, | ||
5157 | {0x18, 0x411111f0}, | ||
5158 | {0x19, 0x411111f0}, | ||
5159 | {0x1a, 0x411111f0}, | ||
5160 | {0x1b, 0x411111f0}, | ||
5161 | {0x1d, 0x40700001}, | ||
5162 | {0x1e, 0x411111f0}, | ||
5163 | }, | ||
5164 | .value = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, | ||
5165 | }, | ||
5166 | { | ||
5167 | .codec = 0x10ec0293, | ||
5168 | .subvendor = 0x1028, | ||
5169 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
5170 | .name = "Dell", | ||
5171 | #endif | ||
5172 | .pins = (const struct hda_pintbl[]) { | ||
5173 | {0x12, 0x40000000}, | ||
5174 | {0x13, 0x90a60140}, | ||
5175 | {0x14, 0x90170110}, | ||
5176 | {0x15, 0x0221401f}, | ||
5177 | {0x16, 0x21014020}, | ||
5178 | {0x18, 0x411111f0}, | ||
5179 | {0x19, 0x21a19030}, | ||
5180 | {0x1a, 0x411111f0}, | ||
5181 | {0x1b, 0x411111f0}, | ||
5182 | {0x1d, 0x40700001}, | ||
5183 | {0x1e, 0x411111f0}, | ||
5184 | }, | ||
5185 | .value = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5186 | }, | ||
5187 | {} | 5101 | {} |
5188 | }; | 5102 | }; |
5189 | 5103 | ||
@@ -6039,90 +5953,66 @@ static const struct hda_model_fixup alc662_fixup_models[] = { | |||
6039 | }; | 5953 | }; |
6040 | 5954 | ||
6041 | static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { | 5955 | static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { |
6042 | { | 5956 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, |
6043 | .codec = 0x10ec0668, | 5957 | {0x12, 0x99a30130}, |
6044 | .subvendor = 0x1028, | 5958 | {0x14, 0x90170110}, |
6045 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5959 | {0x15, 0x0321101f}, |
6046 | .name = "Dell", | 5960 | {0x16, 0x03011020}, |
6047 | #endif | 5961 | {0x18, 0x40000008}, |
6048 | .pins = (const struct hda_pintbl[]) { | 5962 | {0x19, 0x411111f0}, |
6049 | {0x12, 0x99a30130}, | 5963 | {0x1a, 0x411111f0}, |
6050 | {0x14, 0x90170110}, | 5964 | {0x1b, 0x411111f0}, |
6051 | {0x15, 0x0321101f}, | 5965 | {0x1d, 0x41000001}, |
6052 | {0x16, 0x03011020}, | 5966 | {0x1e, 0x411111f0}, |
6053 | {0x18, 0x40000008}, | 5967 | {0x1f, 0x411111f0}), |
6054 | {0x19, 0x411111f0}, | 5968 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, |
6055 | {0x1a, 0x411111f0}, | 5969 | {0x12, 0x99a30140}, |
6056 | {0x1b, 0x411111f0}, | 5970 | {0x14, 0x90170110}, |
6057 | {0x1d, 0x41000001}, | 5971 | {0x15, 0x0321101f}, |
6058 | {0x1e, 0x411111f0}, | 5972 | {0x16, 0x03011020}, |
6059 | {0x1f, 0x411111f0}, | 5973 | {0x18, 0x40000008}, |
6060 | }, | 5974 | {0x19, 0x411111f0}, |
6061 | .value = ALC668_FIXUP_AUTO_MUTE, | 5975 | {0x1a, 0x411111f0}, |
6062 | }, | 5976 | {0x1b, 0x411111f0}, |
6063 | { | 5977 | {0x1d, 0x41000001}, |
6064 | .codec = 0x10ec0668, | 5978 | {0x1e, 0x411111f0}, |
6065 | .subvendor = 0x1028, | 5979 | {0x1f, 0x411111f0}), |
6066 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 5980 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, |
6067 | .name = "Dell", | 5981 | {0x12, 0x99a30150}, |
6068 | #endif | 5982 | {0x14, 0x90170110}, |
6069 | .pins = (const struct hda_pintbl[]) { | 5983 | {0x15, 0x0321101f}, |
6070 | {0x12, 0x99a30140}, | 5984 | {0x16, 0x03011020}, |
6071 | {0x14, 0x90170110}, | 5985 | {0x18, 0x40000008}, |
6072 | {0x15, 0x0321101f}, | 5986 | {0x19, 0x411111f0}, |
6073 | {0x16, 0x03011020}, | 5987 | {0x1a, 0x411111f0}, |
6074 | {0x18, 0x40000008}, | 5988 | {0x1b, 0x411111f0}, |
6075 | {0x19, 0x411111f0}, | 5989 | {0x1d, 0x41000001}, |
6076 | {0x1a, 0x411111f0}, | 5990 | {0x1e, 0x411111f0}, |
6077 | {0x1b, 0x411111f0}, | 5991 | {0x1f, 0x411111f0}), |
6078 | {0x1d, 0x41000001}, | 5992 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, |
6079 | {0x1e, 0x411111f0}, | 5993 | {0x12, 0x411111f0}, |
6080 | {0x1f, 0x411111f0}, | 5994 | {0x14, 0x90170110}, |
6081 | }, | 5995 | {0x15, 0x0321101f}, |
6082 | .value = ALC668_FIXUP_AUTO_MUTE, | 5996 | {0x16, 0x03011020}, |
6083 | }, | 5997 | {0x18, 0x40000008}, |
6084 | { | 5998 | {0x19, 0x411111f0}, |
6085 | .codec = 0x10ec0668, | 5999 | {0x1a, 0x411111f0}, |
6086 | .subvendor = 0x1028, | 6000 | {0x1b, 0x411111f0}, |
6087 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 6001 | {0x1d, 0x41000001}, |
6088 | .name = "Dell", | 6002 | {0x1e, 0x411111f0}, |
6089 | #endif | 6003 | {0x1f, 0x411111f0}), |
6090 | .pins = (const struct hda_pintbl[]) { | 6004 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE, |
6091 | {0x12, 0x99a30150}, | 6005 | {0x12, 0x90a60130}, |
6092 | {0x14, 0x90170110}, | 6006 | {0x14, 0x90170110}, |
6093 | {0x15, 0x0321101f}, | 6007 | {0x15, 0x0321101f}, |
6094 | {0x16, 0x03011020}, | 6008 | {0x16, 0x40000000}, |
6095 | {0x18, 0x40000008}, | 6009 | {0x18, 0x411111f0}, |
6096 | {0x19, 0x411111f0}, | 6010 | {0x19, 0x411111f0}, |
6097 | {0x1a, 0x411111f0}, | 6011 | {0x1a, 0x411111f0}, |
6098 | {0x1b, 0x411111f0}, | 6012 | {0x1b, 0x411111f0}, |
6099 | {0x1d, 0x41000001}, | 6013 | {0x1d, 0x40d6832d}, |
6100 | {0x1e, 0x411111f0}, | 6014 | {0x1e, 0x411111f0}, |
6101 | {0x1f, 0x411111f0}, | 6015 | {0x1f, 0x411111f0}), |
6102 | }, | ||
6103 | .value = ALC668_FIXUP_AUTO_MUTE, | ||
6104 | }, | ||
6105 | { | ||
6106 | .codec = 0x10ec0668, | ||
6107 | .subvendor = 0x1028, | ||
6108 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
6109 | .name = "Dell", | ||
6110 | #endif | ||
6111 | .pins = (const struct hda_pintbl[]) { | ||
6112 | {0x12, 0x411111f0}, | ||
6113 | {0x14, 0x90170110}, | ||
6114 | {0x15, 0x0321101f}, | ||
6115 | {0x16, 0x03011020}, | ||
6116 | {0x18, 0x40000008}, | ||
6117 | {0x19, 0x411111f0}, | ||
6118 | {0x1a, 0x411111f0}, | ||
6119 | {0x1b, 0x411111f0}, | ||
6120 | {0x1d, 0x41000001}, | ||
6121 | {0x1e, 0x411111f0}, | ||
6122 | {0x1f, 0x411111f0}, | ||
6123 | }, | ||
6124 | .value = ALC668_FIXUP_AUTO_MUTE, | ||
6125 | }, | ||
6126 | {} | 6016 | {} |
6127 | }; | 6017 | }; |
6128 | 6018 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7f40a150899c..3744ea4e843d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -122,6 +122,12 @@ enum { | |||
122 | }; | 122 | }; |
123 | 123 | ||
124 | enum { | 124 | enum { |
125 | STAC_92HD95_HP_LED, | ||
126 | STAC_92HD95_HP_BASS, | ||
127 | STAC_92HD95_MODELS | ||
128 | }; | ||
129 | |||
130 | enum { | ||
125 | STAC_925x_REF, | 131 | STAC_925x_REF, |
126 | STAC_M1, | 132 | STAC_M1, |
127 | STAC_M1_2, | 133 | STAC_M1_2, |
@@ -4128,6 +4134,48 @@ static const struct snd_pci_quirk stac9205_fixup_tbl[] = { | |||
4128 | {} /* terminator */ | 4134 | {} /* terminator */ |
4129 | }; | 4135 | }; |
4130 | 4136 | ||
4137 | static void stac92hd95_fixup_hp_led(struct hda_codec *codec, | ||
4138 | const struct hda_fixup *fix, int action) | ||
4139 | { | ||
4140 | struct sigmatel_spec *spec = codec->spec; | ||
4141 | |||
4142 | if (action != HDA_FIXUP_ACT_PRE_PROBE) | ||
4143 | return; | ||
4144 | |||
4145 | if (find_mute_led_cfg(codec, spec->default_polarity)) | ||
4146 | codec_dbg(codec, "mute LED gpio %d polarity %d\n", | ||
4147 | spec->gpio_led, | ||
4148 | spec->gpio_led_polarity); | ||
4149 | } | ||
4150 | |||
4151 | static const struct hda_fixup stac92hd95_fixups[] = { | ||
4152 | [STAC_92HD95_HP_LED] = { | ||
4153 | .type = HDA_FIXUP_FUNC, | ||
4154 | .v.func = stac92hd95_fixup_hp_led, | ||
4155 | }, | ||
4156 | [STAC_92HD95_HP_BASS] = { | ||
4157 | .type = HDA_FIXUP_VERBS, | ||
4158 | .v.verbs = (const struct hda_verb[]) { | ||
4159 | {0x1a, 0x795, 0x00}, /* HPF to 100Hz */ | ||
4160 | {} | ||
4161 | }, | ||
4162 | .chained = true, | ||
4163 | .chain_id = STAC_92HD95_HP_LED, | ||
4164 | }, | ||
4165 | }; | ||
4166 | |||
4167 | static const struct snd_pci_quirk stac92hd95_fixup_tbl[] = { | ||
4168 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS), | ||
4169 | {} /* terminator */ | ||
4170 | }; | ||
4171 | |||
4172 | static const struct hda_model_fixup stac92hd95_models[] = { | ||
4173 | { .id = STAC_92HD95_HP_LED, .name = "hp-led" }, | ||
4174 | { .id = STAC_92HD95_HP_BASS, .name = "hp-bass" }, | ||
4175 | {} | ||
4176 | }; | ||
4177 | |||
4178 | |||
4131 | static int stac_parse_auto_config(struct hda_codec *codec) | 4179 | static int stac_parse_auto_config(struct hda_codec *codec) |
4132 | { | 4180 | { |
4133 | struct sigmatel_spec *spec = codec->spec; | 4181 | struct sigmatel_spec *spec = codec->spec; |
@@ -4580,10 +4628,16 @@ static int patch_stac92hd95(struct hda_codec *codec) | |||
4580 | spec->gen.beep_nid = 0x19; /* digital beep */ | 4628 | spec->gen.beep_nid = 0x19; /* digital beep */ |
4581 | spec->pwr_nids = stac92hd95_pwr_nids; | 4629 | spec->pwr_nids = stac92hd95_pwr_nids; |
4582 | spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids); | 4630 | spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids); |
4583 | spec->default_polarity = -1; /* no default cfg */ | 4631 | spec->default_polarity = 0; |
4584 | 4632 | ||
4585 | codec->patch_ops = stac_patch_ops; | 4633 | codec->patch_ops = stac_patch_ops; |
4586 | 4634 | ||
4635 | snd_hda_pick_fixup(codec, stac92hd95_models, stac92hd95_fixup_tbl, | ||
4636 | stac92hd95_fixups); | ||
4637 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | ||
4638 | |||
4639 | stac_setup_gpio(codec); | ||
4640 | |||
4587 | err = stac_parse_auto_config(codec); | 4641 | err = stac_parse_auto_config(codec); |
4588 | if (err < 0) { | 4642 | if (err < 0) { |
4589 | stac_free(codec); | 4643 | stac_free(codec); |
@@ -4592,6 +4646,8 @@ static int patch_stac92hd95(struct hda_codec *codec) | |||
4592 | 4646 | ||
4593 | codec->proc_widget_hook = stac92hd_proc_hook; | 4647 | codec->proc_widget_hook = stac92hd_proc_hook; |
4594 | 4648 | ||
4649 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
4650 | |||
4595 | return 0; | 4651 | return 0; |
4596 | } | 4652 | } |
4597 | 4653 | ||
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index de433cfd044c..f403f399808a 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -347,6 +347,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
347 | u32 tfmr, rfmr, tcmr, rcmr; | 347 | u32 tfmr, rfmr, tcmr, rcmr; |
348 | int start_event; | 348 | int start_event; |
349 | int ret; | 349 | int ret; |
350 | int fslen, fslen_ext; | ||
350 | 351 | ||
351 | /* | 352 | /* |
352 | * Currently, there is only one set of dma params for | 353 | * Currently, there is only one set of dma params for |
@@ -388,18 +389,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
388 | } | 389 | } |
389 | 390 | ||
390 | /* | 391 | /* |
391 | * The SSC only supports up to 16-bit samples in I2S format, due | ||
392 | * to the size of the Frame Mode Register FSLEN field. | ||
393 | */ | ||
394 | if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S | ||
395 | && bits > 16) { | ||
396 | printk(KERN_WARNING | ||
397 | "atmel_ssc_dai: sample size %d " | ||
398 | "is too large for I2S\n", bits); | ||
399 | return -EINVAL; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Compute SSC register settings. | 392 | * Compute SSC register settings. |
404 | */ | 393 | */ |
405 | switch (ssc_p->daifmt | 394 | switch (ssc_p->daifmt |
@@ -413,6 +402,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
413 | * from the MCK divider, and the BCLK signal | 402 | * from the MCK divider, and the BCLK signal |
414 | * is output on the SSC TK line. | 403 | * is output on the SSC TK line. |
415 | */ | 404 | */ |
405 | |||
406 | if (bits > 16 && !ssc->pdata->has_fslen_ext) { | ||
407 | dev_err(dai->dev, | ||
408 | "sample size %d is too large for SSC device\n", | ||
409 | bits); | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | fslen_ext = (bits - 1) / 16; | ||
414 | fslen = (bits - 1) % 16; | ||
415 | |||
416 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | 416 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
417 | | SSC_BF(RCMR_STTDLY, START_DELAY) | 417 | | SSC_BF(RCMR_STTDLY, START_DELAY) |
418 | | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | 418 | | SSC_BF(RCMR_START, SSC_START_FALLING_RF) |
@@ -420,9 +420,10 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
420 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 420 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
421 | | SSC_BF(RCMR_CKS, SSC_CKS_DIV); | 421 | | SSC_BF(RCMR_CKS, SSC_CKS_DIV); |
422 | 422 | ||
423 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 423 | rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) |
424 | | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | ||
424 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | 425 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) |
425 | | SSC_BF(RFMR_FSLEN, (bits - 1)) | 426 | | SSC_BF(RFMR_FSLEN, fslen) |
426 | | SSC_BF(RFMR_DATNB, (channels - 1)) | 427 | | SSC_BF(RFMR_DATNB, (channels - 1)) |
427 | | SSC_BIT(RFMR_MSBF) | 428 | | SSC_BIT(RFMR_MSBF) |
428 | | SSC_BF(RFMR_LOOP, 0) | 429 | | SSC_BF(RFMR_LOOP, 0) |
@@ -435,10 +436,11 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
435 | | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | 436 | | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
436 | | SSC_BF(TCMR_CKS, SSC_CKS_DIV); | 437 | | SSC_BF(TCMR_CKS, SSC_CKS_DIV); |
437 | 438 | ||
438 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 439 | tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) |
440 | | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | ||
439 | | SSC_BF(TFMR_FSDEN, 0) | 441 | | SSC_BF(TFMR_FSDEN, 0) |
440 | | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | 442 | | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) |
441 | | SSC_BF(TFMR_FSLEN, (bits - 1)) | 443 | | SSC_BF(TFMR_FSLEN, fslen) |
442 | | SSC_BF(TFMR_DATNB, (channels - 1)) | 444 | | SSC_BF(TFMR_DATNB, (channels - 1)) |
443 | | SSC_BIT(TFMR_MSBF) | 445 | | SSC_BIT(TFMR_MSBF) |
444 | | SSC_BF(TFMR_DATDEF, 0) | 446 | | SSC_BF(TFMR_DATDEF, 0) |
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index b4e36901a40b..4052268ce462 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c | |||
@@ -18,10 +18,6 @@ | |||
18 | #include "../codecs/wm8904.h" | 18 | #include "../codecs/wm8904.h" |
19 | #include "atmel_ssc_dai.h" | 19 | #include "atmel_ssc_dai.h" |
20 | 20 | ||
21 | #define MCLK_RATE 32768 | ||
22 | |||
23 | static struct clk *mclk; | ||
24 | |||
25 | static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = { | 21 | static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = { |
26 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 22 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
27 | SND_SOC_DAPM_MIC("Mic", NULL), | 23 | SND_SOC_DAPM_MIC("Mic", NULL), |
@@ -61,26 +57,6 @@ static struct snd_soc_ops atmel_asoc_wm8904_ops = { | |||
61 | .hw_params = atmel_asoc_wm8904_hw_params, | 57 | .hw_params = atmel_asoc_wm8904_hw_params, |
62 | }; | 58 | }; |
63 | 59 | ||
64 | static int atmel_set_bias_level(struct snd_soc_card *card, | ||
65 | struct snd_soc_dapm_context *dapm, | ||
66 | enum snd_soc_bias_level level) | ||
67 | { | ||
68 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { | ||
69 | switch (level) { | ||
70 | case SND_SOC_BIAS_PREPARE: | ||
71 | clk_prepare_enable(mclk); | ||
72 | break; | ||
73 | case SND_SOC_BIAS_OFF: | ||
74 | clk_disable_unprepare(mclk); | ||
75 | break; | ||
76 | default: | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | }; | ||
83 | |||
84 | static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { | 60 | static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { |
85 | .name = "WM8904", | 61 | .name = "WM8904", |
86 | .stream_name = "WM8904 PCM", | 62 | .stream_name = "WM8904 PCM", |
@@ -94,7 +70,6 @@ static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { | |||
94 | static struct snd_soc_card atmel_asoc_wm8904_card = { | 70 | static struct snd_soc_card atmel_asoc_wm8904_card = { |
95 | .name = "atmel_asoc_wm8904", | 71 | .name = "atmel_asoc_wm8904", |
96 | .owner = THIS_MODULE, | 72 | .owner = THIS_MODULE, |
97 | .set_bias_level = atmel_set_bias_level, | ||
98 | .dai_link = &atmel_asoc_wm8904_dailink, | 73 | .dai_link = &atmel_asoc_wm8904_dailink, |
99 | .num_links = 1, | 74 | .num_links = 1, |
100 | .dapm_widgets = atmel_asoc_wm8904_dapm_widgets, | 75 | .dapm_widgets = atmel_asoc_wm8904_dapm_widgets, |
@@ -153,7 +128,6 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev) | |||
153 | { | 128 | { |
154 | struct snd_soc_card *card = &atmel_asoc_wm8904_card; | 129 | struct snd_soc_card *card = &atmel_asoc_wm8904_card; |
155 | struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; | 130 | struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; |
156 | struct clk *clk_src; | ||
157 | int id, ret; | 131 | int id, ret; |
158 | 132 | ||
159 | card->dev = &pdev->dev; | 133 | card->dev = &pdev->dev; |
@@ -170,30 +144,6 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev) | |||
170 | return ret; | 144 | return ret; |
171 | } | 145 | } |
172 | 146 | ||
173 | mclk = clk_get(NULL, "pck0"); | ||
174 | if (IS_ERR(mclk)) { | ||
175 | dev_err(&pdev->dev, "failed to get pck0\n"); | ||
176 | ret = PTR_ERR(mclk); | ||
177 | goto err_set_audio; | ||
178 | } | ||
179 | |||
180 | clk_src = clk_get(NULL, "clk32k"); | ||
181 | if (IS_ERR(clk_src)) { | ||
182 | dev_err(&pdev->dev, "failed to get clk32k\n"); | ||
183 | ret = PTR_ERR(clk_src); | ||
184 | goto err_set_audio; | ||
185 | } | ||
186 | |||
187 | ret = clk_set_parent(mclk, clk_src); | ||
188 | clk_put(clk_src); | ||
189 | if (ret != 0) { | ||
190 | dev_err(&pdev->dev, "failed to set MCLK parent\n"); | ||
191 | goto err_set_audio; | ||
192 | } | ||
193 | |||
194 | dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE); | ||
195 | clk_set_rate(mclk, MCLK_RATE); | ||
196 | |||
197 | ret = snd_soc_register_card(card); | 147 | ret = snd_soc_register_card(card); |
198 | if (ret) { | 148 | if (ret) { |
199 | dev_err(&pdev->dev, "snd_soc_register_card failed\n"); | 149 | dev_err(&pdev->dev, "snd_soc_register_card failed\n"); |
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index a3881c4381c9..bcf591373a7a 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -290,19 +290,19 @@ static int bf5xx_pcm_silence(struct snd_pcm_substream *substream, | |||
290 | unsigned int sample_size = runtime->sample_bits / 8; | 290 | unsigned int sample_size = runtime->sample_bits / 8; |
291 | void *buf = runtime->dma_area; | 291 | void *buf = runtime->dma_area; |
292 | struct bf5xx_i2s_pcm_data *dma_data; | 292 | struct bf5xx_i2s_pcm_data *dma_data; |
293 | unsigned int offset, size; | 293 | unsigned int offset, samples; |
294 | 294 | ||
295 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | 295 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
296 | 296 | ||
297 | if (dma_data->tdm_mode) { | 297 | if (dma_data->tdm_mode) { |
298 | offset = pos * 8 * sample_size; | 298 | offset = pos * 8 * sample_size; |
299 | size = count * 8 * sample_size; | 299 | samples = count * 8; |
300 | } else { | 300 | } else { |
301 | offset = frames_to_bytes(runtime, pos); | 301 | offset = frames_to_bytes(runtime, pos); |
302 | size = frames_to_bytes(runtime, count); | 302 | samples = count * runtime->channels; |
303 | } | 303 | } |
304 | 304 | ||
305 | snd_pcm_format_set_silence(runtime->format, buf + offset, size); | 305 | snd_pcm_format_set_silence(runtime->format, buf + offset, samples); |
306 | 306 | ||
307 | return 0; | 307 | return 0; |
308 | } | 308 | } |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cbfa1e18f651..4c7542571484 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -47,6 +47,7 @@ config SND_SOC_ALL_CODECS | |||
47 | select SND_SOC_CS42L52 if I2C && INPUT | 47 | select SND_SOC_CS42L52 if I2C && INPUT |
48 | select SND_SOC_CS42L56 if I2C && INPUT | 48 | select SND_SOC_CS42L56 if I2C && INPUT |
49 | select SND_SOC_CS42L73 if I2C | 49 | select SND_SOC_CS42L73 if I2C |
50 | select SND_SOC_CS4265 if I2C | ||
50 | select SND_SOC_CS4270 if I2C | 51 | select SND_SOC_CS4270 if I2C |
51 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI | 52 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI |
52 | select SND_SOC_CS42XX8_I2C if I2C | 53 | select SND_SOC_CS42XX8_I2C if I2C |
@@ -74,6 +75,7 @@ config SND_SOC_ALL_CODECS | |||
74 | select SND_SOC_PCM3008 | 75 | select SND_SOC_PCM3008 |
75 | select SND_SOC_PCM512x_I2C if I2C | 76 | select SND_SOC_PCM512x_I2C if I2C |
76 | select SND_SOC_PCM512x_SPI if SPI_MASTER | 77 | select SND_SOC_PCM512x_SPI if SPI_MASTER |
78 | select SND_SOC_RT286 if I2C | ||
77 | select SND_SOC_RT5631 if I2C | 79 | select SND_SOC_RT5631 if I2C |
78 | select SND_SOC_RT5640 if I2C | 80 | select SND_SOC_RT5640 if I2C |
79 | select SND_SOC_RT5645 if I2C | 81 | select SND_SOC_RT5645 if I2C |
@@ -225,11 +227,11 @@ config SND_SOC_ADAU1373 | |||
225 | config SND_SOC_ADAU1701 | 227 | config SND_SOC_ADAU1701 |
226 | tristate "Analog Devices ADAU1701 CODEC" | 228 | tristate "Analog Devices ADAU1701 CODEC" |
227 | depends on I2C | 229 | depends on I2C |
228 | select SND_SOC_SIGMADSP | 230 | select SND_SOC_SIGMADSP_I2C |
229 | 231 | ||
230 | config SND_SOC_ADAU17X1 | 232 | config SND_SOC_ADAU17X1 |
231 | tristate | 233 | tristate |
232 | select SND_SOC_SIGMADSP | 234 | select SND_SOC_SIGMADSP_REGMAP |
233 | 235 | ||
234 | config SND_SOC_ADAU1761 | 236 | config SND_SOC_ADAU1761 |
235 | tristate | 237 | tristate |
@@ -338,6 +340,11 @@ config SND_SOC_CS42L73 | |||
338 | tristate "Cirrus Logic CS42L73 CODEC" | 340 | tristate "Cirrus Logic CS42L73 CODEC" |
339 | depends on I2C | 341 | depends on I2C |
340 | 342 | ||
343 | config SND_SOC_CS4265 | ||
344 | tristate "Cirrus Logic CS4265 CODEC" | ||
345 | depends on I2C | ||
346 | select REGMAP_I2C | ||
347 | |||
341 | # Cirrus Logic CS4270 Codec | 348 | # Cirrus Logic CS4270 Codec |
342 | config SND_SOC_CS4270 | 349 | config SND_SOC_CS4270 |
343 | tristate "Cirrus Logic CS4270 CODEC" | 350 | tristate "Cirrus Logic CS4270 CODEC" |
@@ -449,6 +456,9 @@ config SND_SOC_RL6231 | |||
449 | default m if SND_SOC_RT5645=m | 456 | default m if SND_SOC_RT5645=m |
450 | default m if SND_SOC_RT5651=m | 457 | default m if SND_SOC_RT5651=m |
451 | 458 | ||
459 | config SND_SOC_RT286 | ||
460 | tristate | ||
461 | |||
452 | config SND_SOC_RT5631 | 462 | config SND_SOC_RT5631 |
453 | tristate | 463 | tristate |
454 | 464 | ||
@@ -476,6 +486,14 @@ config SND_SOC_SIGMADSP | |||
476 | tristate | 486 | tristate |
477 | select CRC32 | 487 | select CRC32 |
478 | 488 | ||
489 | config SND_SOC_SIGMADSP_I2C | ||
490 | tristate | ||
491 | select SND_SOC_SIGMADSP | ||
492 | |||
493 | config SND_SOC_SIGMADSP_REGMAP | ||
494 | tristate | ||
495 | select SND_SOC_SIGMADSP | ||
496 | |||
479 | config SND_SOC_SIRF_AUDIO_CODEC | 497 | config SND_SOC_SIRF_AUDIO_CODEC |
480 | tristate "SiRF SoC internal audio codec" | 498 | tristate "SiRF SoC internal audio codec" |
481 | select REGMAP_MMIO | 499 | select REGMAP_MMIO |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index be3377b8d73f..ade412e49bd0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -37,6 +37,7 @@ snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o | |||
37 | snd-soc-cs42l52-objs := cs42l52.o | 37 | snd-soc-cs42l52-objs := cs42l52.o |
38 | snd-soc-cs42l56-objs := cs42l56.o | 38 | snd-soc-cs42l56-objs := cs42l56.o |
39 | snd-soc-cs42l73-objs := cs42l73.o | 39 | snd-soc-cs42l73-objs := cs42l73.o |
40 | snd-soc-cs4265-objs := cs4265.o | ||
40 | snd-soc-cs4270-objs := cs4270.o | 41 | snd-soc-cs4270-objs := cs4270.o |
41 | snd-soc-cs4271-objs := cs4271.o | 42 | snd-soc-cs4271-objs := cs4271.o |
42 | snd-soc-cs42xx8-objs := cs42xx8.o | 43 | snd-soc-cs42xx8-objs := cs42xx8.o |
@@ -68,6 +69,7 @@ snd-soc-pcm512x-objs := pcm512x.o | |||
68 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | 69 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o |
69 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | 70 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o |
70 | snd-soc-rl6231-objs := rl6231.o | 71 | snd-soc-rl6231-objs := rl6231.o |
72 | snd-soc-rt286-objs := rt286.o | ||
71 | snd-soc-rt5631-objs := rt5631.o | 73 | snd-soc-rt5631-objs := rt5631.o |
72 | snd-soc-rt5640-objs := rt5640.o | 74 | snd-soc-rt5640-objs := rt5640.o |
73 | snd-soc-rt5645-objs := rt5645.o | 75 | snd-soc-rt5645-objs := rt5645.o |
@@ -77,6 +79,8 @@ snd-soc-sgtl5000-objs := sgtl5000.o | |||
77 | snd-soc-alc5623-objs := alc5623.o | 79 | snd-soc-alc5623-objs := alc5623.o |
78 | snd-soc-alc5632-objs := alc5632.o | 80 | snd-soc-alc5632-objs := alc5632.o |
79 | snd-soc-sigmadsp-objs := sigmadsp.o | 81 | snd-soc-sigmadsp-objs := sigmadsp.o |
82 | snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o | ||
83 | snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o | ||
80 | snd-soc-si476x-objs := si476x.o | 84 | snd-soc-si476x-objs := si476x.o |
81 | snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o | 85 | snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o |
82 | snd-soc-sn95031-objs := sn95031.o | 86 | snd-soc-sn95031-objs := sn95031.o |
@@ -202,6 +206,7 @@ obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o | |||
202 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o | 206 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o |
203 | obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o | 207 | obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o |
204 | obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o | 208 | obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o |
209 | obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o | ||
205 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 210 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
206 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o | 211 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o |
207 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o | 212 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o |
@@ -233,6 +238,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | |||
233 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | 238 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o |
234 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | 239 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o |
235 | obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o | 240 | obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o |
241 | obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o | ||
236 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 242 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
237 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 243 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
238 | obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o | 244 | obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o |
@@ -240,6 +246,8 @@ obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o | |||
240 | obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o | 246 | obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o |
241 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 247 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
242 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o | 248 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o |
249 | obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o | ||
250 | obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o | ||
243 | obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o | 251 | obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o |
244 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | 252 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o |
245 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o | 253 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 8d9ba4ba4bfe..e889e1b84192 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -89,8 +89,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) | |||
89 | int ret; | 89 | int ret; |
90 | 90 | ||
91 | /* add codec as bus device for standard ac97 */ | 91 | /* add codec as bus device for standard ac97 */ |
92 | ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL, | 92 | ret = snd_ac97_bus(codec->component.card->snd_card, 0, soc_ac97_ops, |
93 | &ac97_bus); | 93 | NULL, &ac97_bus); |
94 | if (ret < 0) | 94 | if (ret < 0) |
95 | return ret; | 95 | return ret; |
96 | 96 | ||
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index d71c59cf7bdd..370b742117ef 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -230,8 +230,10 @@ static int adau1701_reg_read(void *context, unsigned int reg, | |||
230 | 230 | ||
231 | *value = 0; | 231 | *value = 0; |
232 | 232 | ||
233 | for (i = 0; i < size; i++) | 233 | for (i = 0; i < size; i++) { |
234 | *value |= recv_buf[i] << (i * 8); | 234 | *value <<= 8; |
235 | *value |= recv_buf[i]; | ||
236 | } | ||
235 | 237 | ||
236 | return 0; | 238 | return 0; |
237 | } | 239 | } |
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index fd55da7cb9d4..70ab35744aba 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c | |||
@@ -968,7 +968,7 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, | |||
968 | if (adau1977->dvdd_reg) | 968 | if (adau1977->dvdd_reg) |
969 | power_off_mask = ~0; | 969 | power_off_mask = ~0; |
970 | else | 970 | else |
971 | power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; | 971 | power_off_mask = (unsigned int)~ADAU1977_BLOCK_POWER_SAI_LDO_EN; |
972 | 972 | ||
973 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, | 973 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, |
974 | power_off_mask, 0x00); | 974 | power_off_mask, 0x00); |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 3ba4c0f11418..041712592e29 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -547,7 +547,7 @@ static const struct ak4642_drvdata ak4648_drvdata = { | |||
547 | .extended_frequencies = 1, | 547 | .extended_frequencies = 1, |
548 | }; | 548 | }; |
549 | 549 | ||
550 | static struct of_device_id ak4642_of_match[]; | 550 | static const struct of_device_id ak4642_of_match[]; |
551 | static int ak4642_i2c_probe(struct i2c_client *i2c, | 551 | static int ak4642_i2c_probe(struct i2c_client *i2c, |
552 | const struct i2c_device_id *id) | 552 | const struct i2c_device_id *id) |
553 | { | 553 | { |
@@ -593,7 +593,7 @@ static int ak4642_i2c_remove(struct i2c_client *client) | |||
593 | return 0; | 593 | return 0; |
594 | } | 594 | } |
595 | 595 | ||
596 | static struct of_device_id ak4642_of_match[] = { | 596 | static const struct of_device_id ak4642_of_match[] = { |
597 | { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata}, | 597 | { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata}, |
598 | { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata}, | 598 | { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata}, |
599 | { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata}, | 599 | { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata}, |
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index 72e953b2cb41..8107a1cac876 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c | |||
@@ -14,12 +14,18 @@ | |||
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_gpio.h> | 15 | #include <linux/of_gpio.h> |
16 | #include <linux/of_device.h> | 16 | #include <linux/of_device.h> |
17 | #include <linux/regulator/consumer.h> | ||
17 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
18 | #include <sound/pcm.h> | 19 | #include <sound/pcm.h> |
19 | #include <sound/initval.h> | 20 | #include <sound/initval.h> |
20 | 21 | ||
22 | static const char * const supply_names[] = { | ||
23 | "va", "vd" | ||
24 | }; | ||
25 | |||
21 | struct ak5386_priv { | 26 | struct ak5386_priv { |
22 | int reset_gpio; | 27 | int reset_gpio; |
28 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | ||
23 | }; | 29 | }; |
24 | 30 | ||
25 | static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { | 31 | static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { |
@@ -32,7 +38,42 @@ static const struct snd_soc_dapm_route ak5386_dapm_routes[] = { | |||
32 | { "Capture", NULL, "AINR" }, | 38 | { "Capture", NULL, "AINR" }, |
33 | }; | 39 | }; |
34 | 40 | ||
41 | static int ak5386_soc_probe(struct snd_soc_codec *codec) | ||
42 | { | ||
43 | struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
44 | return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); | ||
45 | } | ||
46 | |||
47 | static int ak5386_soc_remove(struct snd_soc_codec *codec) | ||
48 | { | ||
49 | struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
50 | regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | #ifdef CONFIG_PM | ||
55 | static int ak5386_soc_suspend(struct snd_soc_codec *codec) | ||
56 | { | ||
57 | struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
58 | regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int ak5386_soc_resume(struct snd_soc_codec *codec) | ||
63 | { | ||
64 | struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
65 | return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); | ||
66 | } | ||
67 | #else | ||
68 | #define ak5386_soc_suspend NULL | ||
69 | #define ak5386_soc_resume NULL | ||
70 | #endif /* CONFIG_PM */ | ||
71 | |||
35 | static struct snd_soc_codec_driver soc_codec_ak5386 = { | 72 | static struct snd_soc_codec_driver soc_codec_ak5386 = { |
73 | .probe = ak5386_soc_probe, | ||
74 | .remove = ak5386_soc_remove, | ||
75 | .suspend = ak5386_soc_suspend, | ||
76 | .resume = ak5386_soc_resume, | ||
36 | .dapm_widgets = ak5386_dapm_widgets, | 77 | .dapm_widgets = ak5386_dapm_widgets, |
37 | .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), | 78 | .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), |
38 | .dapm_routes = ak5386_dapm_routes, | 79 | .dapm_routes = ak5386_dapm_routes, |
@@ -122,6 +163,7 @@ static int ak5386_probe(struct platform_device *pdev) | |||
122 | { | 163 | { |
123 | struct device *dev = &pdev->dev; | 164 | struct device *dev = &pdev->dev; |
124 | struct ak5386_priv *priv; | 165 | struct ak5386_priv *priv; |
166 | int ret, i; | ||
125 | 167 | ||
126 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 168 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
127 | if (!priv) | 169 | if (!priv) |
@@ -130,6 +172,14 @@ static int ak5386_probe(struct platform_device *pdev) | |||
130 | priv->reset_gpio = -EINVAL; | 172 | priv->reset_gpio = -EINVAL; |
131 | dev_set_drvdata(dev, priv); | 173 | dev_set_drvdata(dev, priv); |
132 | 174 | ||
175 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) | ||
176 | priv->supplies[i].supply = supply_names[i]; | ||
177 | |||
178 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), | ||
179 | priv->supplies); | ||
180 | if (ret < 0) | ||
181 | return ret; | ||
182 | |||
133 | if (of_match_device(of_match_ptr(ak5386_dt_ids), dev)) | 183 | if (of_match_device(of_match_ptr(ak5386_dt_ids), dev)) |
134 | priv->reset_gpio = of_get_named_gpio(dev->of_node, | 184 | priv->reset_gpio = of_get_named_gpio(dev->of_node, |
135 | "reset-gpio", 0); | 185 | "reset-gpio", 0); |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 29e198f57d4c..2f2e91ac690f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -243,6 +243,31 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
243 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(arizona_init_spk); | 244 | EXPORT_SYMBOL_GPL(arizona_init_spk); |
245 | 245 | ||
246 | static const struct snd_soc_dapm_route arizona_mono_routes[] = { | ||
247 | { "OUT1R", NULL, "OUT1L" }, | ||
248 | { "OUT2R", NULL, "OUT2L" }, | ||
249 | { "OUT3R", NULL, "OUT3L" }, | ||
250 | { "OUT4R", NULL, "OUT4L" }, | ||
251 | { "OUT5R", NULL, "OUT5L" }, | ||
252 | { "OUT6R", NULL, "OUT6L" }, | ||
253 | }; | ||
254 | |||
255 | int arizona_init_mono(struct snd_soc_codec *codec) | ||
256 | { | ||
257 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
258 | struct arizona *arizona = priv->arizona; | ||
259 | int i; | ||
260 | |||
261 | for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) { | ||
262 | if (arizona->pdata.out_mono[i]) | ||
263 | snd_soc_dapm_add_routes(&codec->dapm, | ||
264 | &arizona_mono_routes[i], 1); | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(arizona_init_mono); | ||
270 | |||
246 | int arizona_init_gpio(struct snd_soc_codec *codec) | 271 | int arizona_init_gpio(struct snd_soc_codec *codec) |
247 | { | 272 | { |
248 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 273 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
@@ -1127,6 +1152,31 @@ static int arizona_startup(struct snd_pcm_substream *substream, | |||
1127 | constraint); | 1152 | constraint); |
1128 | } | 1153 | } |
1129 | 1154 | ||
1155 | static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, | ||
1156 | unsigned int rate) | ||
1157 | { | ||
1158 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
1159 | struct arizona *arizona = priv->arizona; | ||
1160 | struct reg_default dac_comp[] = { | ||
1161 | { 0x80, 0x3 }, | ||
1162 | { ARIZONA_DAC_COMP_1, 0 }, | ||
1163 | { ARIZONA_DAC_COMP_2, 0 }, | ||
1164 | { 0x80, 0x0 }, | ||
1165 | }; | ||
1166 | |||
1167 | mutex_lock(&codec->mutex); | ||
1168 | |||
1169 | dac_comp[1].def = arizona->dac_comp_coeff; | ||
1170 | if (rate >= 176400) | ||
1171 | dac_comp[2].def = arizona->dac_comp_enabled; | ||
1172 | |||
1173 | mutex_unlock(&codec->mutex); | ||
1174 | |||
1175 | regmap_multi_reg_write(arizona->regmap, | ||
1176 | dac_comp, | ||
1177 | ARRAY_SIZE(dac_comp)); | ||
1178 | } | ||
1179 | |||
1130 | static int arizona_hw_params_rate(struct snd_pcm_substream *substream, | 1180 | static int arizona_hw_params_rate(struct snd_pcm_substream *substream, |
1131 | struct snd_pcm_hw_params *params, | 1181 | struct snd_pcm_hw_params *params, |
1132 | struct snd_soc_dai *dai) | 1182 | struct snd_soc_dai *dai) |
@@ -1153,6 +1203,15 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, | |||
1153 | 1203 | ||
1154 | switch (dai_priv->clk) { | 1204 | switch (dai_priv->clk) { |
1155 | case ARIZONA_CLK_SYSCLK: | 1205 | case ARIZONA_CLK_SYSCLK: |
1206 | switch (priv->arizona->type) { | ||
1207 | case WM5102: | ||
1208 | arizona_wm5102_set_dac_comp(codec, | ||
1209 | params_rate(params)); | ||
1210 | break; | ||
1211 | default: | ||
1212 | break; | ||
1213 | } | ||
1214 | |||
1156 | snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, | 1215 | snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, |
1157 | ARIZONA_SAMPLE_RATE_1_MASK, sr_val); | 1216 | ARIZONA_SAMPLE_RATE_1_MASK, sr_val); |
1158 | if (base) | 1217 | if (base) |
@@ -1175,6 +1234,27 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, | |||
1175 | return 0; | 1234 | return 0; |
1176 | } | 1235 | } |
1177 | 1236 | ||
1237 | static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec, | ||
1238 | int base, int bclk, int lrclk, int frame) | ||
1239 | { | ||
1240 | int val; | ||
1241 | |||
1242 | val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL); | ||
1243 | if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK)) | ||
1244 | return true; | ||
1245 | |||
1246 | val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE); | ||
1247 | if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK)) | ||
1248 | return true; | ||
1249 | |||
1250 | val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1); | ||
1251 | if (frame != (val & (ARIZONA_AIF1TX_WL_MASK | | ||
1252 | ARIZONA_AIF1TX_SLOT_LEN_MASK))) | ||
1253 | return true; | ||
1254 | |||
1255 | return false; | ||
1256 | } | ||
1257 | |||
1178 | static int arizona_hw_params(struct snd_pcm_substream *substream, | 1258 | static int arizona_hw_params(struct snd_pcm_substream *substream, |
1179 | struct snd_pcm_hw_params *params, | 1259 | struct snd_pcm_hw_params *params, |
1180 | struct snd_soc_dai *dai) | 1260 | struct snd_soc_dai *dai) |
@@ -1185,26 +1265,40 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1185 | int base = dai->driver->base; | 1265 | int base = dai->driver->base; |
1186 | const int *rates; | 1266 | const int *rates; |
1187 | int i, ret, val; | 1267 | int i, ret, val; |
1268 | int channels = params_channels(params); | ||
1188 | int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; | 1269 | int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; |
1270 | int tdm_width = arizona->tdm_width[dai->id - 1]; | ||
1271 | int tdm_slots = arizona->tdm_slots[dai->id - 1]; | ||
1189 | int bclk, lrclk, wl, frame, bclk_target; | 1272 | int bclk, lrclk, wl, frame, bclk_target; |
1273 | bool reconfig; | ||
1274 | unsigned int aif_tx_state, aif_rx_state; | ||
1190 | 1275 | ||
1191 | if (params_rate(params) % 8000) | 1276 | if (params_rate(params) % 8000) |
1192 | rates = &arizona_44k1_bclk_rates[0]; | 1277 | rates = &arizona_44k1_bclk_rates[0]; |
1193 | else | 1278 | else |
1194 | rates = &arizona_48k_bclk_rates[0]; | 1279 | rates = &arizona_48k_bclk_rates[0]; |
1195 | 1280 | ||
1196 | bclk_target = snd_soc_params_to_bclk(params); | 1281 | if (tdm_slots) { |
1197 | if (chan_limit && chan_limit < params_channels(params)) { | 1282 | arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", |
1283 | tdm_slots, tdm_width); | ||
1284 | bclk_target = tdm_slots * tdm_width * params_rate(params); | ||
1285 | channels = tdm_slots; | ||
1286 | } else { | ||
1287 | bclk_target = snd_soc_params_to_bclk(params); | ||
1288 | } | ||
1289 | |||
1290 | if (chan_limit && chan_limit < channels) { | ||
1198 | arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit); | 1291 | arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit); |
1199 | bclk_target /= params_channels(params); | 1292 | bclk_target /= channels; |
1200 | bclk_target *= chan_limit; | 1293 | bclk_target *= chan_limit; |
1201 | } | 1294 | } |
1202 | 1295 | ||
1203 | /* Force stereo for I2S mode */ | 1296 | /* Force multiple of 2 channels for I2S mode */ |
1204 | val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); | 1297 | val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); |
1205 | if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) { | 1298 | if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) { |
1206 | arizona_aif_dbg(dai, "Forcing stereo mode\n"); | 1299 | arizona_aif_dbg(dai, "Forcing stereo mode\n"); |
1207 | bclk_target *= 2; | 1300 | bclk_target /= channels; |
1301 | bclk_target *= channels + 1; | ||
1208 | } | 1302 | } |
1209 | 1303 | ||
1210 | for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { | 1304 | for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { |
@@ -1228,28 +1322,56 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1228 | wl = snd_pcm_format_width(params_format(params)); | 1322 | wl = snd_pcm_format_width(params_format(params)); |
1229 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; | 1323 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; |
1230 | 1324 | ||
1325 | reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame); | ||
1326 | |||
1327 | if (reconfig) { | ||
1328 | /* Save AIF TX/RX state */ | ||
1329 | aif_tx_state = snd_soc_read(codec, | ||
1330 | base + ARIZONA_AIF_TX_ENABLES); | ||
1331 | aif_rx_state = snd_soc_read(codec, | ||
1332 | base + ARIZONA_AIF_RX_ENABLES); | ||
1333 | /* Disable AIF TX/RX before reconfiguring it */ | ||
1334 | regmap_update_bits_async(arizona->regmap, | ||
1335 | base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0); | ||
1336 | regmap_update_bits(arizona->regmap, | ||
1337 | base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0); | ||
1338 | } | ||
1339 | |||
1231 | ret = arizona_hw_params_rate(substream, params, dai); | 1340 | ret = arizona_hw_params_rate(substream, params, dai); |
1232 | if (ret != 0) | 1341 | if (ret != 0) |
1233 | return ret; | 1342 | goto restore_aif; |
1234 | 1343 | ||
1235 | regmap_update_bits_async(arizona->regmap, | 1344 | if (reconfig) { |
1236 | base + ARIZONA_AIF_BCLK_CTRL, | 1345 | regmap_update_bits_async(arizona->regmap, |
1237 | ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); | 1346 | base + ARIZONA_AIF_BCLK_CTRL, |
1238 | regmap_update_bits_async(arizona->regmap, | 1347 | ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); |
1239 | base + ARIZONA_AIF_TX_BCLK_RATE, | 1348 | regmap_update_bits_async(arizona->regmap, |
1240 | ARIZONA_AIF1TX_BCPF_MASK, lrclk); | 1349 | base + ARIZONA_AIF_TX_BCLK_RATE, |
1241 | regmap_update_bits_async(arizona->regmap, | 1350 | ARIZONA_AIF1TX_BCPF_MASK, lrclk); |
1242 | base + ARIZONA_AIF_RX_BCLK_RATE, | 1351 | regmap_update_bits_async(arizona->regmap, |
1243 | ARIZONA_AIF1RX_BCPF_MASK, lrclk); | 1352 | base + ARIZONA_AIF_RX_BCLK_RATE, |
1244 | regmap_update_bits_async(arizona->regmap, | 1353 | ARIZONA_AIF1RX_BCPF_MASK, lrclk); |
1245 | base + ARIZONA_AIF_FRAME_CTRL_1, | 1354 | regmap_update_bits_async(arizona->regmap, |
1246 | ARIZONA_AIF1TX_WL_MASK | | 1355 | base + ARIZONA_AIF_FRAME_CTRL_1, |
1247 | ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); | 1356 | ARIZONA_AIF1TX_WL_MASK | |
1248 | regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2, | 1357 | ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); |
1249 | ARIZONA_AIF1RX_WL_MASK | | 1358 | regmap_update_bits(arizona->regmap, |
1250 | ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); | 1359 | base + ARIZONA_AIF_FRAME_CTRL_2, |
1360 | ARIZONA_AIF1RX_WL_MASK | | ||
1361 | ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); | ||
1362 | } | ||
1251 | 1363 | ||
1252 | return 0; | 1364 | restore_aif: |
1365 | if (reconfig) { | ||
1366 | /* Restore AIF TX/RX state */ | ||
1367 | regmap_update_bits_async(arizona->regmap, | ||
1368 | base + ARIZONA_AIF_TX_ENABLES, | ||
1369 | 0xff, aif_tx_state); | ||
1370 | regmap_update_bits(arizona->regmap, | ||
1371 | base + ARIZONA_AIF_RX_ENABLES, | ||
1372 | 0xff, aif_rx_state); | ||
1373 | } | ||
1374 | return ret; | ||
1253 | } | 1375 | } |
1254 | 1376 | ||
1255 | static const char *arizona_dai_clk_str(int clk_id) | 1377 | static const char *arizona_dai_clk_str(int clk_id) |
@@ -1324,9 +1446,63 @@ static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) | |||
1324 | ARIZONA_AIF1_TRI, reg); | 1446 | ARIZONA_AIF1_TRI, reg); |
1325 | } | 1447 | } |
1326 | 1448 | ||
1449 | static void arizona_set_channels_to_mask(struct snd_soc_dai *dai, | ||
1450 | unsigned int base, | ||
1451 | int channels, unsigned int mask) | ||
1452 | { | ||
1453 | struct snd_soc_codec *codec = dai->codec; | ||
1454 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
1455 | struct arizona *arizona = priv->arizona; | ||
1456 | int slot, i; | ||
1457 | |||
1458 | for (i = 0; i < channels; ++i) { | ||
1459 | slot = ffs(mask) - 1; | ||
1460 | if (slot < 0) | ||
1461 | return; | ||
1462 | |||
1463 | regmap_write(arizona->regmap, base + i, slot); | ||
1464 | |||
1465 | mask &= ~(1 << slot); | ||
1466 | } | ||
1467 | |||
1468 | if (mask) | ||
1469 | arizona_aif_warn(dai, "Too many channels in TDM mask\n"); | ||
1470 | } | ||
1471 | |||
1472 | static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
1473 | unsigned int rx_mask, int slots, int slot_width) | ||
1474 | { | ||
1475 | struct snd_soc_codec *codec = dai->codec; | ||
1476 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
1477 | struct arizona *arizona = priv->arizona; | ||
1478 | int base = dai->driver->base; | ||
1479 | int rx_max_chan = dai->driver->playback.channels_max; | ||
1480 | int tx_max_chan = dai->driver->capture.channels_max; | ||
1481 | |||
1482 | /* Only support TDM for the physical AIFs */ | ||
1483 | if (dai->id > ARIZONA_MAX_AIF) | ||
1484 | return -ENOTSUPP; | ||
1485 | |||
1486 | if (slots == 0) { | ||
1487 | tx_mask = (1 << tx_max_chan) - 1; | ||
1488 | rx_mask = (1 << rx_max_chan) - 1; | ||
1489 | } | ||
1490 | |||
1491 | arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3, | ||
1492 | tx_max_chan, tx_mask); | ||
1493 | arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11, | ||
1494 | rx_max_chan, rx_mask); | ||
1495 | |||
1496 | arizona->tdm_width[dai->id - 1] = slot_width; | ||
1497 | arizona->tdm_slots[dai->id - 1] = slots; | ||
1498 | |||
1499 | return 0; | ||
1500 | } | ||
1501 | |||
1327 | const struct snd_soc_dai_ops arizona_dai_ops = { | 1502 | const struct snd_soc_dai_ops arizona_dai_ops = { |
1328 | .startup = arizona_startup, | 1503 | .startup = arizona_startup, |
1329 | .set_fmt = arizona_set_fmt, | 1504 | .set_fmt = arizona_set_fmt, |
1505 | .set_tdm_slot = arizona_set_tdm_slot, | ||
1330 | .hw_params = arizona_hw_params, | 1506 | .hw_params = arizona_hw_params, |
1331 | .set_sysclk = arizona_dai_set_sysclk, | 1507 | .set_sysclk = arizona_dai_set_sysclk, |
1332 | .set_tristate = arizona_set_tristate, | 1508 | .set_tristate = arizona_set_tristate, |
@@ -1400,6 +1576,12 @@ static int arizona_validate_fll(struct arizona_fll *fll, | |||
1400 | { | 1576 | { |
1401 | unsigned int Fvco_min; | 1577 | unsigned int Fvco_min; |
1402 | 1578 | ||
1579 | if (fll->fout && Fout != fll->fout) { | ||
1580 | arizona_fll_err(fll, | ||
1581 | "Can't change output on active FLL\n"); | ||
1582 | return -EINVAL; | ||
1583 | } | ||
1584 | |||
1403 | if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { | 1585 | if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { |
1404 | arizona_fll_err(fll, | 1586 | arizona_fll_err(fll, |
1405 | "Can't scale %dMHz in to <=13.5MHz\n", | 1587 | "Can't scale %dMHz in to <=13.5MHz\n", |
@@ -1478,6 +1660,10 @@ static int arizona_calc_fratio(struct arizona_fll *fll, | |||
1478 | while (div <= ARIZONA_FLL_MAX_REFDIV) { | 1660 | while (div <= ARIZONA_FLL_MAX_REFDIV) { |
1479 | for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; | 1661 | for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; |
1480 | ratio++) { | 1662 | ratio++) { |
1663 | if ((ARIZONA_FLL_VCO_CORNER / 2) / | ||
1664 | (fll->vco_mult * ratio) < Fref) | ||
1665 | break; | ||
1666 | |||
1481 | if (target % (ratio * Fref)) { | 1667 | if (target % (ratio * Fref)) { |
1482 | cfg->refdiv = refdiv; | 1668 | cfg->refdiv = refdiv; |
1483 | cfg->fratio = ratio - 1; | 1669 | cfg->fratio = ratio - 1; |
@@ -1485,11 +1671,7 @@ static int arizona_calc_fratio(struct arizona_fll *fll, | |||
1485 | } | 1671 | } |
1486 | } | 1672 | } |
1487 | 1673 | ||
1488 | for (ratio = init_ratio - 1; ratio >= 0; ratio--) { | 1674 | for (ratio = init_ratio - 1; ratio > 0; ratio--) { |
1489 | if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < | ||
1490 | Fref) | ||
1491 | break; | ||
1492 | |||
1493 | if (target % (ratio * Fref)) { | 1675 | if (target % (ratio * Fref)) { |
1494 | cfg->refdiv = refdiv; | 1676 | cfg->refdiv = refdiv; |
1495 | cfg->fratio = ratio - 1; | 1677 | cfg->fratio = ratio - 1; |
@@ -1616,7 +1798,7 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, | |||
1616 | ARIZONA_FLL1_CTRL_UPD | cfg->n); | 1798 | ARIZONA_FLL1_CTRL_UPD | cfg->n); |
1617 | } | 1799 | } |
1618 | 1800 | ||
1619 | static bool arizona_is_enabled_fll(struct arizona_fll *fll) | 1801 | static int arizona_is_enabled_fll(struct arizona_fll *fll) |
1620 | { | 1802 | { |
1621 | struct arizona *arizona = fll->arizona; | 1803 | struct arizona *arizona = fll->arizona; |
1622 | unsigned int reg; | 1804 | unsigned int reg; |
@@ -1632,13 +1814,26 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) | |||
1632 | return reg & ARIZONA_FLL1_ENA; | 1814 | return reg & ARIZONA_FLL1_ENA; |
1633 | } | 1815 | } |
1634 | 1816 | ||
1635 | static void arizona_enable_fll(struct arizona_fll *fll) | 1817 | static int arizona_enable_fll(struct arizona_fll *fll) |
1636 | { | 1818 | { |
1637 | struct arizona *arizona = fll->arizona; | 1819 | struct arizona *arizona = fll->arizona; |
1638 | int ret; | 1820 | int ret; |
1639 | bool use_sync = false; | 1821 | bool use_sync = false; |
1822 | int already_enabled = arizona_is_enabled_fll(fll); | ||
1640 | struct arizona_fll_cfg cfg; | 1823 | struct arizona_fll_cfg cfg; |
1641 | 1824 | ||
1825 | if (already_enabled < 0) | ||
1826 | return already_enabled; | ||
1827 | |||
1828 | if (already_enabled) { | ||
1829 | /* Facilitate smooth refclk across the transition */ | ||
1830 | regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7, | ||
1831 | ARIZONA_FLL1_GAIN_MASK, 0); | ||
1832 | regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, | ||
1833 | ARIZONA_FLL1_FREERUN, | ||
1834 | ARIZONA_FLL1_FREERUN); | ||
1835 | } | ||
1836 | |||
1642 | /* | 1837 | /* |
1643 | * If we have both REFCLK and SYNCCLK then enable both, | 1838 | * If we have both REFCLK and SYNCCLK then enable both, |
1644 | * otherwise apply the SYNCCLK settings to REFCLK. | 1839 | * otherwise apply the SYNCCLK settings to REFCLK. |
@@ -1666,7 +1861,7 @@ static void arizona_enable_fll(struct arizona_fll *fll) | |||
1666 | ARIZONA_FLL1_SYNC_ENA, 0); | 1861 | ARIZONA_FLL1_SYNC_ENA, 0); |
1667 | } else { | 1862 | } else { |
1668 | arizona_fll_err(fll, "No clocks provided\n"); | 1863 | arizona_fll_err(fll, "No clocks provided\n"); |
1669 | return; | 1864 | return -EINVAL; |
1670 | } | 1865 | } |
1671 | 1866 | ||
1672 | /* | 1867 | /* |
@@ -1681,25 +1876,29 @@ static void arizona_enable_fll(struct arizona_fll *fll) | |||
1681 | ARIZONA_FLL1_SYNC_BW, | 1876 | ARIZONA_FLL1_SYNC_BW, |
1682 | ARIZONA_FLL1_SYNC_BW); | 1877 | ARIZONA_FLL1_SYNC_BW); |
1683 | 1878 | ||
1684 | if (!arizona_is_enabled_fll(fll)) | 1879 | if (!already_enabled) |
1685 | pm_runtime_get(arizona->dev); | 1880 | pm_runtime_get(arizona->dev); |
1686 | 1881 | ||
1687 | /* Clear any pending completions */ | 1882 | /* Clear any pending completions */ |
1688 | try_wait_for_completion(&fll->ok); | 1883 | try_wait_for_completion(&fll->ok); |
1689 | 1884 | ||
1690 | regmap_update_bits_async(arizona->regmap, fll->base + 1, | 1885 | regmap_update_bits_async(arizona->regmap, fll->base + 1, |
1691 | ARIZONA_FLL1_FREERUN, 0); | ||
1692 | regmap_update_bits_async(arizona->regmap, fll->base + 1, | ||
1693 | ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); | 1886 | ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); |
1694 | if (use_sync) | 1887 | if (use_sync) |
1695 | regmap_update_bits_async(arizona->regmap, fll->base + 0x11, | 1888 | regmap_update_bits_async(arizona->regmap, fll->base + 0x11, |
1696 | ARIZONA_FLL1_SYNC_ENA, | 1889 | ARIZONA_FLL1_SYNC_ENA, |
1697 | ARIZONA_FLL1_SYNC_ENA); | 1890 | ARIZONA_FLL1_SYNC_ENA); |
1698 | 1891 | ||
1892 | if (already_enabled) | ||
1893 | regmap_update_bits_async(arizona->regmap, fll->base + 1, | ||
1894 | ARIZONA_FLL1_FREERUN, 0); | ||
1895 | |||
1699 | ret = wait_for_completion_timeout(&fll->ok, | 1896 | ret = wait_for_completion_timeout(&fll->ok, |
1700 | msecs_to_jiffies(250)); | 1897 | msecs_to_jiffies(250)); |
1701 | if (ret == 0) | 1898 | if (ret == 0) |
1702 | arizona_fll_warn(fll, "Timed out waiting for lock\n"); | 1899 | arizona_fll_warn(fll, "Timed out waiting for lock\n"); |
1900 | |||
1901 | return 0; | ||
1703 | } | 1902 | } |
1704 | 1903 | ||
1705 | static void arizona_disable_fll(struct arizona_fll *fll) | 1904 | static void arizona_disable_fll(struct arizona_fll *fll) |
@@ -1713,6 +1912,8 @@ static void arizona_disable_fll(struct arizona_fll *fll) | |||
1713 | ARIZONA_FLL1_ENA, 0, &change); | 1912 | ARIZONA_FLL1_ENA, 0, &change); |
1714 | regmap_update_bits(arizona->regmap, fll->base + 0x11, | 1913 | regmap_update_bits(arizona->regmap, fll->base + 0x11, |
1715 | ARIZONA_FLL1_SYNC_ENA, 0); | 1914 | ARIZONA_FLL1_SYNC_ENA, 0); |
1915 | regmap_update_bits_async(arizona->regmap, fll->base + 1, | ||
1916 | ARIZONA_FLL1_FREERUN, 0); | ||
1716 | 1917 | ||
1717 | if (change) | 1918 | if (change) |
1718 | pm_runtime_put_autosuspend(arizona->dev); | 1919 | pm_runtime_put_autosuspend(arizona->dev); |
@@ -1721,7 +1922,7 @@ static void arizona_disable_fll(struct arizona_fll *fll) | |||
1721 | int arizona_set_fll_refclk(struct arizona_fll *fll, int source, | 1922 | int arizona_set_fll_refclk(struct arizona_fll *fll, int source, |
1722 | unsigned int Fref, unsigned int Fout) | 1923 | unsigned int Fref, unsigned int Fout) |
1723 | { | 1924 | { |
1724 | int ret; | 1925 | int ret = 0; |
1725 | 1926 | ||
1726 | if (fll->ref_src == source && fll->ref_freq == Fref) | 1927 | if (fll->ref_src == source && fll->ref_freq == Fref) |
1727 | return 0; | 1928 | return 0; |
@@ -1736,17 +1937,17 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, | |||
1736 | fll->ref_freq = Fref; | 1937 | fll->ref_freq = Fref; |
1737 | 1938 | ||
1738 | if (fll->fout && Fref > 0) { | 1939 | if (fll->fout && Fref > 0) { |
1739 | arizona_enable_fll(fll); | 1940 | ret = arizona_enable_fll(fll); |
1740 | } | 1941 | } |
1741 | 1942 | ||
1742 | return 0; | 1943 | return ret; |
1743 | } | 1944 | } |
1744 | EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); | 1945 | EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); |
1745 | 1946 | ||
1746 | int arizona_set_fll(struct arizona_fll *fll, int source, | 1947 | int arizona_set_fll(struct arizona_fll *fll, int source, |
1747 | unsigned int Fref, unsigned int Fout) | 1948 | unsigned int Fref, unsigned int Fout) |
1748 | { | 1949 | { |
1749 | int ret; | 1950 | int ret = 0; |
1750 | 1951 | ||
1751 | if (fll->sync_src == source && | 1952 | if (fll->sync_src == source && |
1752 | fll->sync_freq == Fref && fll->fout == Fout) | 1953 | fll->sync_freq == Fref && fll->fout == Fout) |
@@ -1768,13 +1969,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, | |||
1768 | fll->sync_freq = Fref; | 1969 | fll->sync_freq = Fref; |
1769 | fll->fout = Fout; | 1970 | fll->fout = Fout; |
1770 | 1971 | ||
1771 | if (Fout) { | 1972 | if (Fout) |
1772 | arizona_enable_fll(fll); | 1973 | ret = arizona_enable_fll(fll); |
1773 | } else { | 1974 | else |
1774 | arizona_disable_fll(fll); | 1975 | arizona_disable_fll(fll); |
1775 | } | ||
1776 | 1976 | ||
1777 | return 0; | 1977 | return ret; |
1778 | } | 1978 | } |
1779 | EXPORT_SYMBOL_GPL(arizona_set_fll); | 1979 | EXPORT_SYMBOL_GPL(arizona_set_fll); |
1780 | 1980 | ||
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 05ae17f5bca3..942cfb197b6d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -249,6 +249,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, | |||
249 | 249 | ||
250 | extern int arizona_init_spk(struct snd_soc_codec *codec); | 250 | extern int arizona_init_spk(struct snd_soc_codec *codec); |
251 | extern int arizona_init_gpio(struct snd_soc_codec *codec); | 251 | extern int arizona_init_gpio(struct snd_soc_codec *codec); |
252 | extern int arizona_init_mono(struct snd_soc_codec *codec); | ||
252 | 253 | ||
253 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); | 254 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); |
254 | 255 | ||
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c new file mode 100644 index 000000000000..a20b30ca52c0 --- /dev/null +++ b/sound/soc/codecs/cs4265.c | |||
@@ -0,0 +1,682 @@ | |||
1 | /* | ||
2 | * cs4265.c -- CS4265 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2014 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Author: Paul Handrigan <paul.handrigan@cirrus.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/gpio/consumer.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <sound/core.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/tlv.h> | ||
32 | #include "cs4265.h" | ||
33 | |||
34 | struct cs4265_private { | ||
35 | struct device *dev; | ||
36 | struct regmap *regmap; | ||
37 | struct gpio_desc *reset_gpio; | ||
38 | u8 format; | ||
39 | u32 sysclk; | ||
40 | }; | ||
41 | |||
42 | static const struct reg_default cs4265_reg_defaults[] = { | ||
43 | { CS4265_PWRCTL, 0x0F }, | ||
44 | { CS4265_DAC_CTL, 0x08 }, | ||
45 | { CS4265_ADC_CTL, 0x00 }, | ||
46 | { CS4265_MCLK_FREQ, 0x00 }, | ||
47 | { CS4265_SIG_SEL, 0x40 }, | ||
48 | { CS4265_CHB_PGA_CTL, 0x00 }, | ||
49 | { CS4265_CHA_PGA_CTL, 0x00 }, | ||
50 | { CS4265_ADC_CTL2, 0x19 }, | ||
51 | { CS4265_DAC_CHA_VOL, 0x00 }, | ||
52 | { CS4265_DAC_CHB_VOL, 0x00 }, | ||
53 | { CS4265_DAC_CTL2, 0xC0 }, | ||
54 | { CS4265_SPDIF_CTL1, 0x00 }, | ||
55 | { CS4265_SPDIF_CTL2, 0x00 }, | ||
56 | { CS4265_INT_MASK, 0x00 }, | ||
57 | { CS4265_STATUS_MODE_MSB, 0x00 }, | ||
58 | { CS4265_STATUS_MODE_LSB, 0x00 }, | ||
59 | }; | ||
60 | |||
61 | static bool cs4265_readable_register(struct device *dev, unsigned int reg) | ||
62 | { | ||
63 | switch (reg) { | ||
64 | case CS4265_PWRCTL: | ||
65 | case CS4265_DAC_CTL: | ||
66 | case CS4265_ADC_CTL: | ||
67 | case CS4265_MCLK_FREQ: | ||
68 | case CS4265_SIG_SEL: | ||
69 | case CS4265_CHB_PGA_CTL: | ||
70 | case CS4265_CHA_PGA_CTL: | ||
71 | case CS4265_ADC_CTL2: | ||
72 | case CS4265_DAC_CHA_VOL: | ||
73 | case CS4265_DAC_CHB_VOL: | ||
74 | case CS4265_DAC_CTL2: | ||
75 | case CS4265_SPDIF_CTL1: | ||
76 | case CS4265_SPDIF_CTL2: | ||
77 | case CS4265_INT_MASK: | ||
78 | case CS4265_STATUS_MODE_MSB: | ||
79 | case CS4265_STATUS_MODE_LSB: | ||
80 | return true; | ||
81 | default: | ||
82 | return false; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static bool cs4265_volatile_register(struct device *dev, unsigned int reg) | ||
87 | { | ||
88 | switch (reg) { | ||
89 | case CS4265_INT_STATUS: | ||
90 | return true; | ||
91 | default: | ||
92 | return false; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0); | ||
97 | |||
98 | static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0); | ||
99 | |||
100 | static const char * const digital_input_mux_text[] = { | ||
101 | "SDIN1", "SDIN2" | ||
102 | }; | ||
103 | |||
104 | static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7, | ||
105 | digital_input_mux_text); | ||
106 | |||
107 | static const struct snd_kcontrol_new digital_input_mux = | ||
108 | SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum); | ||
109 | |||
110 | static const char * const mic_linein_text[] = { | ||
111 | "MIC", "LINEIN" | ||
112 | }; | ||
113 | |||
114 | static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0, | ||
115 | mic_linein_text); | ||
116 | |||
117 | static const char * const cam_mode_text[] = { | ||
118 | "One Byte", "Two Byte" | ||
119 | }; | ||
120 | |||
121 | static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5, | ||
122 | cam_mode_text); | ||
123 | |||
124 | static const char * const cam_mono_stereo_text[] = { | ||
125 | "Stereo", "Mono" | ||
126 | }; | ||
127 | |||
128 | static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2, | ||
129 | cam_mono_stereo_text); | ||
130 | |||
131 | static const char * const mono_select_text[] = { | ||
132 | "Channel A", "Channel B" | ||
133 | }; | ||
134 | |||
135 | static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0, | ||
136 | mono_select_text); | ||
137 | |||
138 | static const struct snd_kcontrol_new mic_linein_mux = | ||
139 | SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum); | ||
140 | |||
141 | static const struct snd_kcontrol_new loopback_ctl = | ||
142 | SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0); | ||
143 | |||
144 | static const struct snd_kcontrol_new spdif_switch = | ||
145 | SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0); | ||
146 | |||
147 | static const struct snd_kcontrol_new dac_switch = | ||
148 | SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0); | ||
149 | |||
150 | static const struct snd_kcontrol_new cs4265_snd_controls[] = { | ||
151 | |||
152 | SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL, | ||
153 | CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv), | ||
154 | SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL, | ||
155 | CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv), | ||
156 | SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1, | ||
157 | 1, 0), | ||
158 | SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5, | ||
159 | 1, 0), | ||
160 | SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6, | ||
161 | 1, 0), | ||
162 | SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7, | ||
163 | 1, 0), | ||
164 | SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1, | ||
165 | 1, 0), | ||
166 | SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3, | ||
167 | 1, 1), | ||
168 | SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7, | ||
169 | 1, 0), | ||
170 | SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1, | ||
171 | 6, 1, 0), | ||
172 | SOC_ENUM("C Data Access", cam_mode_enum), | ||
173 | SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, | ||
174 | 3, 1, 0), | ||
175 | SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), | ||
176 | SOC_SINGLE("MMTLR Data Switch", 0, | ||
177 | 1, 1, 0), | ||
178 | SOC_ENUM("Mono Channel Select", spdif_mono_select_enum), | ||
179 | SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24), | ||
180 | }; | ||
181 | |||
182 | static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = { | ||
183 | |||
184 | SND_SOC_DAPM_INPUT("LINEINL"), | ||
185 | SND_SOC_DAPM_INPUT("LINEINR"), | ||
186 | SND_SOC_DAPM_INPUT("MICL"), | ||
187 | SND_SOC_DAPM_INPUT("MICR"), | ||
188 | |||
189 | SND_SOC_DAPM_AIF_OUT("DOUT", NULL, 0, | ||
190 | SND_SOC_NOPM, 0, 0), | ||
191 | SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL, 0, | ||
192 | SND_SOC_NOPM, 0, 0), | ||
193 | |||
194 | SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux), | ||
195 | |||
196 | SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1), | ||
197 | SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3, | ||
198 | 1, NULL, 0), | ||
199 | |||
200 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, | ||
201 | 0, 0, &digital_input_mux), | ||
202 | |||
203 | SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
204 | SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
205 | SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
206 | |||
207 | SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0, | ||
208 | &loopback_ctl), | ||
209 | SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0, | ||
210 | &spdif_switch), | ||
211 | SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1, | ||
212 | &dac_switch), | ||
213 | |||
214 | SND_SOC_DAPM_AIF_IN("DIN1", NULL, 0, | ||
215 | SND_SOC_NOPM, 0, 0), | ||
216 | SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0, | ||
217 | SND_SOC_NOPM, 0, 0), | ||
218 | SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0, | ||
219 | CS4265_SPDIF_CTL2, 5, 1), | ||
220 | |||
221 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
222 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
223 | |||
224 | }; | ||
225 | |||
226 | static const struct snd_soc_dapm_route cs4265_audio_map[] = { | ||
227 | |||
228 | {"DIN1", NULL, "DAI1 Playback"}, | ||
229 | {"DIN2", NULL, "DAI2 Playback"}, | ||
230 | {"SDIN1 Input Mixer", NULL, "DIN1"}, | ||
231 | {"SDIN2 Input Mixer", NULL, "DIN2"}, | ||
232 | {"Input Mux", "SDIN1", "SDIN1 Input Mixer"}, | ||
233 | {"Input Mux", "SDIN2", "SDIN2 Input Mixer"}, | ||
234 | {"DAC", "Switch", "Input Mux"}, | ||
235 | {"SPDIF", "Switch", "Input Mux"}, | ||
236 | {"LINEOUTL", NULL, "DAC"}, | ||
237 | {"LINEOUTR", NULL, "DAC"}, | ||
238 | {"SPDIFOUT", NULL, "SPDIF"}, | ||
239 | |||
240 | {"ADC Mux", "LINEIN", "LINEINL"}, | ||
241 | {"ADC Mux", "LINEIN", "LINEINR"}, | ||
242 | {"ADC Mux", "MIC", "MICL"}, | ||
243 | {"ADC Mux", "MIC", "MICR"}, | ||
244 | {"ADC", NULL, "ADC Mux"}, | ||
245 | {"DOUT", NULL, "ADC"}, | ||
246 | {"DAI1 Capture", NULL, "DOUT"}, | ||
247 | {"DAI2 Capture", NULL, "DOUT"}, | ||
248 | |||
249 | /* Loopback */ | ||
250 | {"Loopback", "Switch", "ADC"}, | ||
251 | {"DAC", NULL, "Loopback"}, | ||
252 | }; | ||
253 | |||
254 | struct cs4265_clk_para { | ||
255 | u32 mclk; | ||
256 | u32 rate; | ||
257 | u8 fm_mode; /* values 1, 2, or 4 */ | ||
258 | u8 mclkdiv; | ||
259 | }; | ||
260 | |||
261 | static const struct cs4265_clk_para clk_map_table[] = { | ||
262 | /*32k*/ | ||
263 | {8192000, 32000, 0, 0}, | ||
264 | {12288000, 32000, 0, 1}, | ||
265 | {16384000, 32000, 0, 2}, | ||
266 | {24576000, 32000, 0, 3}, | ||
267 | {32768000, 32000, 0, 4}, | ||
268 | |||
269 | /*44.1k*/ | ||
270 | {11289600, 44100, 0, 0}, | ||
271 | {16934400, 44100, 0, 1}, | ||
272 | {22579200, 44100, 0, 2}, | ||
273 | {33868000, 44100, 0, 3}, | ||
274 | {45158400, 44100, 0, 4}, | ||
275 | |||
276 | /*48k*/ | ||
277 | {12288000, 48000, 0, 0}, | ||
278 | {18432000, 48000, 0, 1}, | ||
279 | {24576000, 48000, 0, 2}, | ||
280 | {36864000, 48000, 0, 3}, | ||
281 | {49152000, 48000, 0, 4}, | ||
282 | |||
283 | /*64k*/ | ||
284 | {8192000, 64000, 1, 0}, | ||
285 | {1228800, 64000, 1, 1}, | ||
286 | {1693440, 64000, 1, 2}, | ||
287 | {2457600, 64000, 1, 3}, | ||
288 | {3276800, 64000, 1, 4}, | ||
289 | |||
290 | /* 88.2k */ | ||
291 | {11289600, 88200, 1, 0}, | ||
292 | {16934400, 88200, 1, 1}, | ||
293 | {22579200, 88200, 1, 2}, | ||
294 | {33868000, 88200, 1, 3}, | ||
295 | {45158400, 88200, 1, 4}, | ||
296 | |||
297 | /* 96k */ | ||
298 | {12288000, 96000, 1, 0}, | ||
299 | {18432000, 96000, 1, 1}, | ||
300 | {24576000, 96000, 1, 2}, | ||
301 | {36864000, 96000, 1, 3}, | ||
302 | {49152000, 96000, 1, 4}, | ||
303 | |||
304 | /* 128k */ | ||
305 | {8192000, 128000, 2, 0}, | ||
306 | {12288000, 128000, 2, 1}, | ||
307 | {16934400, 128000, 2, 2}, | ||
308 | {24576000, 128000, 2, 3}, | ||
309 | {32768000, 128000, 2, 4}, | ||
310 | |||
311 | /* 176.4k */ | ||
312 | {11289600, 176400, 2, 0}, | ||
313 | {16934400, 176400, 2, 1}, | ||
314 | {22579200, 176400, 2, 2}, | ||
315 | {33868000, 176400, 2, 3}, | ||
316 | {49152000, 176400, 2, 4}, | ||
317 | |||
318 | /* 192k */ | ||
319 | {12288000, 192000, 2, 0}, | ||
320 | {18432000, 192000, 2, 1}, | ||
321 | {24576000, 192000, 2, 2}, | ||
322 | {36864000, 192000, 2, 3}, | ||
323 | {49152000, 192000, 2, 4}, | ||
324 | }; | ||
325 | |||
326 | static int cs4265_get_clk_index(int mclk, int rate) | ||
327 | { | ||
328 | int i; | ||
329 | |||
330 | for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { | ||
331 | if (clk_map_table[i].rate == rate && | ||
332 | clk_map_table[i].mclk == mclk) | ||
333 | return i; | ||
334 | } | ||
335 | return -EINVAL; | ||
336 | } | ||
337 | |||
338 | static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, | ||
339 | unsigned int freq, int dir) | ||
340 | { | ||
341 | struct snd_soc_codec *codec = codec_dai->codec; | ||
342 | struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec); | ||
343 | int i; | ||
344 | |||
345 | if (clk_id != 0) { | ||
346 | dev_err(codec->dev, "Invalid clk_id %d\n", clk_id); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { | ||
350 | if (clk_map_table[i].mclk == freq) { | ||
351 | cs4265->sysclk = freq; | ||
352 | return 0; | ||
353 | } | ||
354 | } | ||
355 | cs4265->sysclk = 0; | ||
356 | dev_err(codec->dev, "Invalid freq parameter %d\n", freq); | ||
357 | return -EINVAL; | ||
358 | } | ||
359 | |||
360 | static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
361 | { | ||
362 | struct snd_soc_codec *codec = codec_dai->codec; | ||
363 | struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec); | ||
364 | u8 iface = 0; | ||
365 | |||
366 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
367 | case SND_SOC_DAIFMT_CBM_CFM: | ||
368 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
369 | CS4265_ADC_MASTER, | ||
370 | CS4265_ADC_MASTER); | ||
371 | break; | ||
372 | case SND_SOC_DAIFMT_CBS_CFS: | ||
373 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
374 | CS4265_ADC_MASTER, | ||
375 | 0); | ||
376 | break; | ||
377 | default: | ||
378 | return -EINVAL; | ||
379 | } | ||
380 | |||
381 | /* interface format */ | ||
382 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
383 | case SND_SOC_DAIFMT_I2S: | ||
384 | iface |= SND_SOC_DAIFMT_I2S; | ||
385 | break; | ||
386 | case SND_SOC_DAIFMT_RIGHT_J: | ||
387 | iface |= SND_SOC_DAIFMT_RIGHT_J; | ||
388 | break; | ||
389 | case SND_SOC_DAIFMT_LEFT_J: | ||
390 | iface |= SND_SOC_DAIFMT_LEFT_J; | ||
391 | break; | ||
392 | default: | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | cs4265->format = iface; | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute) | ||
401 | { | ||
402 | struct snd_soc_codec *codec = dai->codec; | ||
403 | |||
404 | if (mute) { | ||
405 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | ||
406 | CS4265_DAC_CTL_MUTE, | ||
407 | CS4265_DAC_CTL_MUTE); | ||
408 | snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, | ||
409 | CS4265_SPDIF_CTL2_MUTE, | ||
410 | CS4265_SPDIF_CTL2_MUTE); | ||
411 | } else { | ||
412 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | ||
413 | CS4265_DAC_CTL_MUTE, | ||
414 | 0); | ||
415 | snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, | ||
416 | CS4265_SPDIF_CTL2_MUTE, | ||
417 | 0); | ||
418 | } | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, | ||
423 | struct snd_pcm_hw_params *params, | ||
424 | struct snd_soc_dai *dai) | ||
425 | { | ||
426 | struct snd_soc_codec *codec = dai->codec; | ||
427 | struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec); | ||
428 | int index; | ||
429 | |||
430 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && | ||
431 | ((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) | ||
432 | == SND_SOC_DAIFMT_RIGHT_J)) | ||
433 | return -EINVAL; | ||
434 | |||
435 | index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); | ||
436 | if (index >= 0) { | ||
437 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
438 | CS4265_ADC_FM, clk_map_table[index].fm_mode); | ||
439 | snd_soc_update_bits(codec, CS4265_MCLK_FREQ, | ||
440 | CS4265_MCLK_FREQ_MASK, | ||
441 | clk_map_table[index].mclkdiv); | ||
442 | |||
443 | } else { | ||
444 | dev_err(codec->dev, "can't get correct mclk\n"); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
449 | case SND_SOC_DAIFMT_I2S: | ||
450 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | ||
451 | CS4265_DAC_CTL_DIF, (1 << 4)); | ||
452 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
453 | CS4265_ADC_DIF, (1 << 4)); | ||
454 | snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, | ||
455 | CS4265_SPDIF_CTL2_DIF, (1 << 6)); | ||
456 | break; | ||
457 | case SND_SOC_DAIFMT_RIGHT_J: | ||
458 | if (params_width(params) == 16) { | ||
459 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | ||
460 | CS4265_DAC_CTL_DIF, (1 << 5)); | ||
461 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
462 | CS4265_SPDIF_CTL2_DIF, (1 << 7)); | ||
463 | } else { | ||
464 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | ||
465 | CS4265_DAC_CTL_DIF, (3 << 5)); | ||
466 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
467 | CS4265_SPDIF_CTL2_DIF, (1 << 7)); | ||
468 | } | ||
469 | break; | ||
470 | case SND_SOC_DAIFMT_LEFT_J: | ||
471 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | ||
472 | CS4265_DAC_CTL_DIF, 0); | ||
473 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
474 | CS4265_ADC_DIF, 0); | ||
475 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | ||
476 | CS4265_SPDIF_CTL2_DIF, (1 << 6)); | ||
477 | |||
478 | break; | ||
479 | default: | ||
480 | return -EINVAL; | ||
481 | } | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int cs4265_set_bias_level(struct snd_soc_codec *codec, | ||
486 | enum snd_soc_bias_level level) | ||
487 | { | ||
488 | switch (level) { | ||
489 | case SND_SOC_BIAS_ON: | ||
490 | break; | ||
491 | case SND_SOC_BIAS_PREPARE: | ||
492 | snd_soc_update_bits(codec, CS4265_PWRCTL, | ||
493 | CS4265_PWRCTL_PDN, 0); | ||
494 | break; | ||
495 | case SND_SOC_BIAS_STANDBY: | ||
496 | snd_soc_update_bits(codec, CS4265_PWRCTL, | ||
497 | CS4265_PWRCTL_PDN, | ||
498 | CS4265_PWRCTL_PDN); | ||
499 | break; | ||
500 | case SND_SOC_BIAS_OFF: | ||
501 | snd_soc_update_bits(codec, CS4265_PWRCTL, | ||
502 | CS4265_PWRCTL_PDN, | ||
503 | CS4265_PWRCTL_PDN); | ||
504 | break; | ||
505 | } | ||
506 | codec->dapm.bias_level = level; | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | #define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
511 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ | ||
512 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ | ||
513 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) | ||
514 | |||
515 | #define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ | ||
516 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE) | ||
517 | |||
518 | static const struct snd_soc_dai_ops cs4265_ops = { | ||
519 | .hw_params = cs4265_pcm_hw_params, | ||
520 | .digital_mute = cs4265_digital_mute, | ||
521 | .set_fmt = cs4265_set_fmt, | ||
522 | .set_sysclk = cs4265_set_sysclk, | ||
523 | }; | ||
524 | |||
525 | static struct snd_soc_dai_driver cs4265_dai[] = { | ||
526 | { | ||
527 | .name = "cs4265-dai1", | ||
528 | .playback = { | ||
529 | .stream_name = "DAI1 Playback", | ||
530 | .channels_min = 1, | ||
531 | .channels_max = 2, | ||
532 | .rates = CS4265_RATES, | ||
533 | .formats = CS4265_FORMATS, | ||
534 | }, | ||
535 | .capture = { | ||
536 | .stream_name = "DAI1 Capture", | ||
537 | .channels_min = 1, | ||
538 | .channels_max = 2, | ||
539 | .rates = CS4265_RATES, | ||
540 | .formats = CS4265_FORMATS, | ||
541 | }, | ||
542 | .ops = &cs4265_ops, | ||
543 | }, | ||
544 | { | ||
545 | .name = "cs4265-dai2", | ||
546 | .playback = { | ||
547 | .stream_name = "DAI2 Playback", | ||
548 | .channels_min = 1, | ||
549 | .channels_max = 2, | ||
550 | .rates = CS4265_RATES, | ||
551 | .formats = CS4265_FORMATS, | ||
552 | }, | ||
553 | .capture = { | ||
554 | .stream_name = "DAI2 Capture", | ||
555 | .channels_min = 1, | ||
556 | .channels_max = 2, | ||
557 | .rates = CS4265_RATES, | ||
558 | .formats = CS4265_FORMATS, | ||
559 | }, | ||
560 | .ops = &cs4265_ops, | ||
561 | }, | ||
562 | }; | ||
563 | |||
564 | static const struct snd_soc_codec_driver soc_codec_cs4265 = { | ||
565 | .set_bias_level = cs4265_set_bias_level, | ||
566 | |||
567 | .dapm_widgets = cs4265_dapm_widgets, | ||
568 | .num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets), | ||
569 | .dapm_routes = cs4265_audio_map, | ||
570 | .num_dapm_routes = ARRAY_SIZE(cs4265_audio_map), | ||
571 | |||
572 | .controls = cs4265_snd_controls, | ||
573 | .num_controls = ARRAY_SIZE(cs4265_snd_controls), | ||
574 | }; | ||
575 | |||
576 | static const struct regmap_config cs4265_regmap = { | ||
577 | .reg_bits = 8, | ||
578 | .val_bits = 8, | ||
579 | |||
580 | .max_register = CS4265_MAX_REGISTER, | ||
581 | .reg_defaults = cs4265_reg_defaults, | ||
582 | .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults), | ||
583 | .readable_reg = cs4265_readable_register, | ||
584 | .volatile_reg = cs4265_volatile_register, | ||
585 | .cache_type = REGCACHE_RBTREE, | ||
586 | }; | ||
587 | |||
588 | static int cs4265_i2c_probe(struct i2c_client *i2c_client, | ||
589 | const struct i2c_device_id *id) | ||
590 | { | ||
591 | struct cs4265_private *cs4265; | ||
592 | int ret = 0; | ||
593 | unsigned int devid = 0; | ||
594 | unsigned int reg; | ||
595 | |||
596 | cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private), | ||
597 | GFP_KERNEL); | ||
598 | if (cs4265 == NULL) | ||
599 | return -ENOMEM; | ||
600 | cs4265->dev = &i2c_client->dev; | ||
601 | |||
602 | cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); | ||
603 | if (IS_ERR(cs4265->regmap)) { | ||
604 | ret = PTR_ERR(cs4265->regmap); | ||
605 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); | ||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev, | ||
610 | "reset-gpios"); | ||
611 | if (IS_ERR(cs4265->reset_gpio)) { | ||
612 | ret = PTR_ERR(cs4265->reset_gpio); | ||
613 | if (ret != -ENOENT && ret != -ENOSYS) | ||
614 | return ret; | ||
615 | |||
616 | cs4265->reset_gpio = NULL; | ||
617 | } else { | ||
618 | ret = gpiod_direction_output(cs4265->reset_gpio, 0); | ||
619 | if (ret) | ||
620 | return ret; | ||
621 | mdelay(1); | ||
622 | gpiod_set_value_cansleep(cs4265->reset_gpio, 1); | ||
623 | |||
624 | } | ||
625 | |||
626 | i2c_set_clientdata(i2c_client, cs4265); | ||
627 | |||
628 | ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, ®); | ||
629 | devid = reg & CS4265_CHIP_ID_MASK; | ||
630 | if (devid != CS4265_CHIP_ID_VAL) { | ||
631 | ret = -ENODEV; | ||
632 | dev_err(&i2c_client->dev, | ||
633 | "CS4265 Device ID (%X). Expected %X\n", | ||
634 | devid, CS4265_CHIP_ID); | ||
635 | return ret; | ||
636 | } | ||
637 | dev_info(&i2c_client->dev, | ||
638 | "CS4265 Version %x\n", | ||
639 | reg & CS4265_REV_ID_MASK); | ||
640 | |||
641 | regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F); | ||
642 | |||
643 | ret = snd_soc_register_codec(&i2c_client->dev, | ||
644 | &soc_codec_cs4265, cs4265_dai, | ||
645 | ARRAY_SIZE(cs4265_dai)); | ||
646 | return ret; | ||
647 | } | ||
648 | |||
649 | static int cs4265_i2c_remove(struct i2c_client *client) | ||
650 | { | ||
651 | snd_soc_unregister_codec(&client->dev); | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static const struct of_device_id cs4265_of_match[] = { | ||
656 | { .compatible = "cirrus,cs4265", }, | ||
657 | { } | ||
658 | }; | ||
659 | MODULE_DEVICE_TABLE(of, cs4265_of_match); | ||
660 | |||
661 | static const struct i2c_device_id cs4265_id[] = { | ||
662 | { "cs4265", 0 }, | ||
663 | { } | ||
664 | }; | ||
665 | MODULE_DEVICE_TABLE(i2c, cs4265_id); | ||
666 | |||
667 | static struct i2c_driver cs4265_i2c_driver = { | ||
668 | .driver = { | ||
669 | .name = "cs4265", | ||
670 | .owner = THIS_MODULE, | ||
671 | .of_match_table = cs4265_of_match, | ||
672 | }, | ||
673 | .id_table = cs4265_id, | ||
674 | .probe = cs4265_i2c_probe, | ||
675 | .remove = cs4265_i2c_remove, | ||
676 | }; | ||
677 | |||
678 | module_i2c_driver(cs4265_i2c_driver); | ||
679 | |||
680 | MODULE_DESCRIPTION("ASoC CS4265 driver"); | ||
681 | MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>"); | ||
682 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs4265.h b/sound/soc/codecs/cs4265.h new file mode 100644 index 000000000000..0a80a8dcec67 --- /dev/null +++ b/sound/soc/codecs/cs4265.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * cs4265.h -- CS4265 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2014 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Author: Paul Handrigan <paul.handrigan@cirrus.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef __CS4265_H__ | ||
15 | #define __CS4265_H__ | ||
16 | |||
17 | #define CS4265_CHIP_ID 0x1 | ||
18 | #define CS4265_CHIP_ID_VAL 0xD0 | ||
19 | #define CS4265_CHIP_ID_MASK 0xF0 | ||
20 | #define CS4265_REV_ID_MASK 0x0F | ||
21 | |||
22 | #define CS4265_PWRCTL 0x02 | ||
23 | #define CS4265_PWRCTL_PDN 1 | ||
24 | |||
25 | #define CS4265_DAC_CTL 0x3 | ||
26 | #define CS4265_DAC_CTL_MUTE (1 << 2) | ||
27 | #define CS4265_DAC_CTL_DIF (3 << 4) | ||
28 | |||
29 | #define CS4265_ADC_CTL 0x4 | ||
30 | #define CS4265_ADC_MASTER 1 | ||
31 | #define CS4265_ADC_DIF (1 << 4) | ||
32 | #define CS4265_ADC_FM (3 << 6) | ||
33 | |||
34 | #define CS4265_MCLK_FREQ 0x5 | ||
35 | #define CS4265_MCLK_FREQ_MASK (7 << 4) | ||
36 | |||
37 | #define CS4265_SIG_SEL 0x6 | ||
38 | #define CS4265_SIG_SEL_LOOP (1 << 1) | ||
39 | |||
40 | #define CS4265_CHB_PGA_CTL 0x7 | ||
41 | #define CS4265_CHA_PGA_CTL 0x8 | ||
42 | |||
43 | #define CS4265_ADC_CTL2 0x9 | ||
44 | |||
45 | #define CS4265_DAC_CHA_VOL 0xA | ||
46 | #define CS4265_DAC_CHB_VOL 0xB | ||
47 | |||
48 | #define CS4265_DAC_CTL2 0xC | ||
49 | |||
50 | #define CS4265_INT_STATUS 0xD | ||
51 | #define CS4265_INT_MASK 0xE | ||
52 | #define CS4265_STATUS_MODE_MSB 0xF | ||
53 | #define CS4265_STATUS_MODE_LSB 0x10 | ||
54 | |||
55 | #define CS4265_SPDIF_CTL1 0x11 | ||
56 | |||
57 | #define CS4265_SPDIF_CTL2 0x12 | ||
58 | #define CS4265_SPDIF_CTL2_MUTE (1 << 4) | ||
59 | #define CS4265_SPDIF_CTL2_DIF (3 << 6) | ||
60 | |||
61 | #define CS4265_C_DATA_BUFF 0x13 | ||
62 | #define CS4265_MAX_REGISTER 0x2A | ||
63 | |||
64 | #endif | ||
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 071fc77f2f06..969167d8b71e 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
@@ -399,15 +399,15 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { | |||
399 | CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv), | 399 | CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv), |
400 | 400 | ||
401 | SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL, | 401 | SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL, |
402 | CS42L52_HPB_VOL, 0, 0x34, 0xCC, hpd_tlv), | 402 | CS42L52_HPB_VOL, 0, 0x34, 0xC0, hpd_tlv), |
403 | 403 | ||
404 | SOC_ENUM("Headphone Analog Gain", hp_gain_enum), | 404 | SOC_ENUM("Headphone Analog Gain", hp_gain_enum), |
405 | 405 | ||
406 | SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL, | 406 | SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL, |
407 | CS42L52_SPKB_VOL, 0, 0x1, 0xff, hl_tlv), | 407 | CS42L52_SPKB_VOL, 0, 0x40, 0xC0, hl_tlv), |
408 | 408 | ||
409 | SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL, | 409 | SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL, |
410 | CS42L52_PASSTHRUB_VOL, 6, 0x18, 0x90, pga_tlv), | 410 | CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pga_tlv), |
411 | 411 | ||
412 | SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), | 412 | SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), |
413 | 413 | ||
@@ -417,10 +417,10 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { | |||
417 | SOC_ENUM("MIC Bias Level", mic_bias_level_enum), | 417 | SOC_ENUM("MIC Bias Level", mic_bias_level_enum), |
418 | 418 | ||
419 | SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL, | 419 | SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL, |
420 | CS42L52_ADCB_VOL, 7, 0x80, 0xA0, ipd_tlv), | 420 | CS42L52_ADCB_VOL, 0, 0xA0, 0x78, ipd_tlv), |
421 | SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", | 421 | SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", |
422 | CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL, | 422 | CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL, |
423 | 6, 0x7f, 0x19, ipd_tlv), | 423 | 0, 0x19, 0x7F, ipd_tlv), |
424 | 424 | ||
425 | SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0), | 425 | SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0), |
426 | 426 | ||
@@ -428,11 +428,11 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { | |||
428 | CS42L52_ADCB_MIXER_VOL, 7, 1, 1), | 428 | CS42L52_ADCB_MIXER_VOL, 7, 1, 1), |
429 | 429 | ||
430 | SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL, | 430 | SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL, |
431 | CS42L52_PGAB_CTL, 0, 0x28, 0x30, pga_tlv), | 431 | CS42L52_PGAB_CTL, 0, 0x28, 0x24, pga_tlv), |
432 | 432 | ||
433 | SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", | 433 | SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", |
434 | CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, | 434 | CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, |
435 | 0, 0x7f, 0x19, mix_tlv), | 435 | 0, 0x19, 0x7f, mix_tlv), |
436 | SOC_DOUBLE_R("PCM Mixer Switch", | 436 | SOC_DOUBLE_R("PCM Mixer Switch", |
437 | CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1), | 437 | CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1), |
438 | 438 | ||
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index fdc4bd27b0df..c766a5a9ce80 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c | |||
@@ -318,24 +318,32 @@ static const struct soc_enum adca_swap_enum = | |||
318 | ARRAY_SIZE(left_swap_text), | 318 | ARRAY_SIZE(left_swap_text), |
319 | left_swap_text, | 319 | left_swap_text, |
320 | swap_values); | 320 | swap_values); |
321 | static const struct snd_kcontrol_new adca_swap_mux = | ||
322 | SOC_DAPM_ENUM("Route", adca_swap_enum); | ||
321 | 323 | ||
322 | static const struct soc_enum pcma_swap_enum = | 324 | static const struct soc_enum pcma_swap_enum = |
323 | SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3, | 325 | SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3, |
324 | ARRAY_SIZE(left_swap_text), | 326 | ARRAY_SIZE(left_swap_text), |
325 | left_swap_text, | 327 | left_swap_text, |
326 | swap_values); | 328 | swap_values); |
329 | static const struct snd_kcontrol_new pcma_swap_mux = | ||
330 | SOC_DAPM_ENUM("Route", pcma_swap_enum); | ||
327 | 331 | ||
328 | static const struct soc_enum adcb_swap_enum = | 332 | static const struct soc_enum adcb_swap_enum = |
329 | SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3, | 333 | SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3, |
330 | ARRAY_SIZE(right_swap_text), | 334 | ARRAY_SIZE(right_swap_text), |
331 | right_swap_text, | 335 | right_swap_text, |
332 | swap_values); | 336 | swap_values); |
337 | static const struct snd_kcontrol_new adcb_swap_mux = | ||
338 | SOC_DAPM_ENUM("Route", adcb_swap_enum); | ||
333 | 339 | ||
334 | static const struct soc_enum pcmb_swap_enum = | 340 | static const struct soc_enum pcmb_swap_enum = |
335 | SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3, | 341 | SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3, |
336 | ARRAY_SIZE(right_swap_text), | 342 | ARRAY_SIZE(right_swap_text), |
337 | right_swap_text, | 343 | right_swap_text, |
338 | swap_values); | 344 | swap_values); |
345 | static const struct snd_kcontrol_new pcmb_swap_mux = | ||
346 | SOC_DAPM_ENUM("Route", pcmb_swap_enum); | ||
339 | 347 | ||
340 | static const struct snd_kcontrol_new hpa_switch = | 348 | static const struct snd_kcontrol_new hpa_switch = |
341 | SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1); | 349 | SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1); |
@@ -421,15 +429,15 @@ static const struct soc_enum ng_delay_enum = | |||
421 | static const struct snd_kcontrol_new cs42l56_snd_controls[] = { | 429 | static const struct snd_kcontrol_new cs42l56_snd_controls[] = { |
422 | 430 | ||
423 | SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME, | 431 | SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME, |
424 | CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv), | 432 | CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv), |
425 | SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1), | 433 | SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1), |
426 | 434 | ||
427 | SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME, | 435 | SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME, |
428 | CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), | 436 | CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv), |
429 | SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1), | 437 | SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1), |
430 | 438 | ||
431 | SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME, | 439 | SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME, |
432 | CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), | 440 | CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv), |
433 | SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1), | 441 | SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1), |
434 | 442 | ||
435 | SOC_SINGLE_TLV("Analog Advisory Volume", | 443 | SOC_SINGLE_TLV("Analog Advisory Volume", |
@@ -438,16 +446,16 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { | |||
438 | CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), | 446 | CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), |
439 | 447 | ||
440 | SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME, | 448 | SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME, |
441 | CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv), | 449 | CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv), |
442 | SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR, | 450 | SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR, |
443 | CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv), | 451 | CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv), |
444 | SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1), | 452 | SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1), |
445 | SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), | 453 | SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), |
446 | 454 | ||
447 | SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, | 455 | SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, |
448 | CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv), | 456 | CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv), |
449 | SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, | 457 | SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, |
450 | CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv), | 458 | CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv), |
451 | 459 | ||
452 | SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, | 460 | SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, |
453 | 0, 0x00, 1, tone_tlv), | 461 | 0, 0x00, 1, tone_tlv), |
@@ -467,11 +475,6 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { | |||
467 | SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1), | 475 | SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1), |
468 | SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1), | 476 | SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1), |
469 | 477 | ||
470 | SOC_ENUM("PCMA Swap", pcma_swap_enum), | ||
471 | SOC_ENUM("PCMB Swap", pcmb_swap_enum), | ||
472 | SOC_ENUM("ADCA Swap", adca_swap_enum), | ||
473 | SOC_ENUM("ADCB Swap", adcb_swap_enum), | ||
474 | |||
475 | SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1), | 478 | SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1), |
476 | SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1), | 479 | SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1), |
477 | SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum), | 480 | SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum), |
@@ -570,6 +573,16 @@ static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = { | |||
570 | SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1), | 573 | SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1), |
571 | SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1), | 574 | SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1), |
572 | 575 | ||
576 | SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0, | ||
577 | &adca_swap_mux), | ||
578 | SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0, | ||
579 | &adcb_swap_mux), | ||
580 | |||
581 | SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0, | ||
582 | &pcma_swap_mux), | ||
583 | SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0, | ||
584 | &pcmb_swap_mux), | ||
585 | |||
573 | SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0), | 586 | SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0), |
574 | SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0), | 587 | SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0), |
575 | 588 | ||
@@ -607,8 +620,19 @@ static const struct snd_soc_dapm_route cs42l56_audio_map[] = { | |||
607 | {"Digital Output Mux", NULL, "ADCA"}, | 620 | {"Digital Output Mux", NULL, "ADCA"}, |
608 | {"Digital Output Mux", NULL, "ADCB"}, | 621 | {"Digital Output Mux", NULL, "ADCB"}, |
609 | 622 | ||
610 | {"ADCB", NULL, "ADCB Mux"}, | 623 | {"ADCB", NULL, "ADCB Swap Mux"}, |
611 | {"ADCA", NULL, "ADCA Mux"}, | 624 | {"ADCA", NULL, "ADCA Swap Mux"}, |
625 | |||
626 | {"ADCA Swap Mux", NULL, "ADCA"}, | ||
627 | {"ADCB Swap Mux", NULL, "ADCB"}, | ||
628 | |||
629 | {"DACA", "Left", "ADCA Swap Mux"}, | ||
630 | {"DACA", "LR 2", "ADCA Swap Mux"}, | ||
631 | {"DACA", "Right", "ADCA Swap Mux"}, | ||
632 | |||
633 | {"DACB", "Left", "ADCB Swap Mux"}, | ||
634 | {"DACB", "LR 2", "ADCB Swap Mux"}, | ||
635 | {"DACB", "Right", "ADCB Swap Mux"}, | ||
612 | 636 | ||
613 | {"ADCA Mux", NULL, "AIN3A"}, | 637 | {"ADCA Mux", NULL, "AIN3A"}, |
614 | {"ADCA Mux", NULL, "AIN2A"}, | 638 | {"ADCA Mux", NULL, "AIN2A"}, |
@@ -633,30 +657,32 @@ static const struct snd_soc_dapm_route cs42l56_audio_map[] = { | |||
633 | {"PGAB Input Mux", NULL, "AIN2B"}, | 657 | {"PGAB Input Mux", NULL, "AIN2B"}, |
634 | {"PGAB Input Mux", NULL, "AIN3B"}, | 658 | {"PGAB Input Mux", NULL, "AIN3B"}, |
635 | 659 | ||
636 | {"LOB", NULL, "Lineout Right"}, | 660 | {"LOB", "Switch", "LINEOUTB Input Mux"}, |
637 | {"LOA", NULL, "Lineout Left"}, | 661 | {"LOA", "Switch", "LINEOUTA Input Mux"}, |
638 | |||
639 | {"Lineout Right", "Switch", "LINEOUTB Input Mux"}, | ||
640 | {"Lineout Left", "Switch", "LINEOUTA Input Mux"}, | ||
641 | 662 | ||
642 | {"LINEOUTA Input Mux", "PGAA", "PGAA"}, | 663 | {"LINEOUTA Input Mux", "PGAA", "PGAA"}, |
643 | {"LINEOUTB Input Mux", "PGAB", "PGAB"}, | 664 | {"LINEOUTB Input Mux", "PGAB", "PGAB"}, |
644 | {"LINEOUTA Input Mux", "DACA", "DACA"}, | 665 | {"LINEOUTA Input Mux", "DACA", "DACA"}, |
645 | {"LINEOUTB Input Mux", "DACB", "DACB"}, | 666 | {"LINEOUTB Input Mux", "DACB", "DACB"}, |
646 | 667 | ||
647 | {"HPA", NULL, "Headphone Left"}, | 668 | {"HPA", "Switch", "HPB Input Mux"}, |
648 | {"HPB", NULL, "Headphone Right"}, | 669 | {"HPB", "Switch", "HPA Input Mux"}, |
649 | |||
650 | {"Headphone Right", "Switch", "HPB Input Mux"}, | ||
651 | {"Headphone Left", "Switch", "HPA Input Mux"}, | ||
652 | 670 | ||
653 | {"HPA Input Mux", "PGAA", "PGAA"}, | 671 | {"HPA Input Mux", "PGAA", "PGAA"}, |
654 | {"HPB Input Mux", "PGAB", "PGAB"}, | 672 | {"HPB Input Mux", "PGAB", "PGAB"}, |
655 | {"HPA Input Mux", "DACA", "DACA"}, | 673 | {"HPA Input Mux", "DACA", "DACA"}, |
656 | {"HPB Input Mux", "DACB", "DACB"}, | 674 | {"HPB Input Mux", "DACB", "DACB"}, |
657 | 675 | ||
658 | {"DACB", NULL, "HiFi Playback"}, | 676 | {"DACA", NULL, "PCMA Swap Mux"}, |
659 | {"DACA", NULL, "HiFi Playback"}, | 677 | {"DACB", NULL, "PCMB Swap Mux"}, |
678 | |||
679 | {"PCMB Swap Mux", "Left", "HiFi Playback"}, | ||
680 | {"PCMB Swap Mux", "LR 2", "HiFi Playback"}, | ||
681 | {"PCMB Swap Mux", "Right", "HiFi Playback"}, | ||
682 | |||
683 | {"PCMA Swap Mux", "Left", "HiFi Playback"}, | ||
684 | {"PCMA Swap Mux", "LR 2", "HiFi Playback"}, | ||
685 | {"PCMA Swap Mux", "Right", "HiFi Playback"}, | ||
660 | 686 | ||
661 | }; | 687 | }; |
662 | 688 | ||
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index ae3717992d56..8658194f50bf 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -401,7 +401,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { | |||
401 | CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv), | 401 | CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv), |
402 | 402 | ||
403 | SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL, | 403 | SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL, |
404 | CS42L73_MICBPREPGABVOL, 5, 0x34, | 404 | CS42L73_MICBPREPGABVOL, 0, 0x34, |
405 | 0x24, micpga_tlv), | 405 | 0x24, micpga_tlv), |
406 | 406 | ||
407 | SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL, | 407 | SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL, |
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index a25bc6061a30..02b1520ae0bc 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c | |||
@@ -219,6 +219,9 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
219 | case SND_SOC_DAIFMT_RIGHT_J: | 219 | case SND_SOC_DAIFMT_RIGHT_J: |
220 | val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ; | 220 | val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ; |
221 | break; | 221 | break; |
222 | case SND_SOC_DAIFMT_DSP_A: | ||
223 | val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM; | ||
224 | break; | ||
222 | default: | 225 | default: |
223 | dev_err(codec->dev, "unsupported dai format\n"); | 226 | dev_err(codec->dev, "unsupported dai format\n"); |
224 | return -EINVAL; | 227 | return -EINVAL; |
@@ -422,7 +425,7 @@ const struct cs42xx8_driver_data cs42888_data = { | |||
422 | }; | 425 | }; |
423 | EXPORT_SYMBOL_GPL(cs42888_data); | 426 | EXPORT_SYMBOL_GPL(cs42888_data); |
424 | 427 | ||
425 | const struct of_device_id cs42xx8_of_match[] = { | 428 | static const struct of_device_id cs42xx8_of_match[] = { |
426 | { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, | 429 | { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, |
427 | { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, | 430 | { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, |
428 | { /* sentinel */ } | 431 | { /* sentinel */ } |
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h index da0b94aee419..b2c10e537ef6 100644 --- a/sound/soc/codecs/cs42xx8.h +++ b/sound/soc/codecs/cs42xx8.h | |||
@@ -128,8 +128,8 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap); | |||
128 | #define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT) | 128 | #define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT) |
129 | #define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT) | 129 | #define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT) |
130 | #define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT) | 130 | #define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT) |
131 | #define CS42XX8_INTF_DAC_DIF_ONELINE_24 (6 << CS42XX8_INTF_DAC_DIF_SHIFT) | 131 | #define CS42XX8_INTF_DAC_DIF_ONELINE_24 (5 << CS42XX8_INTF_DAC_DIF_SHIFT) |
132 | #define CS42XX8_INTF_DAC_DIF_TDM (7 << CS42XX8_INTF_DAC_DIF_SHIFT) | 132 | #define CS42XX8_INTF_DAC_DIF_TDM (6 << CS42XX8_INTF_DAC_DIF_SHIFT) |
133 | #define CS42XX8_INTF_ADC_DIF_SHIFT 0 | 133 | #define CS42XX8_INTF_ADC_DIF_SHIFT 0 |
134 | #define CS42XX8_INTF_ADC_DIF_WIDTH 3 | 134 | #define CS42XX8_INTF_ADC_DIF_WIDTH 3 |
135 | #define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT) | 135 | #define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT) |
@@ -138,8 +138,8 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap); | |||
138 | #define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT) | 138 | #define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT) |
139 | #define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT) | 139 | #define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT) |
140 | #define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT) | 140 | #define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT) |
141 | #define CS42XX8_INTF_ADC_DIF_ONELINE_24 (6 << CS42XX8_INTF_ADC_DIF_SHIFT) | 141 | #define CS42XX8_INTF_ADC_DIF_ONELINE_24 (5 << CS42XX8_INTF_ADC_DIF_SHIFT) |
142 | #define CS42XX8_INTF_ADC_DIF_TDM (7 << CS42XX8_INTF_ADC_DIF_SHIFT) | 142 | #define CS42XX8_INTF_ADC_DIF_TDM (6 << CS42XX8_INTF_ADC_DIF_SHIFT) |
143 | 143 | ||
144 | /* ADC Control & DAC De-Emphasis (Address 05h) */ | 144 | /* ADC Control & DAC De-Emphasis (Address 05h) */ |
145 | #define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7 | 145 | #define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7 |
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index d5fd00a64748..8f95b0300f1a 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c | |||
@@ -253,7 +253,7 @@ static void v253_close(struct tty_struct *tty) | |||
253 | /* Prevent the codec driver from further accessing the modem */ | 253 | /* Prevent the codec driver from further accessing the modem */ |
254 | codec->hw_write = NULL; | 254 | codec->hw_write = NULL; |
255 | cx20442->control_data = NULL; | 255 | cx20442->control_data = NULL; |
256 | codec->card->pop_time = 0; | 256 | codec->component.card->pop_time = 0; |
257 | } | 257 | } |
258 | 258 | ||
259 | /* Line discipline .hangup() */ | 259 | /* Line discipline .hangup() */ |
@@ -281,7 +281,7 @@ static void v253_receive(struct tty_struct *tty, | |||
281 | /* Set up codec driver access to modem controls */ | 281 | /* Set up codec driver access to modem controls */ |
282 | cx20442->control_data = tty; | 282 | cx20442->control_data = tty; |
283 | codec->hw_write = (hw_write_t)tty->ops->write; | 283 | codec->hw_write = (hw_write_t)tty->ops->write; |
284 | codec->card->pop_time = 1; | 284 | codec->component.card->pop_time = 1; |
285 | } | 285 | } |
286 | } | 286 | } |
287 | 287 | ||
@@ -372,7 +372,7 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec) | |||
372 | 372 | ||
373 | snd_soc_codec_set_drvdata(codec, cx20442); | 373 | snd_soc_codec_set_drvdata(codec, cx20442); |
374 | codec->hw_write = NULL; | 374 | codec->hw_write = NULL; |
375 | codec->card->pop_time = 0; | 375 | codec->component.card->pop_time = 0; |
376 | 376 | ||
377 | return 0; | 377 | return 0; |
378 | } | 378 | } |
@@ -383,8 +383,8 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec) | |||
383 | struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec); | 383 | struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec); |
384 | 384 | ||
385 | if (cx20442->control_data) { | 385 | if (cx20442->control_data) { |
386 | struct tty_struct *tty = cx20442->control_data; | 386 | struct tty_struct *tty = cx20442->control_data; |
387 | tty_hangup(tty); | 387 | tty_hangup(tty); |
388 | } | 388 | } |
389 | 389 | ||
390 | if (!IS_ERR(cx20442->por)) { | 390 | if (!IS_ERR(cx20442->por)) { |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f5fccc7a8e89..4a063fa88526 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -26,10 +26,6 @@ | |||
26 | #include <sound/max98090.h> | 26 | #include <sound/max98090.h> |
27 | #include "max98090.h" | 27 | #include "max98090.h" |
28 | 28 | ||
29 | #define DEBUG | ||
30 | #define EXTMIC_METHOD | ||
31 | #define EXTMIC_METHOD_TEST | ||
32 | |||
33 | /* Allows for sparsely populated register maps */ | 29 | /* Allows for sparsely populated register maps */ |
34 | static struct reg_default max98090_reg[] = { | 30 | static struct reg_default max98090_reg[] = { |
35 | { 0x00, 0x00 }, /* 00 Software Reset */ | 31 | { 0x00, 0x00 }, /* 00 Software Reset */ |
@@ -820,7 +816,6 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, | |||
820 | else | 816 | else |
821 | val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT; | 817 | val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT; |
822 | 818 | ||
823 | |||
824 | if (val >= 1) { | 819 | if (val >= 1) { |
825 | if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) { | 820 | if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) { |
826 | max98090->pa1en = val - 1; /* Update for volatile */ | 821 | max98090->pa1en = val - 1; /* Update for volatile */ |
@@ -1140,7 +1135,6 @@ static const struct snd_kcontrol_new max98090_mixhprsel_mux = | |||
1140 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); | 1135 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); |
1141 | 1136 | ||
1142 | static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { | 1137 | static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { |
1143 | |||
1144 | SND_SOC_DAPM_INPUT("MIC1"), | 1138 | SND_SOC_DAPM_INPUT("MIC1"), |
1145 | SND_SOC_DAPM_INPUT("MIC2"), | 1139 | SND_SOC_DAPM_INPUT("MIC2"), |
1146 | SND_SOC_DAPM_INPUT("DMICL"), | 1140 | SND_SOC_DAPM_INPUT("DMICL"), |
@@ -1304,7 +1298,6 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { | |||
1304 | }; | 1298 | }; |
1305 | 1299 | ||
1306 | static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { | 1300 | static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { |
1307 | |||
1308 | SND_SOC_DAPM_INPUT("DMIC3"), | 1301 | SND_SOC_DAPM_INPUT("DMIC3"), |
1309 | SND_SOC_DAPM_INPUT("DMIC4"), | 1302 | SND_SOC_DAPM_INPUT("DMIC4"), |
1310 | 1303 | ||
@@ -1315,7 +1308,6 @@ static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { | |||
1315 | }; | 1308 | }; |
1316 | 1309 | ||
1317 | static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | 1310 | static const struct snd_soc_dapm_route max98090_dapm_routes[] = { |
1318 | |||
1319 | {"MIC1 Input", NULL, "MIC1"}, | 1311 | {"MIC1 Input", NULL, "MIC1"}, |
1320 | {"MIC2 Input", NULL, "MIC2"}, | 1312 | {"MIC2 Input", NULL, "MIC2"}, |
1321 | 1313 | ||
@@ -1493,17 +1485,14 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1493 | {"SPKR", NULL, "SPK Right Out"}, | 1485 | {"SPKR", NULL, "SPK Right Out"}, |
1494 | {"RCVL", NULL, "RCV Left Out"}, | 1486 | {"RCVL", NULL, "RCV Left Out"}, |
1495 | {"RCVR", NULL, "RCV Right Out"}, | 1487 | {"RCVR", NULL, "RCV Right Out"}, |
1496 | |||
1497 | }; | 1488 | }; |
1498 | 1489 | ||
1499 | static const struct snd_soc_dapm_route max98091_dapm_routes[] = { | 1490 | static const struct snd_soc_dapm_route max98091_dapm_routes[] = { |
1500 | |||
1501 | /* DMIC inputs */ | 1491 | /* DMIC inputs */ |
1502 | {"DMIC3", NULL, "DMIC3_ENA"}, | 1492 | {"DMIC3", NULL, "DMIC3_ENA"}, |
1503 | {"DMIC4", NULL, "DMIC4_ENA"}, | 1493 | {"DMIC4", NULL, "DMIC4_ENA"}, |
1504 | {"DMIC3", NULL, "AHPF"}, | 1494 | {"DMIC3", NULL, "AHPF"}, |
1505 | {"DMIC4", NULL, "AHPF"}, | 1495 | {"DMIC4", NULL, "AHPF"}, |
1506 | |||
1507 | }; | 1496 | }; |
1508 | 1497 | ||
1509 | static int max98090_add_widgets(struct snd_soc_codec *codec) | 1498 | static int max98090_add_widgets(struct snd_soc_codec *codec) |
@@ -1531,7 +1520,6 @@ static int max98090_add_widgets(struct snd_soc_codec *codec) | |||
1531 | 1520 | ||
1532 | snd_soc_dapm_add_routes(dapm, max98091_dapm_routes, | 1521 | snd_soc_dapm_add_routes(dapm, max98091_dapm_routes, |
1533 | ARRAY_SIZE(max98091_dapm_routes)); | 1522 | ARRAY_SIZE(max98091_dapm_routes)); |
1534 | |||
1535 | } | 1523 | } |
1536 | 1524 | ||
1537 | return 0; | 1525 | return 0; |
@@ -2212,22 +2200,11 @@ static struct snd_soc_dai_driver max98090_dai[] = { | |||
2212 | } | 2200 | } |
2213 | }; | 2201 | }; |
2214 | 2202 | ||
2215 | static void max98090_handle_pdata(struct snd_soc_codec *codec) | ||
2216 | { | ||
2217 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | ||
2218 | struct max98090_pdata *pdata = max98090->pdata; | ||
2219 | |||
2220 | if (!pdata) { | ||
2221 | dev_err(codec->dev, "No platform data\n"); | ||
2222 | return; | ||
2223 | } | ||
2224 | |||
2225 | } | ||
2226 | |||
2227 | static int max98090_probe(struct snd_soc_codec *codec) | 2203 | static int max98090_probe(struct snd_soc_codec *codec) |
2228 | { | 2204 | { |
2229 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 2205 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
2230 | struct max98090_cdata *cdata; | 2206 | struct max98090_cdata *cdata; |
2207 | enum max98090_type devtype; | ||
2231 | int ret = 0; | 2208 | int ret = 0; |
2232 | 2209 | ||
2233 | dev_dbg(codec->dev, "max98090_probe\n"); | 2210 | dev_dbg(codec->dev, "max98090_probe\n"); |
@@ -2263,16 +2240,21 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2263 | } | 2240 | } |
2264 | 2241 | ||
2265 | if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) { | 2242 | if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) { |
2266 | max98090->devtype = MAX98090; | 2243 | devtype = MAX98090; |
2267 | dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret); | 2244 | dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret); |
2268 | } else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) { | 2245 | } else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) { |
2269 | max98090->devtype = MAX98091; | 2246 | devtype = MAX98091; |
2270 | dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret); | 2247 | dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret); |
2271 | } else { | 2248 | } else { |
2272 | max98090->devtype = MAX98090; | 2249 | devtype = MAX98090; |
2273 | dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret); | 2250 | dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret); |
2274 | } | 2251 | } |
2275 | 2252 | ||
2253 | if (max98090->devtype != devtype) { | ||
2254 | dev_warn(codec->dev, "Mismatch in DT specified CODEC type.\n"); | ||
2255 | max98090->devtype = devtype; | ||
2256 | } | ||
2257 | |||
2276 | max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; | 2258 | max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; |
2277 | 2259 | ||
2278 | INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); | 2260 | INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); |
@@ -2284,7 +2266,7 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2284 | /* Register for interrupts */ | 2266 | /* Register for interrupts */ |
2285 | dev_dbg(codec->dev, "irq = %d\n", max98090->irq); | 2267 | dev_dbg(codec->dev, "irq = %d\n", max98090->irq); |
2286 | 2268 | ||
2287 | ret = request_threaded_irq(max98090->irq, NULL, | 2269 | ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL, |
2288 | max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 2270 | max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
2289 | "max98090_interrupt", codec); | 2271 | "max98090_interrupt", codec); |
2290 | if (ret < 0) { | 2272 | if (ret < 0) { |
@@ -2317,8 +2299,6 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2317 | snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, | 2299 | snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, |
2318 | M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); | 2300 | M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); |
2319 | 2301 | ||
2320 | max98090_handle_pdata(codec); | ||
2321 | |||
2322 | max98090_add_widgets(codec); | 2302 | max98090_add_widgets(codec); |
2323 | 2303 | ||
2324 | err_access: | 2304 | err_access: |
@@ -2428,7 +2408,7 @@ static int max98090_runtime_suspend(struct device *dev) | |||
2428 | } | 2408 | } |
2429 | #endif | 2409 | #endif |
2430 | 2410 | ||
2431 | #ifdef CONFIG_PM | 2411 | #ifdef CONFIG_PM_SLEEP |
2432 | static int max98090_resume(struct device *dev) | 2412 | static int max98090_resume(struct device *dev) |
2433 | { | 2413 | { |
2434 | struct max98090_priv *max98090 = dev_get_drvdata(dev); | 2414 | struct max98090_priv *max98090 = dev_get_drvdata(dev); |
@@ -2460,12 +2440,14 @@ static const struct dev_pm_ops max98090_pm = { | |||
2460 | 2440 | ||
2461 | static const struct i2c_device_id max98090_i2c_id[] = { | 2441 | static const struct i2c_device_id max98090_i2c_id[] = { |
2462 | { "max98090", MAX98090 }, | 2442 | { "max98090", MAX98090 }, |
2443 | { "max98091", MAX98091 }, | ||
2463 | { } | 2444 | { } |
2464 | }; | 2445 | }; |
2465 | MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); | 2446 | MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); |
2466 | 2447 | ||
2467 | static const struct of_device_id max98090_of_match[] = { | 2448 | static const struct of_device_id max98090_of_match[] = { |
2468 | { .compatible = "maxim,max98090", }, | 2449 | { .compatible = "maxim,max98090", }, |
2450 | { .compatible = "maxim,max98091", }, | ||
2469 | { } | 2451 | { } |
2470 | }; | 2452 | }; |
2471 | MODULE_DEVICE_TABLE(of, max98090_of_match); | 2453 | MODULE_DEVICE_TABLE(of, max98090_of_match); |
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 3a80ba4452df..57b0c94a710b 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #define PCM1792A_DAC_VOL_LEFT 0x10 | 36 | #define PCM1792A_DAC_VOL_LEFT 0x10 |
37 | #define PCM1792A_DAC_VOL_RIGHT 0x11 | 37 | #define PCM1792A_DAC_VOL_RIGHT 0x11 |
38 | #define PCM1792A_FMT_CONTROL 0x12 | 38 | #define PCM1792A_FMT_CONTROL 0x12 |
39 | #define PCM1792A_MODE_CONTROL 0x13 | ||
39 | #define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL | 40 | #define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL |
40 | 41 | ||
41 | #define PCM1792A_FMT_MASK 0x70 | 42 | #define PCM1792A_FMT_MASK 0x70 |
@@ -164,6 +165,8 @@ static const struct snd_kcontrol_new pcm1792a_controls[] = { | |||
164 | SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, | 165 | SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, |
165 | PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, | 166 | PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, |
166 | pcm1792a_dac_tlv), | 167 | pcm1792a_dac_tlv), |
168 | SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0), | ||
169 | SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0), | ||
167 | }; | 170 | }; |
168 | 171 | ||
169 | static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = { | 172 | static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = { |
diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h index 7a83d1fc102a..51d5470fee16 100644 --- a/sound/soc/codecs/pcm1792a.h +++ b/sound/soc/codecs/pcm1792a.h | |||
@@ -18,7 +18,8 @@ | |||
18 | #define __PCM1792A_H__ | 18 | #define __PCM1792A_H__ |
19 | 19 | ||
20 | #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ | 20 | #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ |
21 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) | 21 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ |
22 | SNDRV_PCM_RATE_192000) | ||
22 | 23 | ||
23 | #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ | 24 | #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ |
24 | SNDRV_PCM_FMTBIT_S16_LE) | 25 | SNDRV_PCM_FMTBIT_S16_LE) |
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c new file mode 100644 index 000000000000..218f86efd196 --- /dev/null +++ b/sound/soc/codecs/rt286.c | |||
@@ -0,0 +1,1224 @@ | |||
1 | /* | ||
2 | * rt286.c -- RT286 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Bard Liao <bardliao@realtek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/pm.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/spi/spi.h> | ||
20 | #include <linux/acpi.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | #include <sound/jack.h> | ||
29 | #include <linux/workqueue.h> | ||
30 | #include <sound/rt286.h> | ||
31 | #include <sound/hda_verbs.h> | ||
32 | |||
33 | #include "rt286.h" | ||
34 | |||
35 | #define RT286_VENDOR_ID 0x10ec0286 | ||
36 | |||
37 | struct rt286_priv { | ||
38 | struct regmap *regmap; | ||
39 | struct snd_soc_codec *codec; | ||
40 | struct rt286_platform_data pdata; | ||
41 | struct i2c_client *i2c; | ||
42 | struct snd_soc_jack *jack; | ||
43 | struct delayed_work jack_detect_work; | ||
44 | int sys_clk; | ||
45 | struct reg_default *index_cache; | ||
46 | }; | ||
47 | |||
48 | static struct reg_default rt286_index_def[] = { | ||
49 | { 0x01, 0xaaaa }, | ||
50 | { 0x02, 0x8aaa }, | ||
51 | { 0x03, 0x0002 }, | ||
52 | { 0x04, 0xaf01 }, | ||
53 | { 0x08, 0x000d }, | ||
54 | { 0x09, 0xd810 }, | ||
55 | { 0x0a, 0x0060 }, | ||
56 | { 0x0b, 0x0000 }, | ||
57 | { 0x0d, 0x2800 }, | ||
58 | { 0x0f, 0x0000 }, | ||
59 | { 0x19, 0x0a17 }, | ||
60 | { 0x20, 0x0020 }, | ||
61 | { 0x33, 0x0208 }, | ||
62 | { 0x49, 0x0004 }, | ||
63 | { 0x4f, 0x50e9 }, | ||
64 | { 0x50, 0x2c00 }, | ||
65 | { 0x63, 0x2902 }, | ||
66 | { 0x67, 0x1111 }, | ||
67 | { 0x68, 0x1016 }, | ||
68 | { 0x69, 0x273f }, | ||
69 | }; | ||
70 | #define INDEX_CACHE_SIZE ARRAY_SIZE(rt286_index_def) | ||
71 | |||
72 | static const struct reg_default rt286_reg[] = { | ||
73 | { 0x00170500, 0x00000400 }, | ||
74 | { 0x00220000, 0x00000031 }, | ||
75 | { 0x00239000, 0x0000007f }, | ||
76 | { 0x0023a000, 0x0000007f }, | ||
77 | { 0x00270500, 0x00000400 }, | ||
78 | { 0x00370500, 0x00000400 }, | ||
79 | { 0x00870500, 0x00000400 }, | ||
80 | { 0x00920000, 0x00000031 }, | ||
81 | { 0x00935000, 0x000000c3 }, | ||
82 | { 0x00936000, 0x000000c3 }, | ||
83 | { 0x00970500, 0x00000400 }, | ||
84 | { 0x00b37000, 0x00000097 }, | ||
85 | { 0x00b37200, 0x00000097 }, | ||
86 | { 0x00b37300, 0x00000097 }, | ||
87 | { 0x00c37000, 0x00000000 }, | ||
88 | { 0x00c37100, 0x00000080 }, | ||
89 | { 0x01270500, 0x00000400 }, | ||
90 | { 0x01370500, 0x00000400 }, | ||
91 | { 0x01371f00, 0x411111f0 }, | ||
92 | { 0x01439000, 0x00000080 }, | ||
93 | { 0x0143a000, 0x00000080 }, | ||
94 | { 0x01470700, 0x00000000 }, | ||
95 | { 0x01470500, 0x00000400 }, | ||
96 | { 0x01470c00, 0x00000000 }, | ||
97 | { 0x01470100, 0x00000000 }, | ||
98 | { 0x01837000, 0x00000000 }, | ||
99 | { 0x01870500, 0x00000400 }, | ||
100 | { 0x02050000, 0x00000000 }, | ||
101 | { 0x02139000, 0x00000080 }, | ||
102 | { 0x0213a000, 0x00000080 }, | ||
103 | { 0x02170100, 0x00000000 }, | ||
104 | { 0x02170500, 0x00000400 }, | ||
105 | { 0x02170700, 0x00000000 }, | ||
106 | { 0x02270100, 0x00000000 }, | ||
107 | { 0x02370100, 0x00000000 }, | ||
108 | { 0x02040000, 0x00004002 }, | ||
109 | { 0x01870700, 0x00000020 }, | ||
110 | { 0x00830000, 0x000000c3 }, | ||
111 | { 0x00930000, 0x000000c3 }, | ||
112 | { 0x01270700, 0x00000000 }, | ||
113 | }; | ||
114 | |||
115 | static bool rt286_volatile_register(struct device *dev, unsigned int reg) | ||
116 | { | ||
117 | switch (reg) { | ||
118 | case 0 ... 0xff: | ||
119 | case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): | ||
120 | case RT286_GET_HP_SENSE: | ||
121 | case RT286_GET_MIC1_SENSE: | ||
122 | case RT286_PROC_COEF: | ||
123 | return true; | ||
124 | default: | ||
125 | return false; | ||
126 | } | ||
127 | |||
128 | |||
129 | } | ||
130 | |||
131 | static bool rt286_readable_register(struct device *dev, unsigned int reg) | ||
132 | { | ||
133 | switch (reg) { | ||
134 | case 0 ... 0xff: | ||
135 | case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): | ||
136 | case RT286_GET_HP_SENSE: | ||
137 | case RT286_GET_MIC1_SENSE: | ||
138 | case RT286_SET_AUDIO_POWER: | ||
139 | case RT286_SET_HPO_POWER: | ||
140 | case RT286_SET_SPK_POWER: | ||
141 | case RT286_SET_DMIC1_POWER: | ||
142 | case RT286_SPK_MUX: | ||
143 | case RT286_HPO_MUX: | ||
144 | case RT286_ADC0_MUX: | ||
145 | case RT286_ADC1_MUX: | ||
146 | case RT286_SET_MIC1: | ||
147 | case RT286_SET_PIN_HPO: | ||
148 | case RT286_SET_PIN_SPK: | ||
149 | case RT286_SET_PIN_DMIC1: | ||
150 | case RT286_SPK_EAPD: | ||
151 | case RT286_SET_AMP_GAIN_HPO: | ||
152 | case RT286_SET_DMIC2_DEFAULT: | ||
153 | case RT286_DACL_GAIN: | ||
154 | case RT286_DACR_GAIN: | ||
155 | case RT286_ADCL_GAIN: | ||
156 | case RT286_ADCR_GAIN: | ||
157 | case RT286_MIC_GAIN: | ||
158 | case RT286_SPOL_GAIN: | ||
159 | case RT286_SPOR_GAIN: | ||
160 | case RT286_HPOL_GAIN: | ||
161 | case RT286_HPOR_GAIN: | ||
162 | case RT286_F_DAC_SWITCH: | ||
163 | case RT286_F_RECMIX_SWITCH: | ||
164 | case RT286_REC_MIC_SWITCH: | ||
165 | case RT286_REC_I2S_SWITCH: | ||
166 | case RT286_REC_LINE_SWITCH: | ||
167 | case RT286_REC_BEEP_SWITCH: | ||
168 | case RT286_DAC_FORMAT: | ||
169 | case RT286_ADC_FORMAT: | ||
170 | case RT286_COEF_INDEX: | ||
171 | case RT286_PROC_COEF: | ||
172 | case RT286_SET_AMP_GAIN_ADC_IN1: | ||
173 | case RT286_SET_AMP_GAIN_ADC_IN2: | ||
174 | case RT286_SET_POWER(RT286_DAC_OUT1): | ||
175 | case RT286_SET_POWER(RT286_DAC_OUT2): | ||
176 | case RT286_SET_POWER(RT286_ADC_IN1): | ||
177 | case RT286_SET_POWER(RT286_ADC_IN2): | ||
178 | case RT286_SET_POWER(RT286_DMIC2): | ||
179 | case RT286_SET_POWER(RT286_MIC1): | ||
180 | return true; | ||
181 | default: | ||
182 | return false; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | ||
187 | { | ||
188 | struct i2c_client *client = context; | ||
189 | struct rt286_priv *rt286 = i2c_get_clientdata(client); | ||
190 | u8 data[4]; | ||
191 | int ret, i; | ||
192 | |||
193 | /*handle index registers*/ | ||
194 | if (reg <= 0xff) { | ||
195 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | ||
196 | reg = RT286_PROC_COEF; | ||
197 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | ||
198 | if (reg == rt286->index_cache[i].reg) { | ||
199 | rt286->index_cache[i].def = value; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | } | ||
204 | } | ||
205 | |||
206 | data[0] = (reg >> 24) & 0xff; | ||
207 | data[1] = (reg >> 16) & 0xff; | ||
208 | /* | ||
209 | * 4 bit VID: reg should be 0 | ||
210 | * 12 bit VID: value should be 0 | ||
211 | * So we use an OR operator to handle it rather than use if condition. | ||
212 | */ | ||
213 | data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); | ||
214 | data[3] = value & 0xff; | ||
215 | |||
216 | ret = i2c_master_send(client, data, 4); | ||
217 | |||
218 | if (ret == 4) | ||
219 | return 0; | ||
220 | else | ||
221 | pr_err("ret=%d\n", ret); | ||
222 | if (ret < 0) | ||
223 | return ret; | ||
224 | else | ||
225 | return -EIO; | ||
226 | } | ||
227 | |||
228 | static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) | ||
229 | { | ||
230 | struct i2c_client *client = context; | ||
231 | struct i2c_msg xfer[2]; | ||
232 | int ret; | ||
233 | __be32 be_reg; | ||
234 | unsigned int index, vid, buf = 0x0; | ||
235 | |||
236 | /*handle index registers*/ | ||
237 | if (reg <= 0xff) { | ||
238 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | ||
239 | reg = RT286_PROC_COEF; | ||
240 | } | ||
241 | |||
242 | reg = reg | 0x80000; | ||
243 | vid = (reg >> 8) & 0xfff; | ||
244 | |||
245 | if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { | ||
246 | index = (reg >> 8) & 0xf; | ||
247 | reg = (reg & ~0xf0f) | index; | ||
248 | } | ||
249 | be_reg = cpu_to_be32(reg); | ||
250 | |||
251 | /* Write register */ | ||
252 | xfer[0].addr = client->addr; | ||
253 | xfer[0].flags = 0; | ||
254 | xfer[0].len = 4; | ||
255 | xfer[0].buf = (u8 *)&be_reg; | ||
256 | |||
257 | /* Read data */ | ||
258 | xfer[1].addr = client->addr; | ||
259 | xfer[1].flags = I2C_M_RD; | ||
260 | xfer[1].len = 4; | ||
261 | xfer[1].buf = (u8 *)&buf; | ||
262 | |||
263 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | else if (ret != 2) | ||
267 | return -EIO; | ||
268 | |||
269 | *value = be32_to_cpu(buf); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static void rt286_index_sync(struct snd_soc_codec *codec) | ||
275 | { | ||
276 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
277 | int i; | ||
278 | |||
279 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | ||
280 | snd_soc_write(codec, rt286->index_cache[i].reg, | ||
281 | rt286->index_cache[i].def); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static int rt286_support_power_controls[] = { | ||
286 | RT286_DAC_OUT1, | ||
287 | RT286_DAC_OUT2, | ||
288 | RT286_ADC_IN1, | ||
289 | RT286_ADC_IN2, | ||
290 | RT286_MIC1, | ||
291 | RT286_DMIC1, | ||
292 | RT286_DMIC2, | ||
293 | RT286_SPK_OUT, | ||
294 | RT286_HP_OUT, | ||
295 | }; | ||
296 | #define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls) | ||
297 | |||
298 | static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic) | ||
299 | { | ||
300 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
301 | unsigned int val, buf; | ||
302 | int i; | ||
303 | |||
304 | *hp = false; | ||
305 | *mic = false; | ||
306 | |||
307 | if (rt286->pdata.cbj_en) { | ||
308 | buf = snd_soc_read(codec, RT286_GET_HP_SENSE); | ||
309 | *hp = buf & 0x80000000; | ||
310 | if (*hp) { | ||
311 | /* power on HV,VERF */ | ||
312 | snd_soc_update_bits(codec, | ||
313 | RT286_POWER_CTRL1, 0x1001, 0x0); | ||
314 | /* power LDO1 */ | ||
315 | snd_soc_update_bits(codec, | ||
316 | RT286_POWER_CTRL2, 0x4, 0x4); | ||
317 | snd_soc_write(codec, RT286_SET_MIC1, 0x24); | ||
318 | val = snd_soc_read(codec, RT286_CBJ_CTRL2); | ||
319 | |||
320 | msleep(200); | ||
321 | i = 40; | ||
322 | while (((val & 0x0800) == 0) && (i > 0)) { | ||
323 | val = snd_soc_read(codec, | ||
324 | RT286_CBJ_CTRL2); | ||
325 | i--; | ||
326 | msleep(20); | ||
327 | } | ||
328 | |||
329 | if (0x0400 == (val & 0x0700)) { | ||
330 | *mic = false; | ||
331 | |||
332 | snd_soc_write(codec, | ||
333 | RT286_SET_MIC1, 0x20); | ||
334 | /* power off HV,VERF */ | ||
335 | snd_soc_update_bits(codec, | ||
336 | RT286_POWER_CTRL1, 0x1001, 0x1001); | ||
337 | snd_soc_update_bits(codec, | ||
338 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | ||
339 | snd_soc_update_bits(codec, | ||
340 | RT286_CBJ_CTRL1, 0x0030, 0x0000); | ||
341 | snd_soc_update_bits(codec, | ||
342 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | ||
343 | } else if ((0x0200 == (val & 0x0700)) || | ||
344 | (0x0100 == (val & 0x0700))) { | ||
345 | *mic = true; | ||
346 | snd_soc_update_bits(codec, | ||
347 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | ||
348 | snd_soc_update_bits(codec, | ||
349 | RT286_CBJ_CTRL1, 0x0030, 0x0020); | ||
350 | snd_soc_update_bits(codec, | ||
351 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | ||
352 | } else { | ||
353 | *mic = false; | ||
354 | } | ||
355 | |||
356 | snd_soc_update_bits(codec, | ||
357 | RT286_MISC_CTRL1, | ||
358 | 0x0060, 0x0000); | ||
359 | } else { | ||
360 | snd_soc_update_bits(codec, | ||
361 | RT286_MISC_CTRL1, | ||
362 | 0x0060, 0x0020); | ||
363 | snd_soc_update_bits(codec, | ||
364 | RT286_A_BIAS_CTRL3, | ||
365 | 0xc000, 0x8000); | ||
366 | snd_soc_update_bits(codec, | ||
367 | RT286_CBJ_CTRL1, | ||
368 | 0x0030, 0x0020); | ||
369 | snd_soc_update_bits(codec, | ||
370 | RT286_A_BIAS_CTRL2, | ||
371 | 0xc000, 0x8000); | ||
372 | |||
373 | *mic = false; | ||
374 | } | ||
375 | } else { | ||
376 | buf = snd_soc_read(codec, RT286_GET_HP_SENSE); | ||
377 | *hp = buf & 0x80000000; | ||
378 | buf = snd_soc_read(codec, RT286_GET_MIC1_SENSE); | ||
379 | *mic = buf & 0x80000000; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static void rt286_jack_detect_work(struct work_struct *work) | ||
386 | { | ||
387 | struct rt286_priv *rt286 = | ||
388 | container_of(work, struct rt286_priv, jack_detect_work.work); | ||
389 | int status = 0; | ||
390 | bool hp = false; | ||
391 | bool mic = false; | ||
392 | |||
393 | rt286_jack_detect(rt286->codec, &hp, &mic); | ||
394 | |||
395 | if (hp == true) | ||
396 | status |= SND_JACK_HEADPHONE; | ||
397 | |||
398 | if (mic == true) | ||
399 | status |= SND_JACK_MICROPHONE; | ||
400 | |||
401 | snd_soc_jack_report(rt286->jack, status, | ||
402 | SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); | ||
403 | } | ||
404 | |||
405 | int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | ||
406 | { | ||
407 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
408 | |||
409 | rt286->jack = jack; | ||
410 | |||
411 | /* Send an initial empty report */ | ||
412 | snd_soc_jack_report(rt286->jack, 0, | ||
413 | SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | EXPORT_SYMBOL_GPL(rt286_mic_detect); | ||
418 | |||
419 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); | ||
420 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); | ||
421 | |||
422 | static const struct snd_kcontrol_new rt286_snd_controls[] = { | ||
423 | SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN, | ||
424 | RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv), | ||
425 | SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN, | ||
426 | RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), | ||
427 | SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN, | ||
428 | 0, 0x3, 0, mic_vol_tlv), | ||
429 | SOC_DOUBLE_R("Speaker Playback Switch", RT286_SPOL_GAIN, | ||
430 | RT286_SPOR_GAIN, RT286_MUTE_SFT, 1, 1), | ||
431 | }; | ||
432 | |||
433 | /* Digital Mixer */ | ||
434 | static const struct snd_kcontrol_new rt286_front_mix[] = { | ||
435 | SOC_DAPM_SINGLE("DAC Switch", RT286_F_DAC_SWITCH, | ||
436 | RT286_MUTE_SFT, 1, 1), | ||
437 | SOC_DAPM_SINGLE("RECMIX Switch", RT286_F_RECMIX_SWITCH, | ||
438 | RT286_MUTE_SFT, 1, 1), | ||
439 | }; | ||
440 | |||
441 | /* Analog Input Mixer */ | ||
442 | static const struct snd_kcontrol_new rt286_rec_mix[] = { | ||
443 | SOC_DAPM_SINGLE("Mic1 Switch", RT286_REC_MIC_SWITCH, | ||
444 | RT286_MUTE_SFT, 1, 1), | ||
445 | SOC_DAPM_SINGLE("I2S Switch", RT286_REC_I2S_SWITCH, | ||
446 | RT286_MUTE_SFT, 1, 1), | ||
447 | SOC_DAPM_SINGLE("Line1 Switch", RT286_REC_LINE_SWITCH, | ||
448 | RT286_MUTE_SFT, 1, 1), | ||
449 | SOC_DAPM_SINGLE("Beep Switch", RT286_REC_BEEP_SWITCH, | ||
450 | RT286_MUTE_SFT, 1, 1), | ||
451 | }; | ||
452 | |||
453 | static const struct snd_kcontrol_new spo_enable_control = | ||
454 | SOC_DAPM_SINGLE("Switch", RT286_SET_PIN_SPK, | ||
455 | RT286_SET_PIN_SFT, 1, 0); | ||
456 | |||
457 | static const struct snd_kcontrol_new hpol_enable_control = | ||
458 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOL_GAIN, | ||
459 | RT286_MUTE_SFT, 1, 1); | ||
460 | |||
461 | static const struct snd_kcontrol_new hpor_enable_control = | ||
462 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOR_GAIN, | ||
463 | RT286_MUTE_SFT, 1, 1); | ||
464 | |||
465 | /* ADC0 source */ | ||
466 | static const char * const rt286_adc_src[] = { | ||
467 | "Mic", "RECMIX", "Dmic" | ||
468 | }; | ||
469 | |||
470 | static const int rt286_adc_values[] = { | ||
471 | 0, 4, 5, | ||
472 | }; | ||
473 | |||
474 | static SOC_VALUE_ENUM_SINGLE_DECL( | ||
475 | rt286_adc0_enum, RT286_ADC0_MUX, RT286_ADC_SEL_SFT, | ||
476 | RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values); | ||
477 | |||
478 | static const struct snd_kcontrol_new rt286_adc0_mux = | ||
479 | SOC_DAPM_ENUM("ADC 0 source", rt286_adc0_enum); | ||
480 | |||
481 | static SOC_VALUE_ENUM_SINGLE_DECL( | ||
482 | rt286_adc1_enum, RT286_ADC1_MUX, RT286_ADC_SEL_SFT, | ||
483 | RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values); | ||
484 | |||
485 | static const struct snd_kcontrol_new rt286_adc1_mux = | ||
486 | SOC_DAPM_ENUM("ADC 1 source", rt286_adc1_enum); | ||
487 | |||
488 | static const char * const rt286_dac_src[] = { | ||
489 | "Front", "Surround" | ||
490 | }; | ||
491 | /* HP-OUT source */ | ||
492 | static SOC_ENUM_SINGLE_DECL(rt286_hpo_enum, RT286_HPO_MUX, | ||
493 | 0, rt286_dac_src); | ||
494 | |||
495 | static const struct snd_kcontrol_new rt286_hpo_mux = | ||
496 | SOC_DAPM_ENUM("HPO source", rt286_hpo_enum); | ||
497 | |||
498 | /* SPK-OUT source */ | ||
499 | static SOC_ENUM_SINGLE_DECL(rt286_spo_enum, RT286_SPK_MUX, | ||
500 | 0, rt286_dac_src); | ||
501 | |||
502 | static const struct snd_kcontrol_new rt286_spo_mux = | ||
503 | SOC_DAPM_ENUM("SPO source", rt286_spo_enum); | ||
504 | |||
505 | static int rt286_spk_event(struct snd_soc_dapm_widget *w, | ||
506 | struct snd_kcontrol *kcontrol, int event) | ||
507 | { | ||
508 | struct snd_soc_codec *codec = w->codec; | ||
509 | |||
510 | switch (event) { | ||
511 | case SND_SOC_DAPM_POST_PMU: | ||
512 | snd_soc_write(codec, | ||
513 | RT286_SPK_EAPD, RT286_SET_EAPD_HIGH); | ||
514 | break; | ||
515 | case SND_SOC_DAPM_PRE_PMD: | ||
516 | snd_soc_write(codec, | ||
517 | RT286_SPK_EAPD, RT286_SET_EAPD_LOW); | ||
518 | break; | ||
519 | |||
520 | default: | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w, | ||
528 | struct snd_kcontrol *kcontrol, int event) | ||
529 | { | ||
530 | struct snd_soc_codec *codec = w->codec; | ||
531 | |||
532 | switch (event) { | ||
533 | case SND_SOC_DAPM_POST_PMU: | ||
534 | snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0x20); | ||
535 | break; | ||
536 | case SND_SOC_DAPM_PRE_PMD: | ||
537 | snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0); | ||
538 | break; | ||
539 | default: | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static int rt286_adc_event(struct snd_soc_dapm_widget *w, | ||
547 | struct snd_kcontrol *kcontrol, int event) | ||
548 | { | ||
549 | struct snd_soc_codec *codec = w->codec; | ||
550 | unsigned int nid; | ||
551 | |||
552 | nid = (w->reg >> 20) & 0xff; | ||
553 | |||
554 | switch (event) { | ||
555 | case SND_SOC_DAPM_POST_PMU: | ||
556 | snd_soc_update_bits(codec, | ||
557 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), | ||
558 | 0x7080, 0x7000); | ||
559 | break; | ||
560 | case SND_SOC_DAPM_PRE_PMD: | ||
561 | snd_soc_update_bits(codec, | ||
562 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), | ||
563 | 0x7080, 0x7080); | ||
564 | break; | ||
565 | default: | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { | ||
573 | /* Input Lines */ | ||
574 | SND_SOC_DAPM_INPUT("DMIC1 Pin"), | ||
575 | SND_SOC_DAPM_INPUT("DMIC2 Pin"), | ||
576 | SND_SOC_DAPM_INPUT("MIC1"), | ||
577 | SND_SOC_DAPM_INPUT("LINE1"), | ||
578 | SND_SOC_DAPM_INPUT("Beep"), | ||
579 | |||
580 | /* DMIC */ | ||
581 | SND_SOC_DAPM_PGA_E("DMIC1", RT286_SET_POWER(RT286_DMIC1), 0, 1, | ||
582 | NULL, 0, rt286_set_dmic1_event, | ||
583 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
584 | SND_SOC_DAPM_PGA("DMIC2", RT286_SET_POWER(RT286_DMIC2), 0, 1, | ||
585 | NULL, 0), | ||
586 | SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM, | ||
587 | 0, 0, NULL, 0), | ||
588 | |||
589 | /* REC Mixer */ | ||
590 | SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0, | ||
591 | rt286_rec_mix, ARRAY_SIZE(rt286_rec_mix)), | ||
592 | |||
593 | /* ADCs */ | ||
594 | SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0), | ||
595 | SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), | ||
596 | |||
597 | /* ADC Mux */ | ||
598 | SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1, | ||
599 | &rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | | ||
600 | SND_SOC_DAPM_POST_PMU), | ||
601 | SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1, | ||
602 | &rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | | ||
603 | SND_SOC_DAPM_POST_PMU), | ||
604 | |||
605 | /* Audio Interface */ | ||
606 | SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
607 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
608 | SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
609 | SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
610 | |||
611 | /* Output Side */ | ||
612 | /* DACs */ | ||
613 | SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0), | ||
614 | SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0), | ||
615 | |||
616 | /* Output Mux */ | ||
617 | SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt286_spo_mux), | ||
618 | SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt286_hpo_mux), | ||
619 | |||
620 | SND_SOC_DAPM_SUPPLY("HP Power", RT286_SET_PIN_HPO, | ||
621 | RT286_SET_PIN_SFT, 0, NULL, 0), | ||
622 | |||
623 | /* Output Mixer */ | ||
624 | SND_SOC_DAPM_MIXER("Front", RT286_SET_POWER(RT286_DAC_OUT1), 0, 1, | ||
625 | rt286_front_mix, ARRAY_SIZE(rt286_front_mix)), | ||
626 | SND_SOC_DAPM_PGA("Surround", RT286_SET_POWER(RT286_DAC_OUT2), 0, 1, | ||
627 | NULL, 0), | ||
628 | |||
629 | /* Output Pga */ | ||
630 | SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0, | ||
631 | &spo_enable_control, rt286_spk_event, | ||
632 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
633 | SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0, | ||
634 | &hpol_enable_control), | ||
635 | SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0, | ||
636 | &hpor_enable_control), | ||
637 | |||
638 | /* Output Lines */ | ||
639 | SND_SOC_DAPM_OUTPUT("SPOL"), | ||
640 | SND_SOC_DAPM_OUTPUT("SPOR"), | ||
641 | SND_SOC_DAPM_OUTPUT("HPO Pin"), | ||
642 | SND_SOC_DAPM_OUTPUT("SPDIF"), | ||
643 | }; | ||
644 | |||
645 | static const struct snd_soc_dapm_route rt286_dapm_routes[] = { | ||
646 | {"DMIC1", NULL, "DMIC1 Pin"}, | ||
647 | {"DMIC2", NULL, "DMIC2 Pin"}, | ||
648 | {"DMIC1", NULL, "DMIC Receiver"}, | ||
649 | {"DMIC2", NULL, "DMIC Receiver"}, | ||
650 | |||
651 | {"RECMIX", "Beep Switch", "Beep"}, | ||
652 | {"RECMIX", "Line1 Switch", "LINE1"}, | ||
653 | {"RECMIX", "Mic1 Switch", "MIC1"}, | ||
654 | |||
655 | {"ADC 0 Mux", "Dmic", "DMIC1"}, | ||
656 | {"ADC 0 Mux", "RECMIX", "RECMIX"}, | ||
657 | {"ADC 0 Mux", "Mic", "MIC1"}, | ||
658 | {"ADC 1 Mux", "Dmic", "DMIC2"}, | ||
659 | {"ADC 1 Mux", "RECMIX", "RECMIX"}, | ||
660 | {"ADC 1 Mux", "Mic", "MIC1"}, | ||
661 | |||
662 | {"ADC 0", NULL, "ADC 0 Mux"}, | ||
663 | {"ADC 1", NULL, "ADC 1 Mux"}, | ||
664 | |||
665 | {"AIF1TX", NULL, "ADC 0"}, | ||
666 | {"AIF2TX", NULL, "ADC 1"}, | ||
667 | |||
668 | {"DAC 0", NULL, "AIF1RX"}, | ||
669 | {"DAC 1", NULL, "AIF2RX"}, | ||
670 | |||
671 | {"Front", "DAC Switch", "DAC 0"}, | ||
672 | {"Front", "RECMIX Switch", "RECMIX"}, | ||
673 | |||
674 | {"Surround", NULL, "DAC 1"}, | ||
675 | |||
676 | {"SPK Mux", "Front", "Front"}, | ||
677 | {"SPK Mux", "Surround", "Surround"}, | ||
678 | |||
679 | {"HPO Mux", "Front", "Front"}, | ||
680 | {"HPO Mux", "Surround", "Surround"}, | ||
681 | |||
682 | {"SPO", "Switch", "SPK Mux"}, | ||
683 | {"HPO L", "Switch", "HPO Mux"}, | ||
684 | {"HPO R", "Switch", "HPO Mux"}, | ||
685 | {"HPO L", NULL, "HP Power"}, | ||
686 | {"HPO R", NULL, "HP Power"}, | ||
687 | |||
688 | {"SPOL", NULL, "SPO"}, | ||
689 | {"SPOR", NULL, "SPO"}, | ||
690 | {"HPO Pin", NULL, "HPO L"}, | ||
691 | {"HPO Pin", NULL, "HPO R"}, | ||
692 | }; | ||
693 | |||
694 | static int rt286_hw_params(struct snd_pcm_substream *substream, | ||
695 | struct snd_pcm_hw_params *params, | ||
696 | struct snd_soc_dai *dai) | ||
697 | { | ||
698 | struct snd_soc_codec *codec = dai->codec; | ||
699 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
700 | unsigned int val = 0; | ||
701 | int d_len_code; | ||
702 | |||
703 | switch (params_rate(params)) { | ||
704 | /* bit 14 0:48K 1:44.1K */ | ||
705 | case 44100: | ||
706 | val |= 0x4000; | ||
707 | break; | ||
708 | case 48000: | ||
709 | break; | ||
710 | default: | ||
711 | dev_err(codec->dev, "Unsupported sample rate %d\n", | ||
712 | params_rate(params)); | ||
713 | return -EINVAL; | ||
714 | } | ||
715 | switch (rt286->sys_clk) { | ||
716 | case 12288000: | ||
717 | case 24576000: | ||
718 | if (params_rate(params) != 48000) { | ||
719 | dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", | ||
720 | params_rate(params), rt286->sys_clk); | ||
721 | return -EINVAL; | ||
722 | } | ||
723 | break; | ||
724 | case 11289600: | ||
725 | case 22579200: | ||
726 | if (params_rate(params) != 44100) { | ||
727 | dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", | ||
728 | params_rate(params), rt286->sys_clk); | ||
729 | return -EINVAL; | ||
730 | } | ||
731 | break; | ||
732 | } | ||
733 | |||
734 | if (params_channels(params) <= 16) { | ||
735 | /* bit 3:0 Number of Channel */ | ||
736 | val |= (params_channels(params) - 1); | ||
737 | } else { | ||
738 | dev_err(codec->dev, "Unsupported channels %d\n", | ||
739 | params_channels(params)); | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | |||
743 | d_len_code = 0; | ||
744 | switch (params_width(params)) { | ||
745 | /* bit 6:4 Bits per Sample */ | ||
746 | case 16: | ||
747 | d_len_code = 0; | ||
748 | val |= (0x1 << 4); | ||
749 | break; | ||
750 | case 32: | ||
751 | d_len_code = 2; | ||
752 | val |= (0x4 << 4); | ||
753 | break; | ||
754 | case 20: | ||
755 | d_len_code = 1; | ||
756 | val |= (0x2 << 4); | ||
757 | break; | ||
758 | case 24: | ||
759 | d_len_code = 2; | ||
760 | val |= (0x3 << 4); | ||
761 | break; | ||
762 | case 8: | ||
763 | d_len_code = 3; | ||
764 | break; | ||
765 | default: | ||
766 | return -EINVAL; | ||
767 | } | ||
768 | |||
769 | snd_soc_update_bits(codec, | ||
770 | RT286_I2S_CTRL1, 0x0018, d_len_code << 3); | ||
771 | dev_dbg(codec->dev, "format val = 0x%x\n", val); | ||
772 | |||
773 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
774 | snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val); | ||
775 | else | ||
776 | snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val); | ||
777 | |||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
782 | { | ||
783 | struct snd_soc_codec *codec = dai->codec; | ||
784 | |||
785 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
786 | case SND_SOC_DAIFMT_CBM_CFM: | ||
787 | snd_soc_update_bits(codec, | ||
788 | RT286_I2S_CTRL1, 0x800, 0x800); | ||
789 | break; | ||
790 | case SND_SOC_DAIFMT_CBS_CFS: | ||
791 | snd_soc_update_bits(codec, | ||
792 | RT286_I2S_CTRL1, 0x800, 0x0); | ||
793 | break; | ||
794 | default: | ||
795 | return -EINVAL; | ||
796 | } | ||
797 | |||
798 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
799 | case SND_SOC_DAIFMT_I2S: | ||
800 | snd_soc_update_bits(codec, | ||
801 | RT286_I2S_CTRL1, 0x300, 0x0); | ||
802 | break; | ||
803 | case SND_SOC_DAIFMT_LEFT_J: | ||
804 | snd_soc_update_bits(codec, | ||
805 | RT286_I2S_CTRL1, 0x300, 0x1 << 8); | ||
806 | break; | ||
807 | case SND_SOC_DAIFMT_DSP_A: | ||
808 | snd_soc_update_bits(codec, | ||
809 | RT286_I2S_CTRL1, 0x300, 0x2 << 8); | ||
810 | break; | ||
811 | case SND_SOC_DAIFMT_DSP_B: | ||
812 | snd_soc_update_bits(codec, | ||
813 | RT286_I2S_CTRL1, 0x300, 0x3 << 8); | ||
814 | break; | ||
815 | default: | ||
816 | return -EINVAL; | ||
817 | } | ||
818 | /* bit 15 Stream Type 0:PCM 1:Non-PCM */ | ||
819 | snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x8000, 0); | ||
820 | snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x8000, 0); | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | static int rt286_set_dai_sysclk(struct snd_soc_dai *dai, | ||
826 | int clk_id, unsigned int freq, int dir) | ||
827 | { | ||
828 | struct snd_soc_codec *codec = dai->codec; | ||
829 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
830 | |||
831 | dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq); | ||
832 | |||
833 | if (RT286_SCLK_S_MCLK == clk_id) { | ||
834 | snd_soc_update_bits(codec, | ||
835 | RT286_I2S_CTRL2, 0x0100, 0x0); | ||
836 | snd_soc_update_bits(codec, | ||
837 | RT286_PLL_CTRL1, 0x20, 0x20); | ||
838 | } else { | ||
839 | snd_soc_update_bits(codec, | ||
840 | RT286_I2S_CTRL2, 0x0100, 0x0100); | ||
841 | snd_soc_update_bits(codec, | ||
842 | RT286_PLL_CTRL, 0x4, 0x4); | ||
843 | snd_soc_update_bits(codec, | ||
844 | RT286_PLL_CTRL1, 0x20, 0x0); | ||
845 | } | ||
846 | |||
847 | switch (freq) { | ||
848 | case 19200000: | ||
849 | if (RT286_SCLK_S_MCLK == clk_id) { | ||
850 | dev_err(codec->dev, "Should not use MCLK\n"); | ||
851 | return -EINVAL; | ||
852 | } | ||
853 | snd_soc_update_bits(codec, | ||
854 | RT286_I2S_CTRL2, 0x40, 0x40); | ||
855 | break; | ||
856 | case 24000000: | ||
857 | if (RT286_SCLK_S_MCLK == clk_id) { | ||
858 | dev_err(codec->dev, "Should not use MCLK\n"); | ||
859 | return -EINVAL; | ||
860 | } | ||
861 | snd_soc_update_bits(codec, | ||
862 | RT286_I2S_CTRL2, 0x40, 0x0); | ||
863 | break; | ||
864 | case 12288000: | ||
865 | case 11289600: | ||
866 | snd_soc_update_bits(codec, | ||
867 | RT286_I2S_CTRL2, 0x8, 0x0); | ||
868 | snd_soc_update_bits(codec, | ||
869 | RT286_CLK_DIV, 0xfc1e, 0x0004); | ||
870 | break; | ||
871 | case 24576000: | ||
872 | case 22579200: | ||
873 | snd_soc_update_bits(codec, | ||
874 | RT286_I2S_CTRL2, 0x8, 0x8); | ||
875 | snd_soc_update_bits(codec, | ||
876 | RT286_CLK_DIV, 0xfc1e, 0x5406); | ||
877 | break; | ||
878 | default: | ||
879 | dev_err(codec->dev, "Unsupported system clock\n"); | ||
880 | return -EINVAL; | ||
881 | } | ||
882 | |||
883 | rt286->sys_clk = freq; | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | static int rt286_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) | ||
889 | { | ||
890 | struct snd_soc_codec *codec = dai->codec; | ||
891 | |||
892 | dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); | ||
893 | if (50 == ratio) | ||
894 | snd_soc_update_bits(codec, | ||
895 | RT286_I2S_CTRL1, 0x1000, 0x1000); | ||
896 | else | ||
897 | snd_soc_update_bits(codec, | ||
898 | RT286_I2S_CTRL1, 0x1000, 0x0); | ||
899 | |||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static int rt286_set_bias_level(struct snd_soc_codec *codec, | ||
905 | enum snd_soc_bias_level level) | ||
906 | { | ||
907 | switch (level) { | ||
908 | case SND_SOC_BIAS_PREPARE: | ||
909 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | ||
910 | snd_soc_write(codec, | ||
911 | RT286_SET_AUDIO_POWER, AC_PWRST_D0); | ||
912 | snd_soc_update_bits(codec, | ||
913 | RT286_DC_GAIN, 0x200, 0x200); | ||
914 | } | ||
915 | break; | ||
916 | |||
917 | case SND_SOC_BIAS_ON: | ||
918 | mdelay(10); | ||
919 | break; | ||
920 | |||
921 | case SND_SOC_BIAS_STANDBY: | ||
922 | snd_soc_write(codec, | ||
923 | RT286_SET_AUDIO_POWER, AC_PWRST_D3); | ||
924 | snd_soc_update_bits(codec, | ||
925 | RT286_DC_GAIN, 0x200, 0x0); | ||
926 | break; | ||
927 | |||
928 | default: | ||
929 | break; | ||
930 | } | ||
931 | codec->dapm.bias_level = level; | ||
932 | |||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static irqreturn_t rt286_irq(int irq, void *data) | ||
937 | { | ||
938 | struct rt286_priv *rt286 = data; | ||
939 | bool hp = false; | ||
940 | bool mic = false; | ||
941 | int status = 0; | ||
942 | |||
943 | rt286_jack_detect(rt286->codec, &hp, &mic); | ||
944 | |||
945 | /* Clear IRQ */ | ||
946 | snd_soc_update_bits(rt286->codec, | ||
947 | RT286_IRQ_CTRL, 0x1, 0x1); | ||
948 | |||
949 | if (hp == true) | ||
950 | status |= SND_JACK_HEADPHONE; | ||
951 | |||
952 | if (mic == true) | ||
953 | status |= SND_JACK_MICROPHONE; | ||
954 | |||
955 | snd_soc_jack_report(rt286->jack, status, | ||
956 | SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); | ||
957 | |||
958 | pm_wakeup_event(&rt286->i2c->dev, 300); | ||
959 | |||
960 | return IRQ_HANDLED; | ||
961 | } | ||
962 | |||
963 | static int rt286_probe(struct snd_soc_codec *codec) | ||
964 | { | ||
965 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
966 | |||
967 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | ||
968 | rt286->codec = codec; | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static int rt286_remove(struct snd_soc_codec *codec) | ||
974 | { | ||
975 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
976 | |||
977 | cancel_delayed_work_sync(&rt286->jack_detect_work); | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | #ifdef CONFIG_PM | ||
983 | static int rt286_suspend(struct snd_soc_codec *codec) | ||
984 | { | ||
985 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
986 | |||
987 | regcache_cache_only(rt286->regmap, true); | ||
988 | regcache_mark_dirty(rt286->regmap); | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int rt286_resume(struct snd_soc_codec *codec) | ||
994 | { | ||
995 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
996 | |||
997 | regcache_cache_only(rt286->regmap, false); | ||
998 | rt286_index_sync(codec); | ||
999 | regcache_sync(rt286->regmap); | ||
1000 | |||
1001 | return 0; | ||
1002 | } | ||
1003 | #else | ||
1004 | #define rt286_suspend NULL | ||
1005 | #define rt286_resume NULL | ||
1006 | #endif | ||
1007 | |||
1008 | #define RT286_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
1009 | #define RT286_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
1010 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) | ||
1011 | |||
1012 | static const struct snd_soc_dai_ops rt286_aif_dai_ops = { | ||
1013 | .hw_params = rt286_hw_params, | ||
1014 | .set_fmt = rt286_set_dai_fmt, | ||
1015 | .set_sysclk = rt286_set_dai_sysclk, | ||
1016 | .set_bclk_ratio = rt286_set_bclk_ratio, | ||
1017 | }; | ||
1018 | |||
1019 | static struct snd_soc_dai_driver rt286_dai[] = { | ||
1020 | { | ||
1021 | .name = "rt286-aif1", | ||
1022 | .id = RT286_AIF1, | ||
1023 | .playback = { | ||
1024 | .stream_name = "AIF1 Playback", | ||
1025 | .channels_min = 1, | ||
1026 | .channels_max = 2, | ||
1027 | .rates = RT286_STEREO_RATES, | ||
1028 | .formats = RT286_FORMATS, | ||
1029 | }, | ||
1030 | .capture = { | ||
1031 | .stream_name = "AIF1 Capture", | ||
1032 | .channels_min = 1, | ||
1033 | .channels_max = 2, | ||
1034 | .rates = RT286_STEREO_RATES, | ||
1035 | .formats = RT286_FORMATS, | ||
1036 | }, | ||
1037 | .ops = &rt286_aif_dai_ops, | ||
1038 | .symmetric_rates = 1, | ||
1039 | }, | ||
1040 | { | ||
1041 | .name = "rt286-aif2", | ||
1042 | .id = RT286_AIF2, | ||
1043 | .playback = { | ||
1044 | .stream_name = "AIF2 Playback", | ||
1045 | .channels_min = 1, | ||
1046 | .channels_max = 2, | ||
1047 | .rates = RT286_STEREO_RATES, | ||
1048 | .formats = RT286_FORMATS, | ||
1049 | }, | ||
1050 | .capture = { | ||
1051 | .stream_name = "AIF2 Capture", | ||
1052 | .channels_min = 1, | ||
1053 | .channels_max = 2, | ||
1054 | .rates = RT286_STEREO_RATES, | ||
1055 | .formats = RT286_FORMATS, | ||
1056 | }, | ||
1057 | .ops = &rt286_aif_dai_ops, | ||
1058 | .symmetric_rates = 1, | ||
1059 | }, | ||
1060 | |||
1061 | }; | ||
1062 | |||
1063 | static struct snd_soc_codec_driver soc_codec_dev_rt286 = { | ||
1064 | .probe = rt286_probe, | ||
1065 | .remove = rt286_remove, | ||
1066 | .suspend = rt286_suspend, | ||
1067 | .resume = rt286_resume, | ||
1068 | .set_bias_level = rt286_set_bias_level, | ||
1069 | .idle_bias_off = true, | ||
1070 | .controls = rt286_snd_controls, | ||
1071 | .num_controls = ARRAY_SIZE(rt286_snd_controls), | ||
1072 | .dapm_widgets = rt286_dapm_widgets, | ||
1073 | .num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets), | ||
1074 | .dapm_routes = rt286_dapm_routes, | ||
1075 | .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), | ||
1076 | }; | ||
1077 | |||
1078 | static const struct regmap_config rt286_regmap = { | ||
1079 | .reg_bits = 32, | ||
1080 | .val_bits = 32, | ||
1081 | .max_register = 0x02370100, | ||
1082 | .volatile_reg = rt286_volatile_register, | ||
1083 | .readable_reg = rt286_readable_register, | ||
1084 | .reg_write = rt286_hw_write, | ||
1085 | .reg_read = rt286_hw_read, | ||
1086 | .cache_type = REGCACHE_RBTREE, | ||
1087 | .reg_defaults = rt286_reg, | ||
1088 | .num_reg_defaults = ARRAY_SIZE(rt286_reg), | ||
1089 | }; | ||
1090 | |||
1091 | static const struct i2c_device_id rt286_i2c_id[] = { | ||
1092 | {"rt286", 0}, | ||
1093 | {} | ||
1094 | }; | ||
1095 | MODULE_DEVICE_TABLE(i2c, rt286_i2c_id); | ||
1096 | |||
1097 | static const struct acpi_device_id rt286_acpi_match[] = { | ||
1098 | { "INT343A", 0 }, | ||
1099 | {}, | ||
1100 | }; | ||
1101 | MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); | ||
1102 | |||
1103 | static int rt286_i2c_probe(struct i2c_client *i2c, | ||
1104 | const struct i2c_device_id *id) | ||
1105 | { | ||
1106 | struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev); | ||
1107 | struct rt286_priv *rt286; | ||
1108 | int i, ret; | ||
1109 | |||
1110 | rt286 = devm_kzalloc(&i2c->dev, sizeof(*rt286), | ||
1111 | GFP_KERNEL); | ||
1112 | if (NULL == rt286) | ||
1113 | return -ENOMEM; | ||
1114 | |||
1115 | rt286->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt286_regmap); | ||
1116 | if (IS_ERR(rt286->regmap)) { | ||
1117 | ret = PTR_ERR(rt286->regmap); | ||
1118 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
1119 | ret); | ||
1120 | return ret; | ||
1121 | } | ||
1122 | |||
1123 | regmap_read(rt286->regmap, | ||
1124 | RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); | ||
1125 | if (ret != RT286_VENDOR_ID) { | ||
1126 | dev_err(&i2c->dev, | ||
1127 | "Device with ID register %x is not rt286\n", ret); | ||
1128 | return -ENODEV; | ||
1129 | } | ||
1130 | |||
1131 | rt286->index_cache = rt286_index_def; | ||
1132 | rt286->i2c = i2c; | ||
1133 | i2c_set_clientdata(i2c, rt286); | ||
1134 | |||
1135 | if (pdata) | ||
1136 | rt286->pdata = *pdata; | ||
1137 | |||
1138 | regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); | ||
1139 | |||
1140 | for (i = 0; i < RT286_POWER_REG_LEN; i++) | ||
1141 | regmap_write(rt286->regmap, | ||
1142 | RT286_SET_POWER(rt286_support_power_controls[i]), | ||
1143 | AC_PWRST_D1); | ||
1144 | |||
1145 | if (!rt286->pdata.cbj_en) { | ||
1146 | regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); | ||
1147 | regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); | ||
1148 | regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); | ||
1149 | regmap_update_bits(rt286->regmap, | ||
1150 | RT286_CBJ_CTRL1, 0xf000, 0xb000); | ||
1151 | } else { | ||
1152 | regmap_update_bits(rt286->regmap, | ||
1153 | RT286_CBJ_CTRL1, 0xf000, 0x5000); | ||
1154 | } | ||
1155 | |||
1156 | mdelay(10); | ||
1157 | |||
1158 | if (!rt286->pdata.gpio2_en) | ||
1159 | regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0x4000); | ||
1160 | else | ||
1161 | regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0); | ||
1162 | |||
1163 | mdelay(10); | ||
1164 | |||
1165 | /*Power down LDO2*/ | ||
1166 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0); | ||
1167 | |||
1168 | /*Set depop parameter*/ | ||
1169 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); | ||
1170 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); | ||
1171 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); | ||
1172 | |||
1173 | if (rt286->i2c->irq) { | ||
1174 | regmap_update_bits(rt286->regmap, | ||
1175 | RT286_IRQ_CTRL, 0x2, 0x2); | ||
1176 | |||
1177 | INIT_DELAYED_WORK(&rt286->jack_detect_work, | ||
1178 | rt286_jack_detect_work); | ||
1179 | schedule_delayed_work(&rt286->jack_detect_work, | ||
1180 | msecs_to_jiffies(1250)); | ||
1181 | |||
1182 | ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, | ||
1183 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); | ||
1184 | if (ret != 0) { | ||
1185 | dev_err(&i2c->dev, | ||
1186 | "Failed to reguest IRQ: %d\n", ret); | ||
1187 | return ret; | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt286, | ||
1192 | rt286_dai, ARRAY_SIZE(rt286_dai)); | ||
1193 | |||
1194 | return ret; | ||
1195 | } | ||
1196 | |||
1197 | static int rt286_i2c_remove(struct i2c_client *i2c) | ||
1198 | { | ||
1199 | struct rt286_priv *rt286 = i2c_get_clientdata(i2c); | ||
1200 | |||
1201 | if (i2c->irq) | ||
1202 | free_irq(i2c->irq, rt286); | ||
1203 | snd_soc_unregister_codec(&i2c->dev); | ||
1204 | |||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | |||
1209 | static struct i2c_driver rt286_i2c_driver = { | ||
1210 | .driver = { | ||
1211 | .name = "rt286", | ||
1212 | .owner = THIS_MODULE, | ||
1213 | .acpi_match_table = ACPI_PTR(rt286_acpi_match), | ||
1214 | }, | ||
1215 | .probe = rt286_i2c_probe, | ||
1216 | .remove = rt286_i2c_remove, | ||
1217 | .id_table = rt286_i2c_id, | ||
1218 | }; | ||
1219 | |||
1220 | module_i2c_driver(rt286_i2c_driver); | ||
1221 | |||
1222 | MODULE_DESCRIPTION("ASoC RT286 driver"); | ||
1223 | MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); | ||
1224 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h new file mode 100644 index 000000000000..b539b7320a79 --- /dev/null +++ b/sound/soc/codecs/rt286.h | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * rt286.h -- RT286 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2011 Realtek Microelectronics | ||
5 | * Author: Johnny Hsu <johnnyhsu@realtek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __RT286_H__ | ||
13 | #define __RT286_H__ | ||
14 | |||
15 | #define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) | ||
16 | |||
17 | #define RT286_AUDIO_FUNCTION_GROUP 0x01 | ||
18 | #define RT286_DAC_OUT1 0x02 | ||
19 | #define RT286_DAC_OUT2 0x03 | ||
20 | #define RT286_ADC_IN1 0x09 | ||
21 | #define RT286_ADC_IN2 0x08 | ||
22 | #define RT286_MIXER_IN 0x0b | ||
23 | #define RT286_MIXER_OUT1 0x0c | ||
24 | #define RT286_MIXER_OUT2 0x0d | ||
25 | #define RT286_DMIC1 0x12 | ||
26 | #define RT286_DMIC2 0x13 | ||
27 | #define RT286_SPK_OUT 0x14 | ||
28 | #define RT286_MIC1 0x18 | ||
29 | #define RT286_LINE1 0x1a | ||
30 | #define RT286_BEEP 0x1d | ||
31 | #define RT286_SPDIF 0x1e | ||
32 | #define RT286_VENDOR_REGISTERS 0x20 | ||
33 | #define RT286_HP_OUT 0x21 | ||
34 | #define RT286_MIXER_IN1 0x22 | ||
35 | #define RT286_MIXER_IN2 0x23 | ||
36 | |||
37 | #define RT286_SET_PIN_SFT 6 | ||
38 | #define RT286_SET_PIN_ENABLE 0x40 | ||
39 | #define RT286_SET_PIN_DISABLE 0 | ||
40 | #define RT286_SET_EAPD_HIGH 0x2 | ||
41 | #define RT286_SET_EAPD_LOW 0 | ||
42 | |||
43 | #define RT286_MUTE_SFT 7 | ||
44 | |||
45 | /* Verb commands */ | ||
46 | #define RT286_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM) | ||
47 | #define RT286_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0) | ||
48 | #define RT286_SET_AUDIO_POWER RT286_SET_POWER(RT286_AUDIO_FUNCTION_GROUP) | ||
49 | #define RT286_SET_HPO_POWER RT286_SET_POWER(RT286_HP_OUT) | ||
50 | #define RT286_SET_SPK_POWER RT286_SET_POWER(RT286_SPK_OUT) | ||
51 | #define RT286_SET_DMIC1_POWER RT286_SET_POWER(RT286_DMIC1) | ||
52 | #define RT286_SPK_MUX\ | ||
53 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_SPK_OUT, 0) | ||
54 | #define RT286_HPO_MUX\ | ||
55 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_HP_OUT, 0) | ||
56 | #define RT286_ADC0_MUX\ | ||
57 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN1, 0) | ||
58 | #define RT286_ADC1_MUX\ | ||
59 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN2, 0) | ||
60 | #define RT286_SET_MIC1\ | ||
61 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_MIC1, 0) | ||
62 | #define RT286_SET_PIN_HPO\ | ||
63 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_HP_OUT, 0) | ||
64 | #define RT286_SET_PIN_SPK\ | ||
65 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_SPK_OUT, 0) | ||
66 | #define RT286_SET_PIN_DMIC1\ | ||
67 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_DMIC1, 0) | ||
68 | #define RT286_SPK_EAPD\ | ||
69 | VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT286_SPK_OUT, 0) | ||
70 | #define RT286_SET_AMP_GAIN_HPO\ | ||
71 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0) | ||
72 | #define RT286_SET_AMP_GAIN_ADC_IN1\ | ||
73 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0) | ||
74 | #define RT286_SET_AMP_GAIN_ADC_IN2\ | ||
75 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN2, 0) | ||
76 | #define RT286_GET_HP_SENSE\ | ||
77 | VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_HP_OUT, 0) | ||
78 | #define RT286_GET_MIC1_SENSE\ | ||
79 | VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_MIC1, 0) | ||
80 | #define RT286_SET_DMIC2_DEFAULT\ | ||
81 | VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT286_DMIC2, 0) | ||
82 | #define RT286_DACL_GAIN\ | ||
83 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0xa000) | ||
84 | #define RT286_DACR_GAIN\ | ||
85 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0x9000) | ||
86 | #define RT286_ADCL_GAIN\ | ||
87 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x6000) | ||
88 | #define RT286_ADCR_GAIN\ | ||
89 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x5000) | ||
90 | #define RT286_MIC_GAIN\ | ||
91 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIC1, 0x7000) | ||
92 | #define RT286_SPOL_GAIN\ | ||
93 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0xa000) | ||
94 | #define RT286_SPOR_GAIN\ | ||
95 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0x9000) | ||
96 | #define RT286_HPOL_GAIN\ | ||
97 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0xa000) | ||
98 | #define RT286_HPOR_GAIN\ | ||
99 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0x9000) | ||
100 | #define RT286_F_DAC_SWITCH\ | ||
101 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7000) | ||
102 | #define RT286_F_RECMIX_SWITCH\ | ||
103 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7100) | ||
104 | #define RT286_REC_MIC_SWITCH\ | ||
105 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7000) | ||
106 | #define RT286_REC_I2S_SWITCH\ | ||
107 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7100) | ||
108 | #define RT286_REC_LINE_SWITCH\ | ||
109 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7200) | ||
110 | #define RT286_REC_BEEP_SWITCH\ | ||
111 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7300) | ||
112 | #define RT286_DAC_FORMAT\ | ||
113 | VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_DAC_OUT1, 0) | ||
114 | #define RT286_ADC_FORMAT\ | ||
115 | VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_ADC_IN1, 0) | ||
116 | #define RT286_COEF_INDEX\ | ||
117 | VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0) | ||
118 | #define RT286_PROC_COEF\ | ||
119 | VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0) | ||
120 | |||
121 | /* Index registers */ | ||
122 | #define RT286_A_BIAS_CTRL1 0x01 | ||
123 | #define RT286_A_BIAS_CTRL2 0x02 | ||
124 | #define RT286_POWER_CTRL1 0x03 | ||
125 | #define RT286_A_BIAS_CTRL3 0x04 | ||
126 | #define RT286_POWER_CTRL2 0x08 | ||
127 | #define RT286_I2S_CTRL1 0x09 | ||
128 | #define RT286_I2S_CTRL2 0x0a | ||
129 | #define RT286_CLK_DIV 0x0b | ||
130 | #define RT286_DC_GAIN 0x0d | ||
131 | #define RT286_POWER_CTRL3 0x0f | ||
132 | #define RT286_MIC1_DET_CTRL 0x19 | ||
133 | #define RT286_MISC_CTRL1 0x20 | ||
134 | #define RT286_IRQ_CTRL 0x33 | ||
135 | #define RT286_PLL_CTRL1 0x49 | ||
136 | #define RT286_CBJ_CTRL1 0x4f | ||
137 | #define RT286_CBJ_CTRL2 0x50 | ||
138 | #define RT286_PLL_CTRL 0x63 | ||
139 | #define RT286_DEPOP_CTRL1 0x66 | ||
140 | #define RT286_DEPOP_CTRL2 0x67 | ||
141 | #define RT286_DEPOP_CTRL3 0x68 | ||
142 | #define RT286_DEPOP_CTRL4 0x69 | ||
143 | |||
144 | /* SPDIF (0x06) */ | ||
145 | #define RT286_SPDIF_SEL_SFT 0 | ||
146 | #define RT286_SPDIF_SEL_PCM0 0 | ||
147 | #define RT286_SPDIF_SEL_PCM1 1 | ||
148 | #define RT286_SPDIF_SEL_SPOUT 2 | ||
149 | #define RT286_SPDIF_SEL_PP 3 | ||
150 | |||
151 | /* RECMIX (0x0b) */ | ||
152 | #define RT286_M_REC_BEEP_SFT 0 | ||
153 | #define RT286_M_REC_LINE1_SFT 1 | ||
154 | #define RT286_M_REC_MIC1_SFT 2 | ||
155 | #define RT286_M_REC_I2S_SFT 3 | ||
156 | |||
157 | /* Front (0x0c) */ | ||
158 | #define RT286_M_FRONT_DAC_SFT 0 | ||
159 | #define RT286_M_FRONT_REC_SFT 1 | ||
160 | |||
161 | /* SPK-OUT (0x14) */ | ||
162 | #define RT286_M_SPK_MUX_SFT 14 | ||
163 | #define RT286_SPK_SEL_MASK 0x1 | ||
164 | #define RT286_SPK_SEL_SFT 0 | ||
165 | #define RT286_SPK_SEL_F 0 | ||
166 | #define RT286_SPK_SEL_S 1 | ||
167 | |||
168 | /* HP-OUT (0x21) */ | ||
169 | #define RT286_M_HP_MUX_SFT 14 | ||
170 | #define RT286_HP_SEL_MASK 0x1 | ||
171 | #define RT286_HP_SEL_SFT 0 | ||
172 | #define RT286_HP_SEL_F 0 | ||
173 | #define RT286_HP_SEL_S 1 | ||
174 | |||
175 | /* ADC (0x22) (0x23) */ | ||
176 | #define RT286_ADC_SEL_MASK 0x7 | ||
177 | #define RT286_ADC_SEL_SFT 0 | ||
178 | #define RT286_ADC_SEL_SURR 0 | ||
179 | #define RT286_ADC_SEL_FRONT 1 | ||
180 | #define RT286_ADC_SEL_DMIC 2 | ||
181 | #define RT286_ADC_SEL_BEEP 4 | ||
182 | #define RT286_ADC_SEL_LINE1 5 | ||
183 | #define RT286_ADC_SEL_I2S 6 | ||
184 | #define RT286_ADC_SEL_MIC1 7 | ||
185 | |||
186 | #define RT286_SCLK_S_MCLK 0 | ||
187 | #define RT286_SCLK_S_PLL 1 | ||
188 | |||
189 | enum { | ||
190 | RT286_AIF1, | ||
191 | RT286_AIF2, | ||
192 | RT286_AIFS, | ||
193 | }; | ||
194 | |||
195 | int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); | ||
196 | |||
197 | #endif /* __RT286_H__ */ | ||
198 | |||
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 3d39f0b5b4a8..8f4c73d17c87 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -1277,7 +1277,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | |||
1277 | return ret; | 1277 | return ret; |
1278 | } | 1278 | } |
1279 | 1279 | ||
1280 | ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | 1280 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), |
1281 | sgtl5000->supplies); | 1281 | sgtl5000->supplies); |
1282 | if (ret) | 1282 | if (ret) |
1283 | goto err_ldo_remove; | 1283 | goto err_ldo_remove; |
@@ -1285,13 +1285,16 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | |||
1285 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | 1285 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), |
1286 | sgtl5000->supplies); | 1286 | sgtl5000->supplies); |
1287 | if (ret) | 1287 | if (ret) |
1288 | goto err_ldo_remove; | 1288 | goto err_regulator_free; |
1289 | 1289 | ||
1290 | /* wait for all power rails bring up */ | 1290 | /* wait for all power rails bring up */ |
1291 | udelay(10); | 1291 | udelay(10); |
1292 | 1292 | ||
1293 | return 0; | 1293 | return 0; |
1294 | 1294 | ||
1295 | err_regulator_free: | ||
1296 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1297 | sgtl5000->supplies); | ||
1295 | err_ldo_remove: | 1298 | err_ldo_remove: |
1296 | if (!external_vddd) | 1299 | if (!external_vddd) |
1297 | ldo_regulator_remove(codec); | 1300 | ldo_regulator_remove(codec); |
@@ -1361,6 +1364,8 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1361 | err: | 1364 | err: |
1362 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | 1365 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), |
1363 | sgtl5000->supplies); | 1366 | sgtl5000->supplies); |
1367 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1368 | sgtl5000->supplies); | ||
1364 | ldo_regulator_remove(codec); | 1369 | ldo_regulator_remove(codec); |
1365 | 1370 | ||
1366 | return ret; | 1371 | return ret; |
@@ -1374,6 +1379,8 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) | |||
1374 | 1379 | ||
1375 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | 1380 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), |
1376 | sgtl5000->supplies); | 1381 | sgtl5000->supplies); |
1382 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1383 | sgtl5000->supplies); | ||
1377 | ldo_regulator_remove(codec); | 1384 | ldo_regulator_remove(codec); |
1378 | 1385 | ||
1379 | return 0; | 1386 | return 0; |
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c new file mode 100644 index 000000000000..246081aae8ca --- /dev/null +++ b/sound/soc/codecs/sigmadsp-i2c.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Load Analog Devices SigmaStudio firmware files | ||
3 | * | ||
4 | * Copyright 2009-2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/i2c.h> | ||
10 | #include <linux/export.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | #include "sigmadsp.h" | ||
14 | |||
15 | static int sigma_action_write_i2c(void *control_data, | ||
16 | const struct sigma_action *sa, size_t len) | ||
17 | { | ||
18 | return i2c_master_send(control_data, (const unsigned char *)&sa->addr, | ||
19 | len); | ||
20 | } | ||
21 | |||
22 | int process_sigma_firmware(struct i2c_client *client, const char *name) | ||
23 | { | ||
24 | struct sigma_firmware ssfw; | ||
25 | |||
26 | ssfw.control_data = client; | ||
27 | ssfw.write = sigma_action_write_i2c; | ||
28 | |||
29 | return _process_sigma_firmware(&client->dev, &ssfw, name); | ||
30 | } | ||
31 | EXPORT_SYMBOL(process_sigma_firmware); | ||
32 | |||
33 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
34 | MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); | ||
35 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c new file mode 100644 index 000000000000..f78ed8d2cfb2 --- /dev/null +++ b/sound/soc/codecs/sigmadsp-regmap.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Load Analog Devices SigmaStudio firmware files | ||
3 | * | ||
4 | * Copyright 2009-2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/regmap.h> | ||
10 | #include <linux/export.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | #include "sigmadsp.h" | ||
14 | |||
15 | static int sigma_action_write_regmap(void *control_data, | ||
16 | const struct sigma_action *sa, size_t len) | ||
17 | { | ||
18 | return regmap_raw_write(control_data, be16_to_cpu(sa->addr), | ||
19 | sa->payload, len - 2); | ||
20 | } | ||
21 | |||
22 | int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, | ||
23 | const char *name) | ||
24 | { | ||
25 | struct sigma_firmware ssfw; | ||
26 | |||
27 | ssfw.control_data = regmap; | ||
28 | ssfw.write = sigma_action_write_regmap; | ||
29 | |||
30 | return _process_sigma_firmware(dev, &ssfw, name); | ||
31 | } | ||
32 | EXPORT_SYMBOL(process_sigma_firmware_regmap); | ||
33 | |||
34 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
35 | MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); | ||
36 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 4068f2491232..f2de7e049bc6 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c | |||
@@ -34,23 +34,6 @@ enum { | |||
34 | SIGMA_ACTION_END, | 34 | SIGMA_ACTION_END, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct sigma_action { | ||
38 | u8 instr; | ||
39 | u8 len_hi; | ||
40 | __le16 len; | ||
41 | __be16 addr; | ||
42 | unsigned char payload[]; | ||
43 | } __packed; | ||
44 | |||
45 | struct sigma_firmware { | ||
46 | const struct firmware *fw; | ||
47 | size_t pos; | ||
48 | |||
49 | void *control_data; | ||
50 | int (*write)(void *control_data, const struct sigma_action *sa, | ||
51 | size_t len); | ||
52 | }; | ||
53 | |||
54 | static inline u32 sigma_action_len(struct sigma_action *sa) | 37 | static inline u32 sigma_action_len(struct sigma_action *sa) |
55 | { | 38 | { |
56 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); | 39 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); |
@@ -138,7 +121,7 @@ process_sigma_actions(struct sigma_firmware *ssfw) | |||
138 | return 0; | 121 | return 0; |
139 | } | 122 | } |
140 | 123 | ||
141 | static int _process_sigma_firmware(struct device *dev, | 124 | int _process_sigma_firmware(struct device *dev, |
142 | struct sigma_firmware *ssfw, const char *name) | 125 | struct sigma_firmware *ssfw, const char *name) |
143 | { | 126 | { |
144 | int ret; | 127 | int ret; |
@@ -197,50 +180,6 @@ static int _process_sigma_firmware(struct device *dev, | |||
197 | 180 | ||
198 | return ret; | 181 | return ret; |
199 | } | 182 | } |
200 | 183 | EXPORT_SYMBOL_GPL(_process_sigma_firmware); | |
201 | #if IS_ENABLED(CONFIG_I2C) | ||
202 | |||
203 | static int sigma_action_write_i2c(void *control_data, | ||
204 | const struct sigma_action *sa, size_t len) | ||
205 | { | ||
206 | return i2c_master_send(control_data, (const unsigned char *)&sa->addr, | ||
207 | len); | ||
208 | } | ||
209 | |||
210 | int process_sigma_firmware(struct i2c_client *client, const char *name) | ||
211 | { | ||
212 | struct sigma_firmware ssfw; | ||
213 | |||
214 | ssfw.control_data = client; | ||
215 | ssfw.write = sigma_action_write_i2c; | ||
216 | |||
217 | return _process_sigma_firmware(&client->dev, &ssfw, name); | ||
218 | } | ||
219 | EXPORT_SYMBOL(process_sigma_firmware); | ||
220 | |||
221 | #endif | ||
222 | |||
223 | #if IS_ENABLED(CONFIG_REGMAP) | ||
224 | |||
225 | static int sigma_action_write_regmap(void *control_data, | ||
226 | const struct sigma_action *sa, size_t len) | ||
227 | { | ||
228 | return regmap_raw_write(control_data, be16_to_cpu(sa->addr), | ||
229 | sa->payload, len - 2); | ||
230 | } | ||
231 | |||
232 | int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, | ||
233 | const char *name) | ||
234 | { | ||
235 | struct sigma_firmware ssfw; | ||
236 | |||
237 | ssfw.control_data = regmap; | ||
238 | ssfw.write = sigma_action_write_regmap; | ||
239 | |||
240 | return _process_sigma_firmware(dev, &ssfw, name); | ||
241 | } | ||
242 | EXPORT_SYMBOL(process_sigma_firmware_regmap); | ||
243 | |||
244 | #endif | ||
245 | 184 | ||
246 | MODULE_LICENSE("GPL"); | 185 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index e439cbd7af7d..c47cd23e9827 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h | |||
@@ -12,6 +12,26 @@ | |||
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
14 | 14 | ||
15 | struct sigma_action { | ||
16 | u8 instr; | ||
17 | u8 len_hi; | ||
18 | __le16 len; | ||
19 | __be16 addr; | ||
20 | unsigned char payload[]; | ||
21 | } __packed; | ||
22 | |||
23 | struct sigma_firmware { | ||
24 | const struct firmware *fw; | ||
25 | size_t pos; | ||
26 | |||
27 | void *control_data; | ||
28 | int (*write)(void *control_data, const struct sigma_action *sa, | ||
29 | size_t len); | ||
30 | }; | ||
31 | |||
32 | int _process_sigma_firmware(struct device *dev, | ||
33 | struct sigma_firmware *ssfw, const char *name); | ||
34 | |||
15 | struct i2c_client; | 35 | struct i2c_client; |
16 | 36 | ||
17 | extern int process_sigma_firmware(struct i2c_client *client, const char *name); | 37 | extern int process_sigma_firmware(struct i2c_client *client, const char *name); |
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 23419109ecac..1cdae8ccc61b 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -1178,7 +1178,7 @@ static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) | |||
1178 | } | 1178 | } |
1179 | #endif /* CONFIG_OF */ | 1179 | #endif /* CONFIG_OF */ |
1180 | 1180 | ||
1181 | static void aic31xx_device_init(struct aic31xx_priv *aic31xx) | 1181 | static int aic31xx_device_init(struct aic31xx_priv *aic31xx) |
1182 | { | 1182 | { |
1183 | int ret, i; | 1183 | int ret, i; |
1184 | 1184 | ||
@@ -1197,7 +1197,7 @@ static void aic31xx_device_init(struct aic31xx_priv *aic31xx) | |||
1197 | "aic31xx-reset-pin"); | 1197 | "aic31xx-reset-pin"); |
1198 | if (ret < 0) { | 1198 | if (ret < 0) { |
1199 | dev_err(aic31xx->dev, "not able to acquire gpio\n"); | 1199 | dev_err(aic31xx->dev, "not able to acquire gpio\n"); |
1200 | return; | 1200 | return ret; |
1201 | } | 1201 | } |
1202 | } | 1202 | } |
1203 | 1203 | ||
@@ -1210,6 +1210,7 @@ static void aic31xx_device_init(struct aic31xx_priv *aic31xx) | |||
1210 | if (ret != 0) | 1210 | if (ret != 0) |
1211 | dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret); | 1211 | dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret); |
1212 | 1212 | ||
1213 | return ret; | ||
1213 | } | 1214 | } |
1214 | 1215 | ||
1215 | static int aic31xx_i2c_probe(struct i2c_client *i2c, | 1216 | static int aic31xx_i2c_probe(struct i2c_client *i2c, |
@@ -1239,7 +1240,9 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, | |||
1239 | 1240 | ||
1240 | aic31xx->pdata.codec_type = id->driver_data; | 1241 | aic31xx->pdata.codec_type = id->driver_data; |
1241 | 1242 | ||
1242 | aic31xx_device_init(aic31xx); | 1243 | ret = aic31xx_device_init(aic31xx); |
1244 | if (ret) | ||
1245 | return ret; | ||
1243 | 1246 | ||
1244 | return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, | 1247 | return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, |
1245 | aic31xx_dai_driver, | 1248 | aic31xx_dai_driver, |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index e12fafbb1e09..5360772bc1ad 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -879,7 +879,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
879 | case SNDRV_PCM_FORMAT_S20_3LE: | 879 | case SNDRV_PCM_FORMAT_S20_3LE: |
880 | data |= (0x01 << 4); | 880 | data |= (0x01 << 4); |
881 | break; | 881 | break; |
882 | case SNDRV_PCM_FORMAT_S24_LE: | 882 | case SNDRV_PCM_FORMAT_S24_3LE: |
883 | data |= (0x02 << 4); | 883 | data |= (0x02 << 4); |
884 | break; | 884 | break; |
885 | case SNDRV_PCM_FORMAT_S32_LE: | 885 | case SNDRV_PCM_FORMAT_S32_LE: |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index df3a7506c023..ff006cc95520 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -1404,7 +1404,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) | |||
1404 | if (dac33->irq >= 0) { | 1404 | if (dac33->irq >= 0) { |
1405 | ret = request_irq(dac33->irq, dac33_interrupt_handler, | 1405 | ret = request_irq(dac33->irq, dac33_interrupt_handler, |
1406 | IRQF_TRIGGER_RISING, | 1406 | IRQF_TRIGGER_RISING, |
1407 | codec->name, codec); | 1407 | codec->component.name, codec); |
1408 | if (ret < 0) { | 1408 | if (ret < 0) { |
1409 | dev_err(codec->dev, "Could not request IRQ%d (%d)\n", | 1409 | dev_err(codec->dev, "Could not request IRQ%d (%d)\n", |
1410 | dac33->irq, ret); | 1410 | dac33->irq, ret); |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 69e12a311ba2..6ab157065353 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -344,17 +344,16 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) | |||
344 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) | 344 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) |
345 | { | 345 | { |
346 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 346 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
347 | int status = -1; | ||
348 | 347 | ||
349 | if (enable) { | 348 | if (enable) { |
350 | twl4030->apll_enabled++; | 349 | twl4030->apll_enabled++; |
351 | if (twl4030->apll_enabled == 1) | 350 | if (twl4030->apll_enabled == 1) |
352 | status = twl4030_audio_enable_resource( | 351 | twl4030_audio_enable_resource( |
353 | TWL4030_AUDIO_RES_APLL); | 352 | TWL4030_AUDIO_RES_APLL); |
354 | } else { | 353 | } else { |
355 | twl4030->apll_enabled--; | 354 | twl4030->apll_enabled--; |
356 | if (!twl4030->apll_enabled) | 355 | if (!twl4030->apll_enabled) |
357 | status = twl4030_audio_disable_resource( | 356 | twl4030_audio_disable_resource( |
358 | TWL4030_AUDIO_RES_APLL); | 357 | TWL4030_AUDIO_RES_APLL); |
359 | } | 358 | } |
360 | } | 359 | } |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index edf27acc1d77..12fc0aed7503 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -479,7 +479,7 @@ static struct snd_soc_dai_driver uda134x_dai = { | |||
479 | static int uda134x_soc_probe(struct snd_soc_codec *codec) | 479 | static int uda134x_soc_probe(struct snd_soc_codec *codec) |
480 | { | 480 | { |
481 | struct uda134x_priv *uda134x; | 481 | struct uda134x_priv *uda134x; |
482 | struct uda134x_platform_data *pd = codec->card->dev->platform_data; | 482 | struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; |
483 | const struct snd_soc_dapm_widget *widgets; | 483 | const struct snd_soc_dapm_widget *widgets; |
484 | unsigned num_widgets; | 484 | unsigned num_widgets; |
485 | 485 | ||
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 91a9ea2a2056..7bb0d36d4c54 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -735,8 +735,7 @@ WM5100_MIXER_CONTROLS("LHPF4", WM5100_HPLP4MIX_INPUT_1_SOURCE), | |||
735 | static void wm5100_seq_notifier(struct snd_soc_dapm_context *dapm, | 735 | static void wm5100_seq_notifier(struct snd_soc_dapm_context *dapm, |
736 | enum snd_soc_dapm_type event, int subseq) | 736 | enum snd_soc_dapm_type event, int subseq) |
737 | { | 737 | { |
738 | struct snd_soc_codec *codec = container_of(dapm, | 738 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); |
739 | struct snd_soc_codec, dapm); | ||
740 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); | 739 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); |
741 | u16 val, expect, i; | 740 | u16 val, expect, i; |
742 | 741 | ||
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 289b64d89abd..f60234962527 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -612,6 +612,62 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
612 | return 0; | 612 | return 0; |
613 | } | 613 | } |
614 | 614 | ||
615 | static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, | ||
616 | struct snd_ctl_elem_value *ucontrol) | ||
617 | { | ||
618 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
619 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
620 | uint16_t data; | ||
621 | |||
622 | mutex_lock(&codec->mutex); | ||
623 | data = cpu_to_be16(arizona->dac_comp_coeff); | ||
624 | memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); | ||
625 | mutex_unlock(&codec->mutex); | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, | ||
631 | struct snd_ctl_elem_value *ucontrol) | ||
632 | { | ||
633 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
634 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
635 | |||
636 | mutex_lock(&codec->mutex); | ||
637 | memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, | ||
638 | sizeof(arizona->dac_comp_coeff)); | ||
639 | arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); | ||
640 | mutex_unlock(&codec->mutex); | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, | ||
646 | struct snd_ctl_elem_value *ucontrol) | ||
647 | { | ||
648 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
649 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
650 | |||
651 | mutex_lock(&codec->mutex); | ||
652 | ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; | ||
653 | mutex_unlock(&codec->mutex); | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, | ||
659 | struct snd_ctl_elem_value *ucontrol) | ||
660 | { | ||
661 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
662 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
663 | |||
664 | mutex_lock(&codec->mutex); | ||
665 | arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; | ||
666 | mutex_unlock(&codec->mutex); | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
615 | static const char *wm5102_osr_text[] = { | 671 | static const char *wm5102_osr_text[] = { |
616 | "Low power", "Normal", "High performance", | 672 | "Low power", "Normal", "High performance", |
617 | }; | 673 | }; |
@@ -843,6 +899,12 @@ SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL, | |||
843 | ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), | 899 | ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), |
844 | SOC_ENUM("Noise Gate Hold", arizona_ng_hold), | 900 | SOC_ENUM("Noise Gate Hold", arizona_ng_hold), |
845 | 901 | ||
902 | SND_SOC_BYTES_EXT("Output Compensation Coefficient", 2, | ||
903 | wm5102_out_comp_coeff_get, wm5102_out_comp_coeff_put), | ||
904 | |||
905 | SOC_SINGLE_EXT("Output Compensation Switch", 0, 0, 1, 0, | ||
906 | wm5102_out_comp_switch_get, wm5102_out_comp_switch_put), | ||
907 | |||
846 | WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), | 908 | WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), |
847 | WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), | 909 | WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), |
848 | WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L), | 910 | WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L), |
@@ -1653,6 +1715,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { | |||
1653 | }, | 1715 | }, |
1654 | .ops = &arizona_dai_ops, | 1716 | .ops = &arizona_dai_ops, |
1655 | .symmetric_rates = 1, | 1717 | .symmetric_rates = 1, |
1718 | .symmetric_samplebits = 1, | ||
1656 | }, | 1719 | }, |
1657 | { | 1720 | { |
1658 | .name = "wm5102-aif2", | 1721 | .name = "wm5102-aif2", |
@@ -1674,6 +1737,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { | |||
1674 | }, | 1737 | }, |
1675 | .ops = &arizona_dai_ops, | 1738 | .ops = &arizona_dai_ops, |
1676 | .symmetric_rates = 1, | 1739 | .symmetric_rates = 1, |
1740 | .symmetric_samplebits = 1, | ||
1677 | }, | 1741 | }, |
1678 | { | 1742 | { |
1679 | .name = "wm5102-aif3", | 1743 | .name = "wm5102-aif3", |
@@ -1695,6 +1759,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { | |||
1695 | }, | 1759 | }, |
1696 | .ops = &arizona_dai_ops, | 1760 | .ops = &arizona_dai_ops, |
1697 | .symmetric_rates = 1, | 1761 | .symmetric_rates = 1, |
1762 | .symmetric_samplebits = 1, | ||
1698 | }, | 1763 | }, |
1699 | { | 1764 | { |
1700 | .name = "wm5102-slim1", | 1765 | .name = "wm5102-slim1", |
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2e5fcb559e90..2f2ec26d831c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -1485,6 +1485,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { | |||
1485 | }, | 1485 | }, |
1486 | .ops = &arizona_dai_ops, | 1486 | .ops = &arizona_dai_ops, |
1487 | .symmetric_rates = 1, | 1487 | .symmetric_rates = 1, |
1488 | .symmetric_samplebits = 1, | ||
1488 | }, | 1489 | }, |
1489 | { | 1490 | { |
1490 | .name = "wm5110-aif2", | 1491 | .name = "wm5110-aif2", |
@@ -1506,6 +1507,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { | |||
1506 | }, | 1507 | }, |
1507 | .ops = &arizona_dai_ops, | 1508 | .ops = &arizona_dai_ops, |
1508 | .symmetric_rates = 1, | 1509 | .symmetric_rates = 1, |
1510 | .symmetric_samplebits = 1, | ||
1509 | }, | 1511 | }, |
1510 | { | 1512 | { |
1511 | .name = "wm5110-aif3", | 1513 | .name = "wm5110-aif3", |
@@ -1527,6 +1529,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { | |||
1527 | }, | 1529 | }, |
1528 | .ops = &arizona_dai_ops, | 1530 | .ops = &arizona_dai_ops, |
1529 | .symmetric_rates = 1, | 1531 | .symmetric_rates = 1, |
1532 | .symmetric_samplebits = 1, | ||
1530 | }, | 1533 | }, |
1531 | { | 1534 | { |
1532 | .name = "wm5110-slim1", | 1535 | .name = "wm5110-slim1", |
@@ -1596,6 +1599,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) | |||
1596 | 1599 | ||
1597 | arizona_init_spk(codec); | 1600 | arizona_init_spk(codec); |
1598 | arizona_init_gpio(codec); | 1601 | arizona_init_gpio(codec); |
1602 | arizona_init_mono(codec); | ||
1599 | 1603 | ||
1600 | ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8); | 1604 | ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8); |
1601 | if (ret != 0) | 1605 | if (ret != 0) |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 392285edb595..d9e634c55e81 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1341,21 +1341,18 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | |||
1341 | { | 1341 | { |
1342 | struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); | 1342 | struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); |
1343 | struct wm8350 *wm8350 = priv->wm8350; | 1343 | struct wm8350 *wm8350 = priv->wm8350; |
1344 | int irq; | ||
1345 | int ena; | 1344 | int ena; |
1346 | 1345 | ||
1347 | switch (which) { | 1346 | switch (which) { |
1348 | case WM8350_JDL: | 1347 | case WM8350_JDL: |
1349 | priv->hpl.jack = jack; | 1348 | priv->hpl.jack = jack; |
1350 | priv->hpl.report = report; | 1349 | priv->hpl.report = report; |
1351 | irq = WM8350_IRQ_CODEC_JCK_DET_L; | ||
1352 | ena = WM8350_JDL_ENA; | 1350 | ena = WM8350_JDL_ENA; |
1353 | break; | 1351 | break; |
1354 | 1352 | ||
1355 | case WM8350_JDR: | 1353 | case WM8350_JDR: |
1356 | priv->hpr.jack = jack; | 1354 | priv->hpr.jack = jack; |
1357 | priv->hpr.report = report; | 1355 | priv->hpr.report = report; |
1358 | irq = WM8350_IRQ_CODEC_JCK_DET_R; | ||
1359 | ena = WM8350_JDR_ENA; | 1356 | ena = WM8350_JDR_ENA; |
1360 | break; | 1357 | break; |
1361 | 1358 | ||
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b84940c359a1..ec3250daa93e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -281,8 +281,7 @@ static int wm8903_dcs_event(struct snd_soc_dapm_widget *w, | |||
281 | static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, | 281 | static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, |
282 | enum snd_soc_dapm_type event, int subseq) | 282 | enum snd_soc_dapm_type event, int subseq) |
283 | { | 283 | { |
284 | struct snd_soc_codec *codec = container_of(dapm, | 284 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); |
285 | struct snd_soc_codec, dapm); | ||
286 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 285 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
287 | int dcs_mode = WM8903_DCS_MODE_WRITE_STOP; | 286 | int dcs_mode = WM8903_DCS_MODE_WRITE_STOP; |
288 | int i, val; | 287 | int i, val; |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index a145d0431b63..e96349b04ba6 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -472,7 +472,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec) | |||
472 | * list each time to find the desired power state do so now | 472 | * list each time to find the desired power state do so now |
473 | * and save the result. | 473 | * and save the result. |
474 | */ | 474 | */ |
475 | list_for_each_entry(w, &codec->card->widgets, list) { | 475 | list_for_each_entry(w, &codec->component.card->widgets, list) { |
476 | if (w->dapm != &codec->dapm) | 476 | if (w->dapm != &codec->dapm) |
477 | continue; | 477 | continue; |
478 | if (strcmp(w->name, "LOUT1 PGA") == 0) | 478 | if (strcmp(w->name, "LOUT1 PGA") == 0) |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 247b39013fba..9719d3ca8e47 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -3505,6 +3505,7 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) | |||
3505 | return IRQ_HANDLED; | 3505 | return IRQ_HANDLED; |
3506 | } | 3506 | } |
3507 | 3507 | ||
3508 | /* Should be called with accdet_lock held */ | ||
3508 | static void wm1811_micd_stop(struct snd_soc_codec *codec) | 3509 | static void wm1811_micd_stop(struct snd_soc_codec *codec) |
3509 | { | 3510 | { |
3510 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3511 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
@@ -3512,14 +3513,10 @@ static void wm1811_micd_stop(struct snd_soc_codec *codec) | |||
3512 | if (!wm8994->jackdet) | 3513 | if (!wm8994->jackdet) |
3513 | return; | 3514 | return; |
3514 | 3515 | ||
3515 | mutex_lock(&wm8994->accdet_lock); | ||
3516 | |||
3517 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0); | 3516 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0); |
3518 | 3517 | ||
3519 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); | 3518 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); |
3520 | 3519 | ||
3521 | mutex_unlock(&wm8994->accdet_lock); | ||
3522 | |||
3523 | if (wm8994->wm8994->pdata.jd_ext_cap) | 3520 | if (wm8994->wm8994->pdata.jd_ext_cap) |
3524 | snd_soc_dapm_disable_pin(&codec->dapm, | 3521 | snd_soc_dapm_disable_pin(&codec->dapm, |
3525 | "MICBIAS2"); | 3522 | "MICBIAS2"); |
@@ -3560,10 +3557,10 @@ static void wm8958_open_circuit_work(struct work_struct *work) | |||
3560 | open_circuit_work.work); | 3557 | open_circuit_work.work); |
3561 | struct device *dev = wm8994->wm8994->dev; | 3558 | struct device *dev = wm8994->wm8994->dev; |
3562 | 3559 | ||
3563 | wm1811_micd_stop(wm8994->hubs.codec); | ||
3564 | |||
3565 | mutex_lock(&wm8994->accdet_lock); | 3560 | mutex_lock(&wm8994->accdet_lock); |
3566 | 3561 | ||
3562 | wm1811_micd_stop(wm8994->hubs.codec); | ||
3563 | |||
3567 | dev_dbg(dev, "Reporting open circuit\n"); | 3564 | dev_dbg(dev, "Reporting open circuit\n"); |
3568 | 3565 | ||
3569 | wm8994->jack_mic = false; | 3566 | wm8994->jack_mic = false; |
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 69266332760e..f16ff4f56923 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c | |||
@@ -620,15 +620,12 @@ static int bg_event(struct snd_soc_dapm_widget *w, | |||
620 | static int cp_event(struct snd_soc_dapm_widget *w, | 620 | static int cp_event(struct snd_soc_dapm_widget *w, |
621 | struct snd_kcontrol *kcontrol, int event) | 621 | struct snd_kcontrol *kcontrol, int event) |
622 | { | 622 | { |
623 | int ret = 0; | ||
624 | |||
625 | switch (event) { | 623 | switch (event) { |
626 | case SND_SOC_DAPM_POST_PMU: | 624 | case SND_SOC_DAPM_POST_PMU: |
627 | msleep(5); | 625 | msleep(5); |
628 | break; | 626 | break; |
629 | default: | 627 | default: |
630 | WARN(1, "Invalid event %d\n", event); | 628 | WARN(1, "Invalid event %d\n", event); |
631 | ret = -EINVAL; | ||
632 | } | 629 | } |
633 | 630 | ||
634 | return 0; | 631 | return 0; |
@@ -690,8 +687,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask) | |||
690 | static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, | 687 | static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, |
691 | enum snd_soc_dapm_type event, int subseq) | 688 | enum snd_soc_dapm_type event, int subseq) |
692 | { | 689 | { |
693 | struct snd_soc_codec *codec = container_of(dapm, | 690 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); |
694 | struct snd_soc_codec, dapm); | ||
695 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | 691 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); |
696 | u16 val, mask; | 692 | u16 val, mask; |
697 | 693 | ||
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index bb9b47b956aa..ab33fe596519 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c | |||
@@ -967,6 +967,7 @@ static struct snd_soc_dai_driver wm8997_dai[] = { | |||
967 | }, | 967 | }, |
968 | .ops = &arizona_dai_ops, | 968 | .ops = &arizona_dai_ops, |
969 | .symmetric_rates = 1, | 969 | .symmetric_rates = 1, |
970 | .symmetric_samplebits = 1, | ||
970 | }, | 971 | }, |
971 | { | 972 | { |
972 | .name = "wm8997-aif2", | 973 | .name = "wm8997-aif2", |
@@ -988,6 +989,7 @@ static struct snd_soc_dai_driver wm8997_dai[] = { | |||
988 | }, | 989 | }, |
989 | .ops = &arizona_dai_ops, | 990 | .ops = &arizona_dai_ops, |
990 | .symmetric_rates = 1, | 991 | .symmetric_rates = 1, |
992 | .symmetric_samplebits = 1, | ||
991 | }, | 993 | }, |
992 | { | 994 | { |
993 | .name = "wm8997-slim1", | 995 | .name = "wm8997-slim1", |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 060027182dcb..f412a9911a75 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -1382,7 +1382,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1382 | int ret; | 1382 | int ret; |
1383 | int val; | 1383 | int val; |
1384 | 1384 | ||
1385 | dsp->card = codec->card; | 1385 | dsp->card = codec->component.card; |
1386 | 1386 | ||
1387 | switch (event) { | 1387 | switch (event) { |
1388 | case SND_SOC_DAPM_POST_PMU: | 1388 | case SND_SOC_DAPM_POST_PMU: |
@@ -1617,7 +1617,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, | |||
1617 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 1617 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
1618 | struct wm_adsp *dsp = &dsps[w->shift]; | 1618 | struct wm_adsp *dsp = &dsps[w->shift]; |
1619 | 1619 | ||
1620 | dsp->card = codec->card; | 1620 | dsp->card = codec->component.card; |
1621 | 1621 | ||
1622 | switch (event) { | 1622 | switch (event) { |
1623 | case SND_SOC_DAPM_PRE_PMU: | 1623 | case SND_SOC_DAPM_PRE_PMU: |
@@ -1758,3 +1758,5 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
1758 | return 0; | 1758 | return 0; |
1759 | } | 1759 | } |
1760 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 1760 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
1761 | |||
1762 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 50a098749b9e..d69510c53239 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -1,12 +1,29 @@ | |||
1 | config SND_DAVINCI_SOC | 1 | config SND_DAVINCI_SOC |
2 | tristate "SoC Audio for TI DAVINCI or AM33XX/AM43XX chips" | 2 | tristate "SoC Audio for TI DAVINCI" |
3 | depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX | 3 | depends on ARCH_DAVINCI |
4 | |||
5 | config SND_EDMA_SOC | ||
6 | tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)" | ||
7 | depends on SOC_AM33XX || SOC_AM43XX | ||
8 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
9 | help | ||
10 | Say Y or M here if you want audio support for TI SoC which uses eDMA. | ||
11 | The following line of SoCs are supported by this platform driver: | ||
12 | - AM335x | ||
13 | - AM437x/AM438x | ||
4 | 14 | ||
5 | config SND_DAVINCI_SOC_I2S | 15 | config SND_DAVINCI_SOC_I2S |
6 | tristate | 16 | tristate |
7 | 17 | ||
8 | config SND_DAVINCI_SOC_MCASP | 18 | config SND_DAVINCI_SOC_MCASP |
9 | tristate | 19 | tristate "Multichannel Audio Serial Port (McASP) support" |
20 | depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC | ||
21 | help | ||
22 | Say Y or M here if you want to have support for McASP IP found in | ||
23 | various Texas Instruments SoCs like: | ||
24 | - daVinci devices | ||
25 | - Sitara line of SoCs (AM335x, AM438x, etc) | ||
26 | - DRA7x devices | ||
10 | 27 | ||
11 | config SND_DAVINCI_SOC_VCIF | 28 | config SND_DAVINCI_SOC_VCIF |
12 | tristate | 29 | tristate |
@@ -18,7 +35,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM | |||
18 | 35 | ||
19 | config SND_AM33XX_SOC_EVM | 36 | config SND_AM33XX_SOC_EVM |
20 | tristate "SoC Audio for the AM33XX chip based boards" | 37 | tristate "SoC Audio for the AM33XX chip based boards" |
21 | depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C | 38 | depends on SND_EDMA_SOC && SOC_AM33XX && I2C |
22 | select SND_DAVINCI_SOC_GENERIC_EVM | 39 | select SND_DAVINCI_SOC_GENERIC_EVM |
23 | help | 40 | help |
24 | Say Y or M if you want to add support for SoC audio on AM33XX | 41 | Say Y or M if you want to add support for SoC audio on AM33XX |
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index 744d4d9a0184..09bf2ba92d38 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile | |||
@@ -1,10 +1,12 @@ | |||
1 | # DAVINCI Platform Support | 1 | # DAVINCI Platform Support |
2 | snd-soc-davinci-objs := davinci-pcm.o | 2 | snd-soc-davinci-objs := davinci-pcm.o |
3 | snd-soc-edma-objs := edma-pcm.o | ||
3 | snd-soc-davinci-i2s-objs := davinci-i2s.o | 4 | snd-soc-davinci-i2s-objs := davinci-i2s.o |
4 | snd-soc-davinci-mcasp-objs:= davinci-mcasp.o | 5 | snd-soc-davinci-mcasp-objs:= davinci-mcasp.o |
5 | snd-soc-davinci-vcif-objs:= davinci-vcif.o | 6 | snd-soc-davinci-vcif-objs:= davinci-vcif.o |
6 | 7 | ||
7 | obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o | 8 | obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o |
9 | obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o | ||
8 | obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o | 10 | obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o |
9 | obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o | 11 | obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o |
10 | obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o | 12 | obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 9afb14629a17..c28508da34cf 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/of_platform.h> | 27 | #include <linux/of_platform.h> |
28 | #include <linux/of_device.h> | 28 | #include <linux/of_device.h> |
29 | 29 | ||
30 | #include <sound/asoundef.h> | ||
30 | #include <sound/core.h> | 31 | #include <sound/core.h> |
31 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
32 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
@@ -36,6 +37,7 @@ | |||
36 | #include <sound/omap-pcm.h> | 37 | #include <sound/omap-pcm.h> |
37 | 38 | ||
38 | #include "davinci-pcm.h" | 39 | #include "davinci-pcm.h" |
40 | #include "edma-pcm.h" | ||
39 | #include "davinci-mcasp.h" | 41 | #include "davinci-mcasp.h" |
40 | 42 | ||
41 | #define MCASP_MAX_AFIFO_DEPTH 64 | 43 | #define MCASP_MAX_AFIFO_DEPTH 64 |
@@ -63,6 +65,7 @@ struct davinci_mcasp { | |||
63 | u8 num_serializer; | 65 | u8 num_serializer; |
64 | u8 *serial_dir; | 66 | u8 *serial_dir; |
65 | u8 version; | 67 | u8 version; |
68 | u8 bclk_div; | ||
66 | u16 bclk_lrclk_ratio; | 69 | u16 bclk_lrclk_ratio; |
67 | int streams; | 70 | int streams; |
68 | 71 | ||
@@ -417,6 +420,7 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div | |||
417 | ACLKXDIV(div - 1), ACLKXDIV_MASK); | 420 | ACLKXDIV(div - 1), ACLKXDIV_MASK); |
418 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, | 421 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, |
419 | ACLKRDIV(div - 1), ACLKRDIV_MASK); | 422 | ACLKRDIV(div - 1), ACLKRDIV_MASK); |
423 | mcasp->bclk_div = div; | ||
420 | break; | 424 | break; |
421 | 425 | ||
422 | case 2: /* BCLK/LRCLK ratio */ | 426 | case 2: /* BCLK/LRCLK ratio */ |
@@ -637,8 +641,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) | |||
637 | } | 641 | } |
638 | 642 | ||
639 | /* S/PDIF */ | 643 | /* S/PDIF */ |
640 | static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) | 644 | static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp, |
645 | unsigned int rate) | ||
641 | { | 646 | { |
647 | u32 cs_value = 0; | ||
648 | u8 *cs_bytes = (u8*) &cs_value; | ||
649 | |||
642 | /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 | 650 | /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 |
643 | and LSB first */ | 651 | and LSB first */ |
644 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15)); | 652 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15)); |
@@ -660,6 +668,46 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) | |||
660 | /* Enable the DIT */ | 668 | /* Enable the DIT */ |
661 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); | 669 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); |
662 | 670 | ||
671 | /* Set S/PDIF channel status bits */ | ||
672 | cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT; | ||
673 | cs_bytes[1] = IEC958_AES1_CON_PCM_CODER; | ||
674 | |||
675 | switch (rate) { | ||
676 | case 22050: | ||
677 | cs_bytes[3] |= IEC958_AES3_CON_FS_22050; | ||
678 | break; | ||
679 | case 24000: | ||
680 | cs_bytes[3] |= IEC958_AES3_CON_FS_24000; | ||
681 | break; | ||
682 | case 32000: | ||
683 | cs_bytes[3] |= IEC958_AES3_CON_FS_32000; | ||
684 | break; | ||
685 | case 44100: | ||
686 | cs_bytes[3] |= IEC958_AES3_CON_FS_44100; | ||
687 | break; | ||
688 | case 48000: | ||
689 | cs_bytes[3] |= IEC958_AES3_CON_FS_48000; | ||
690 | break; | ||
691 | case 88200: | ||
692 | cs_bytes[3] |= IEC958_AES3_CON_FS_88200; | ||
693 | break; | ||
694 | case 96000: | ||
695 | cs_bytes[3] |= IEC958_AES3_CON_FS_96000; | ||
696 | break; | ||
697 | case 176400: | ||
698 | cs_bytes[3] |= IEC958_AES3_CON_FS_176400; | ||
699 | break; | ||
700 | case 192000: | ||
701 | cs_bytes[3] |= IEC958_AES3_CON_FS_192000; | ||
702 | break; | ||
703 | default: | ||
704 | printk(KERN_WARNING "unsupported sampling rate: %d\n", rate); | ||
705 | return -EINVAL; | ||
706 | } | ||
707 | |||
708 | mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value); | ||
709 | mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value); | ||
710 | |||
663 | return 0; | 711 | return 0; |
664 | } | 712 | } |
665 | 713 | ||
@@ -675,15 +723,22 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
675 | int period_size = params_period_size(params); | 723 | int period_size = params_period_size(params); |
676 | int ret; | 724 | int ret; |
677 | 725 | ||
678 | /* If mcasp is BCLK master we need to set BCLK divider */ | 726 | /* |
679 | if (mcasp->bclk_master) { | 727 | * If mcasp is BCLK master, and a BCLK divider was not provided by |
728 | * the machine driver, we need to calculate the ratio. | ||
729 | */ | ||
730 | if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { | ||
680 | unsigned int bclk_freq = snd_soc_params_to_bclk(params); | 731 | unsigned int bclk_freq = snd_soc_params_to_bclk(params); |
732 | unsigned int div = mcasp->sysclk_freq / bclk_freq; | ||
681 | if (mcasp->sysclk_freq % bclk_freq != 0) { | 733 | if (mcasp->sysclk_freq % bclk_freq != 0) { |
682 | dev_err(mcasp->dev, "Can't produce required BCLK\n"); | 734 | if (((mcasp->sysclk_freq / div) - bclk_freq) > |
683 | return -EINVAL; | 735 | (bclk_freq - (mcasp->sysclk_freq / (div+1)))) |
736 | div++; | ||
737 | dev_warn(mcasp->dev, | ||
738 | "Inaccurate BCLK: %u Hz / %u != %u Hz\n", | ||
739 | mcasp->sysclk_freq, div, bclk_freq); | ||
684 | } | 740 | } |
685 | davinci_mcasp_set_clkdiv( | 741 | davinci_mcasp_set_clkdiv(cpu_dai, 1, div); |
686 | cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); | ||
687 | } | 742 | } |
688 | 743 | ||
689 | ret = mcasp_common_hw_param(mcasp, substream->stream, | 744 | ret = mcasp_common_hw_param(mcasp, substream->stream, |
@@ -692,7 +747,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
692 | return ret; | 747 | return ret; |
693 | 748 | ||
694 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 749 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
695 | ret = mcasp_dit_hw_param(mcasp); | 750 | ret = mcasp_dit_hw_param(mcasp, params_rate(params)); |
696 | else | 751 | else |
697 | ret = mcasp_i2s_hw_param(mcasp, substream->stream); | 752 | ret = mcasp_i2s_hw_param(mcasp, substream->stream); |
698 | 753 | ||
@@ -720,6 +775,10 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
720 | 775 | ||
721 | case SNDRV_PCM_FORMAT_U24_LE: | 776 | case SNDRV_PCM_FORMAT_U24_LE: |
722 | case SNDRV_PCM_FORMAT_S24_LE: | 777 | case SNDRV_PCM_FORMAT_S24_LE: |
778 | dma_params->data_type = 4; | ||
779 | word_length = 24; | ||
780 | break; | ||
781 | |||
723 | case SNDRV_PCM_FORMAT_U32_LE: | 782 | case SNDRV_PCM_FORMAT_U32_LE: |
724 | case SNDRV_PCM_FORMAT_S32_LE: | 783 | case SNDRV_PCM_FORMAT_S32_LE: |
725 | dma_params->data_type = 4; | 784 | dma_params->data_type = 4; |
@@ -778,7 +837,7 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) | |||
778 | { | 837 | { |
779 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 838 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); |
780 | 839 | ||
781 | if (mcasp->version == MCASP_VERSION_4) { | 840 | if (mcasp->version >= MCASP_VERSION_3) { |
782 | /* Using dmaengine PCM */ | 841 | /* Using dmaengine PCM */ |
783 | dai->playback_dma_data = | 842 | dai->playback_dma_data = |
784 | &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; | 843 | &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; |
@@ -1223,14 +1282,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1223 | goto err; | 1282 | goto err; |
1224 | 1283 | ||
1225 | switch (mcasp->version) { | 1284 | switch (mcasp->version) { |
1285 | #if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \ | ||
1286 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | ||
1287 | IS_MODULE(CONFIG_SND_DAVINCI_SOC)) | ||
1226 | case MCASP_VERSION_1: | 1288 | case MCASP_VERSION_1: |
1227 | case MCASP_VERSION_2: | 1289 | case MCASP_VERSION_2: |
1228 | case MCASP_VERSION_3: | ||
1229 | ret = davinci_soc_platform_register(&pdev->dev); | 1290 | ret = davinci_soc_platform_register(&pdev->dev); |
1230 | break; | 1291 | break; |
1292 | #endif | ||
1293 | #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ | ||
1294 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | ||
1295 | IS_MODULE(CONFIG_SND_EDMA_SOC)) | ||
1296 | case MCASP_VERSION_3: | ||
1297 | ret = edma_pcm_platform_register(&pdev->dev); | ||
1298 | break; | ||
1299 | #endif | ||
1300 | #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ | ||
1301 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | ||
1302 | IS_MODULE(CONFIG_SND_OMAP_SOC)) | ||
1231 | case MCASP_VERSION_4: | 1303 | case MCASP_VERSION_4: |
1232 | ret = omap_pcm_platform_register(&pdev->dev); | 1304 | ret = omap_pcm_platform_register(&pdev->dev); |
1233 | break; | 1305 | break; |
1306 | #endif | ||
1234 | default: | 1307 | default: |
1235 | dev_err(&pdev->dev, "Invalid McASP version: %d\n", | 1308 | dev_err(&pdev->dev, "Invalid McASP version: %d\n", |
1236 | mcasp->version); | 1309 | mcasp->version); |
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c index d38afb1c61ae..605e643133db 100644 --- a/sound/soc/davinci/edma-pcm.c +++ b/sound/soc/davinci/edma-pcm.c | |||
@@ -28,8 +28,8 @@ | |||
28 | static const struct snd_pcm_hardware edma_pcm_hardware = { | 28 | static const struct snd_pcm_hardware edma_pcm_hardware = { |
29 | .info = SNDRV_PCM_INFO_MMAP | | 29 | .info = SNDRV_PCM_INFO_MMAP | |
30 | SNDRV_PCM_INFO_MMAP_VALID | | 30 | SNDRV_PCM_INFO_MMAP_VALID | |
31 | SNDRV_PCM_INFO_BATCH | | ||
32 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | | 31 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | |
32 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP | | ||
33 | SNDRV_PCM_INFO_INTERLEAVED, | 33 | SNDRV_PCM_INFO_INTERLEAVED, |
34 | .buffer_bytes_max = 128 * 1024, | 34 | .buffer_bytes_max = 128 * 1024, |
35 | .period_bytes_min = 32, | 35 | .period_bytes_min = 32, |
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/davinci/edma-pcm.h index 894c378c0f74..b0957744851c 100644 --- a/sound/soc/davinci/edma-pcm.h +++ b/sound/soc/davinci/edma-pcm.h | |||
@@ -20,6 +20,13 @@ | |||
20 | #ifndef __EDMA_PCM_H__ | 20 | #ifndef __EDMA_PCM_H__ |
21 | #define __EDMA_PCM_H__ | 21 | #define __EDMA_PCM_H__ |
22 | 22 | ||
23 | #if IS_ENABLED(CONFIG_SND_EDMA_SOC) | ||
23 | int edma_pcm_platform_register(struct device *dev); | 24 | int edma_pcm_platform_register(struct device *dev); |
25 | #else | ||
26 | static inline int edma_pcm_platform_register(struct device *dev) | ||
27 | { | ||
28 | return 0; | ||
29 | } | ||
30 | #endif /* CONFIG_SND_EDMA_SOC */ | ||
24 | 31 | ||
25 | #endif /* __EDMA_PCM_H__ */ | 32 | #endif /* __EDMA_PCM_H__ */ |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 37933629cbed..f54a8fc99291 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -2,9 +2,20 @@ menu "SoC Audio for Freescale CPUs" | |||
2 | 2 | ||
3 | comment "Common SoC Audio options for Freescale CPUs:" | 3 | comment "Common SoC Audio options for Freescale CPUs:" |
4 | 4 | ||
5 | config SND_SOC_FSL_ASRC | ||
6 | tristate "Asynchronous Sample Rate Converter (ASRC) module support" | ||
7 | select REGMAP_MMIO | ||
8 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
9 | help | ||
10 | Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) | ||
11 | support for the Freescale CPUs. | ||
12 | This option is only useful for out-of-tree drivers since | ||
13 | in-tree drivers select it automatically. | ||
14 | |||
5 | config SND_SOC_FSL_SAI | 15 | config SND_SOC_FSL_SAI |
6 | tristate "Synchronous Audio Interface (SAI) module support" | 16 | tristate "Synchronous Audio Interface (SAI) module support" |
7 | select REGMAP_MMIO | 17 | select REGMAP_MMIO |
18 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n | ||
8 | select SND_SOC_GENERIC_DMAENGINE_PCM | 19 | select SND_SOC_GENERIC_DMAENGINE_PCM |
9 | help | 20 | help |
10 | Say Y if you want to add Synchronous Audio Interface (SAI) | 21 | Say Y if you want to add Synchronous Audio Interface (SAI) |
@@ -15,7 +26,7 @@ config SND_SOC_FSL_SAI | |||
15 | config SND_SOC_FSL_SSI | 26 | config SND_SOC_FSL_SSI |
16 | tristate "Synchronous Serial Interface module support" | 27 | tristate "Synchronous Serial Interface module support" |
17 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n | 28 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n |
18 | select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC | 29 | select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) |
19 | select REGMAP_MMIO | 30 | select REGMAP_MMIO |
20 | help | 31 | help |
21 | Say Y if you want to add Synchronous Serial Interface (SSI) | 32 | Say Y if you want to add Synchronous Serial Interface (SSI) |
@@ -27,7 +38,7 @@ config SND_SOC_FSL_SPDIF | |||
27 | tristate "Sony/Philips Digital Interface module support" | 38 | tristate "Sony/Philips Digital Interface module support" |
28 | select REGMAP_MMIO | 39 | select REGMAP_MMIO |
29 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n | 40 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n |
30 | select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC | 41 | select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) |
31 | help | 42 | help |
32 | Say Y if you want to add Sony/Philips Digital Interface (SPDIF) | 43 | Say Y if you want to add Sony/Philips Digital Interface (SPDIF) |
33 | support for the Freescale CPUs. | 44 | support for the Freescale CPUs. |
@@ -37,6 +48,7 @@ config SND_SOC_FSL_SPDIF | |||
37 | config SND_SOC_FSL_ESAI | 48 | config SND_SOC_FSL_ESAI |
38 | tristate "Enhanced Serial Audio Interface (ESAI) module support" | 49 | tristate "Enhanced Serial Audio Interface (ESAI) module support" |
39 | select REGMAP_MMIO | 50 | select REGMAP_MMIO |
51 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n | ||
40 | select SND_SOC_FSL_UTILS | 52 | select SND_SOC_FSL_UTILS |
41 | help | 53 | help |
42 | Say Y if you want to add Enhanced Synchronous Audio Interface | 54 | Say Y if you want to add Enhanced Synchronous Audio Interface |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index db254e358c18..9ff59267eac9 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o | |||
11 | obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o | 11 | obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o |
12 | 12 | ||
13 | # Freescale SSI/DMA/SAI/SPDIF Support | 13 | # Freescale SSI/DMA/SAI/SPDIF Support |
14 | snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o | ||
14 | snd-soc-fsl-sai-objs := fsl_sai.o | 15 | snd-soc-fsl-sai-objs := fsl_sai.o |
15 | snd-soc-fsl-ssi-y := fsl_ssi.o | 16 | snd-soc-fsl-ssi-y := fsl_ssi.o |
16 | snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o | 17 | snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o |
@@ -18,6 +19,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o | |||
18 | snd-soc-fsl-esai-objs := fsl_esai.o | 19 | snd-soc-fsl-esai-objs := fsl_esai.o |
19 | snd-soc-fsl-utils-objs := fsl_utils.o | 20 | snd-soc-fsl-utils-objs := fsl_utils.o |
20 | snd-soc-fsl-dma-objs := fsl_dma.o | 21 | snd-soc-fsl-dma-objs := fsl_dma.o |
22 | obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o | ||
21 | obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o | 23 | obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o |
22 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o | 24 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o |
23 | obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o | 25 | obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o |
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c new file mode 100644 index 000000000000..822110420b71 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc.c | |||
@@ -0,0 +1,995 @@ | |||
1 | /* | ||
2 | * Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Nicolin Chen <nicoleotsuka@gmail.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/dma-mapping.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | #include <linux/platform_data/dma-imx.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | #include <sound/dmaengine_pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | |||
23 | #include "fsl_asrc.h" | ||
24 | |||
25 | #define IDEAL_RATIO_DECIMAL_DEPTH 26 | ||
26 | |||
27 | #define pair_err(fmt, ...) \ | ||
28 | dev_err(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) | ||
29 | |||
30 | #define pair_dbg(fmt, ...) \ | ||
31 | dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) | ||
32 | |||
33 | /* Sample rates are aligned with that defined in pcm.h file */ | ||
34 | static const u8 process_option[][8][2] = { | ||
35 | /* 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ | ||
36 | {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ | ||
37 | {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ | ||
38 | {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ | ||
39 | {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ | ||
40 | {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ | ||
41 | {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ | ||
42 | {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ | ||
43 | {{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ | ||
44 | {{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ | ||
45 | {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ | ||
46 | {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ | ||
47 | {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ | ||
48 | {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ | ||
49 | }; | ||
50 | |||
51 | /* Corresponding to process_option */ | ||
52 | static int supported_input_rate[] = { | ||
53 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, | ||
54 | 96000, 176400, 192000, | ||
55 | }; | ||
56 | |||
57 | static int supported_asrc_rate[] = { | ||
58 | 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, | ||
59 | }; | ||
60 | |||
61 | /** | ||
62 | * The following tables map the relationship between asrc_inclk/asrc_outclk in | ||
63 | * fsl_asrc.h and the registers of ASRCSR | ||
64 | */ | ||
65 | static unsigned char input_clk_map_imx35[] = { | ||
66 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, | ||
67 | }; | ||
68 | |||
69 | static unsigned char output_clk_map_imx35[] = { | ||
70 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, | ||
71 | }; | ||
72 | |||
73 | /* i.MX53 uses the same map for input and output */ | ||
74 | static unsigned char input_clk_map_imx53[] = { | ||
75 | /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ | ||
76 | 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, | ||
77 | }; | ||
78 | |||
79 | static unsigned char output_clk_map_imx53[] = { | ||
80 | /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ | ||
81 | 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, | ||
82 | }; | ||
83 | |||
84 | static unsigned char *clk_map[2]; | ||
85 | |||
86 | /** | ||
87 | * Request ASRC pair | ||
88 | * | ||
89 | * It assigns pair by the order of A->C->B because allocation of pair B, | ||
90 | * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A | ||
91 | * while pair A and pair C are comparatively independent. | ||
92 | */ | ||
93 | static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) | ||
94 | { | ||
95 | enum asrc_pair_index index = ASRC_INVALID_PAIR; | ||
96 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
97 | struct device *dev = &asrc_priv->pdev->dev; | ||
98 | unsigned long lock_flags; | ||
99 | int i, ret = 0; | ||
100 | |||
101 | spin_lock_irqsave(&asrc_priv->lock, lock_flags); | ||
102 | |||
103 | for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { | ||
104 | if (asrc_priv->pair[i] != NULL) | ||
105 | continue; | ||
106 | |||
107 | index = i; | ||
108 | |||
109 | if (i != ASRC_PAIR_B) | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | if (index == ASRC_INVALID_PAIR) { | ||
114 | dev_err(dev, "all pairs are busy now\n"); | ||
115 | ret = -EBUSY; | ||
116 | } else if (asrc_priv->channel_avail < channels) { | ||
117 | dev_err(dev, "can't afford required channels: %d\n", channels); | ||
118 | ret = -EINVAL; | ||
119 | } else { | ||
120 | asrc_priv->channel_avail -= channels; | ||
121 | asrc_priv->pair[index] = pair; | ||
122 | pair->channels = channels; | ||
123 | pair->index = index; | ||
124 | } | ||
125 | |||
126 | spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * Release ASRC pair | ||
133 | * | ||
134 | * It clears the resource from asrc_priv and releases the occupied channels. | ||
135 | */ | ||
136 | static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) | ||
137 | { | ||
138 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
139 | enum asrc_pair_index index = pair->index; | ||
140 | unsigned long lock_flags; | ||
141 | |||
142 | /* Make sure the pair is disabled */ | ||
143 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
144 | ASRCTR_ASRCEi_MASK(index), 0); | ||
145 | |||
146 | spin_lock_irqsave(&asrc_priv->lock, lock_flags); | ||
147 | |||
148 | asrc_priv->channel_avail += pair->channels; | ||
149 | asrc_priv->pair[index] = NULL; | ||
150 | pair->error = 0; | ||
151 | |||
152 | spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * Configure input and output thresholds | ||
157 | */ | ||
158 | static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) | ||
159 | { | ||
160 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
161 | enum asrc_pair_index index = pair->index; | ||
162 | |||
163 | regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), | ||
164 | ASRMCRi_EXTTHRSHi_MASK | | ||
165 | ASRMCRi_INFIFO_THRESHOLD_MASK | | ||
166 | ASRMCRi_OUTFIFO_THRESHOLD_MASK, | ||
167 | ASRMCRi_EXTTHRSHi | | ||
168 | ASRMCRi_INFIFO_THRESHOLD(in) | | ||
169 | ASRMCRi_OUTFIFO_THRESHOLD(out)); | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * Calculate the total divisor between asrck clock rate and sample rate | ||
174 | * | ||
175 | * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider | ||
176 | */ | ||
177 | static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) | ||
178 | { | ||
179 | u32 ps; | ||
180 | |||
181 | /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ | ||
182 | for (ps = 0; div > 8; ps++) | ||
183 | div >>= 1; | ||
184 | |||
185 | return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Calculate and set the ratio for Ideal Ratio mode only | ||
190 | * | ||
191 | * The ratio is a 32-bit fixed point value with 26 fractional bits. | ||
192 | */ | ||
193 | static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, | ||
194 | int inrate, int outrate) | ||
195 | { | ||
196 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
197 | enum asrc_pair_index index = pair->index; | ||
198 | unsigned long ratio; | ||
199 | int i; | ||
200 | |||
201 | if (!outrate) { | ||
202 | pair_err("output rate should not be zero\n"); | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | |||
206 | /* Calculate the intergal part of the ratio */ | ||
207 | ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; | ||
208 | |||
209 | /* ... and then the 26 depth decimal part */ | ||
210 | inrate %= outrate; | ||
211 | |||
212 | for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { | ||
213 | inrate <<= 1; | ||
214 | |||
215 | if (inrate < outrate) | ||
216 | continue; | ||
217 | |||
218 | ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); | ||
219 | inrate -= outrate; | ||
220 | |||
221 | if (!inrate) | ||
222 | break; | ||
223 | } | ||
224 | |||
225 | regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio); | ||
226 | regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * Configure the assigned ASRC pair | ||
233 | * | ||
234 | * It configures those ASRC registers according to a configuration instance | ||
235 | * of struct asrc_config which includes in/output sample rate, width, channel | ||
236 | * and clock settings. | ||
237 | */ | ||
238 | static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) | ||
239 | { | ||
240 | struct asrc_config *config = pair->config; | ||
241 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
242 | enum asrc_pair_index index = pair->index; | ||
243 | u32 inrate, outrate, indiv, outdiv; | ||
244 | u32 clk_index[2], div[2]; | ||
245 | int in, out, channels; | ||
246 | struct clk *clk; | ||
247 | bool ideal; | ||
248 | |||
249 | if (!config) { | ||
250 | pair_err("invalid pair config\n"); | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | /* Validate channels */ | ||
255 | if (config->channel_num < 1 || config->channel_num > 10) { | ||
256 | pair_err("does not support %d channels\n", config->channel_num); | ||
257 | return -EINVAL; | ||
258 | } | ||
259 | |||
260 | /* Validate output width */ | ||
261 | if (config->output_word_width == ASRC_WIDTH_8_BIT) { | ||
262 | pair_err("does not support 8bit width output\n"); | ||
263 | return -EINVAL; | ||
264 | } | ||
265 | |||
266 | inrate = config->input_sample_rate; | ||
267 | outrate = config->output_sample_rate; | ||
268 | ideal = config->inclk == INCLK_NONE; | ||
269 | |||
270 | /* Validate input and output sample rates */ | ||
271 | for (in = 0; in < ARRAY_SIZE(supported_input_rate); in++) | ||
272 | if (inrate == supported_input_rate[in]) | ||
273 | break; | ||
274 | |||
275 | if (in == ARRAY_SIZE(supported_input_rate)) { | ||
276 | pair_err("unsupported input sample rate: %dHz\n", inrate); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) | ||
281 | if (outrate == supported_asrc_rate[out]) | ||
282 | break; | ||
283 | |||
284 | if (out == ARRAY_SIZE(supported_asrc_rate)) { | ||
285 | pair_err("unsupported output sample rate: %dHz\n", outrate); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | /* Validate input and output clock sources */ | ||
290 | clk_index[IN] = clk_map[IN][config->inclk]; | ||
291 | clk_index[OUT] = clk_map[OUT][config->outclk]; | ||
292 | |||
293 | /* We only have output clock for ideal ratio mode */ | ||
294 | clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; | ||
295 | |||
296 | div[IN] = clk_get_rate(clk) / inrate; | ||
297 | if (div[IN] == 0) { | ||
298 | pair_err("failed to support input sample rate %dHz by asrck_%x\n", | ||
299 | inrate, clk_index[ideal ? OUT : IN]); | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | |||
303 | clk = asrc_priv->asrck_clk[clk_index[OUT]]; | ||
304 | |||
305 | /* Use fixed output rate for Ideal Ratio mode (INCLK_NONE) */ | ||
306 | if (ideal) | ||
307 | div[OUT] = clk_get_rate(clk) / IDEAL_RATIO_RATE; | ||
308 | else | ||
309 | div[OUT] = clk_get_rate(clk) / outrate; | ||
310 | |||
311 | if (div[OUT] == 0) { | ||
312 | pair_err("failed to support output sample rate %dHz by asrck_%x\n", | ||
313 | outrate, clk_index[OUT]); | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | /* Set the channel number */ | ||
318 | channels = config->channel_num; | ||
319 | |||
320 | if (asrc_priv->channel_bits < 4) | ||
321 | channels /= 2; | ||
322 | |||
323 | /* Update channels for current pair */ | ||
324 | regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR, | ||
325 | ASRCNCR_ANCi_MASK(index, asrc_priv->channel_bits), | ||
326 | ASRCNCR_ANCi(index, channels, asrc_priv->channel_bits)); | ||
327 | |||
328 | /* Default setting: Automatic selection for processing mode */ | ||
329 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
330 | ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); | ||
331 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
332 | ASRCTR_USRi_MASK(index), 0); | ||
333 | |||
334 | /* Set the input and output clock sources */ | ||
335 | regmap_update_bits(asrc_priv->regmap, REG_ASRCSR, | ||
336 | ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), | ||
337 | ASRCSR_AICS(index, clk_index[IN]) | | ||
338 | ASRCSR_AOCS(index, clk_index[OUT])); | ||
339 | |||
340 | /* Calculate the input clock divisors */ | ||
341 | indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); | ||
342 | outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); | ||
343 | |||
344 | /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ | ||
345 | regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index), | ||
346 | ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | | ||
347 | ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), | ||
348 | ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); | ||
349 | |||
350 | /* Implement word_width configurations */ | ||
351 | regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index), | ||
352 | ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, | ||
353 | ASRMCR1i_OW16(config->output_word_width) | | ||
354 | ASRMCR1i_IWD(config->input_word_width)); | ||
355 | |||
356 | /* Enable BUFFER STALL */ | ||
357 | regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), | ||
358 | ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); | ||
359 | |||
360 | /* Set default thresholds for input and output FIFO */ | ||
361 | fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, | ||
362 | ASRC_INPUTFIFO_THRESHOLD); | ||
363 | |||
364 | /* Configure the followings only for Ideal Ratio mode */ | ||
365 | if (!ideal) | ||
366 | return 0; | ||
367 | |||
368 | /* Clear ASTSx bit to use Ideal Ratio mode */ | ||
369 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
370 | ASRCTR_ATSi_MASK(index), 0); | ||
371 | |||
372 | /* Enable Ideal Ratio mode */ | ||
373 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
374 | ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), | ||
375 | ASRCTR_IDR(index) | ASRCTR_USR(index)); | ||
376 | |||
377 | /* Apply configurations for pre- and post-processing */ | ||
378 | regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, | ||
379 | ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), | ||
380 | ASRCFG_PREMOD(index, process_option[in][out][0]) | | ||
381 | ASRCFG_POSTMOD(index, process_option[in][out][1])); | ||
382 | |||
383 | return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * Start the assigned ASRC pair | ||
388 | * | ||
389 | * It enables the assigned pair and makes it stopped at the stall level. | ||
390 | */ | ||
391 | static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) | ||
392 | { | ||
393 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
394 | enum asrc_pair_index index = pair->index; | ||
395 | int reg, retry = 10, i; | ||
396 | |||
397 | /* Enable the current pair */ | ||
398 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
399 | ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); | ||
400 | |||
401 | /* Wait for status of initialization */ | ||
402 | do { | ||
403 | udelay(5); | ||
404 | regmap_read(asrc_priv->regmap, REG_ASRCFG, ®); | ||
405 | reg &= ASRCFG_INIRQi_MASK(index); | ||
406 | } while (!reg && --retry); | ||
407 | |||
408 | /* Make the input fifo to ASRC STALL level */ | ||
409 | regmap_read(asrc_priv->regmap, REG_ASRCNCR, ®); | ||
410 | for (i = 0; i < pair->channels * 4; i++) | ||
411 | regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0); | ||
412 | |||
413 | /* Enable overload interrupt */ | ||
414 | regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE); | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * Stop the assigned ASRC pair | ||
419 | */ | ||
420 | static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) | ||
421 | { | ||
422 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
423 | enum asrc_pair_index index = pair->index; | ||
424 | |||
425 | /* Stop the current pair */ | ||
426 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
427 | ASRCTR_ASRCEi_MASK(index), 0); | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * Get DMA channel according to the pair and direction. | ||
432 | */ | ||
433 | struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) | ||
434 | { | ||
435 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
436 | enum asrc_pair_index index = pair->index; | ||
437 | char name[4]; | ||
438 | |||
439 | sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); | ||
440 | |||
441 | return dma_request_slave_channel(&asrc_priv->pdev->dev, name); | ||
442 | } | ||
443 | EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel); | ||
444 | |||
445 | static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, | ||
446 | struct snd_pcm_hw_params *params, | ||
447 | struct snd_soc_dai *dai) | ||
448 | { | ||
449 | struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); | ||
450 | int width = snd_pcm_format_width(params_format(params)); | ||
451 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
452 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
453 | unsigned int channels = params_channels(params); | ||
454 | unsigned int rate = params_rate(params); | ||
455 | struct asrc_config config; | ||
456 | int word_width, ret; | ||
457 | |||
458 | ret = fsl_asrc_request_pair(channels, pair); | ||
459 | if (ret) { | ||
460 | dev_err(dai->dev, "fail to request asrc pair\n"); | ||
461 | return ret; | ||
462 | } | ||
463 | |||
464 | pair->config = &config; | ||
465 | |||
466 | if (width == 16) | ||
467 | width = ASRC_WIDTH_16_BIT; | ||
468 | else | ||
469 | width = ASRC_WIDTH_24_BIT; | ||
470 | |||
471 | if (asrc_priv->asrc_width == 16) | ||
472 | word_width = ASRC_WIDTH_16_BIT; | ||
473 | else | ||
474 | word_width = ASRC_WIDTH_24_BIT; | ||
475 | |||
476 | config.pair = pair->index; | ||
477 | config.channel_num = channels; | ||
478 | config.inclk = INCLK_NONE; | ||
479 | config.outclk = OUTCLK_ASRCK1_CLK; | ||
480 | |||
481 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
482 | config.input_word_width = width; | ||
483 | config.output_word_width = word_width; | ||
484 | config.input_sample_rate = rate; | ||
485 | config.output_sample_rate = asrc_priv->asrc_rate; | ||
486 | } else { | ||
487 | config.input_word_width = word_width; | ||
488 | config.output_word_width = width; | ||
489 | config.input_sample_rate = asrc_priv->asrc_rate; | ||
490 | config.output_sample_rate = rate; | ||
491 | } | ||
492 | |||
493 | ret = fsl_asrc_config_pair(pair); | ||
494 | if (ret) { | ||
495 | dev_err(dai->dev, "fail to config asrc pair\n"); | ||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, | ||
503 | struct snd_soc_dai *dai) | ||
504 | { | ||
505 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
506 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
507 | |||
508 | if (pair) | ||
509 | fsl_asrc_release_pair(pair); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
515 | struct snd_soc_dai *dai) | ||
516 | { | ||
517 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
518 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
519 | |||
520 | switch (cmd) { | ||
521 | case SNDRV_PCM_TRIGGER_START: | ||
522 | case SNDRV_PCM_TRIGGER_RESUME: | ||
523 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
524 | fsl_asrc_start_pair(pair); | ||
525 | break; | ||
526 | case SNDRV_PCM_TRIGGER_STOP: | ||
527 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
528 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
529 | fsl_asrc_stop_pair(pair); | ||
530 | break; | ||
531 | default: | ||
532 | return -EINVAL; | ||
533 | } | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static struct snd_soc_dai_ops fsl_asrc_dai_ops = { | ||
539 | .hw_params = fsl_asrc_dai_hw_params, | ||
540 | .hw_free = fsl_asrc_dai_hw_free, | ||
541 | .trigger = fsl_asrc_dai_trigger, | ||
542 | }; | ||
543 | |||
544 | static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) | ||
545 | { | ||
546 | struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); | ||
547 | |||
548 | snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx, | ||
549 | &asrc_priv->dma_params_rx); | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | #define FSL_ASRC_RATES SNDRV_PCM_RATE_8000_192000 | ||
555 | #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ | ||
556 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
557 | SNDRV_PCM_FMTBIT_S20_3LE) | ||
558 | |||
559 | static struct snd_soc_dai_driver fsl_asrc_dai = { | ||
560 | .probe = fsl_asrc_dai_probe, | ||
561 | .playback = { | ||
562 | .stream_name = "ASRC-Playback", | ||
563 | .channels_min = 1, | ||
564 | .channels_max = 10, | ||
565 | .rates = FSL_ASRC_RATES, | ||
566 | .formats = FSL_ASRC_FORMATS, | ||
567 | }, | ||
568 | .capture = { | ||
569 | .stream_name = "ASRC-Capture", | ||
570 | .channels_min = 1, | ||
571 | .channels_max = 10, | ||
572 | .rates = FSL_ASRC_RATES, | ||
573 | .formats = FSL_ASRC_FORMATS, | ||
574 | }, | ||
575 | .ops = &fsl_asrc_dai_ops, | ||
576 | }; | ||
577 | |||
578 | static const struct snd_soc_component_driver fsl_asrc_component = { | ||
579 | .name = "fsl-asrc-dai", | ||
580 | }; | ||
581 | |||
582 | static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) | ||
583 | { | ||
584 | switch (reg) { | ||
585 | case REG_ASRCTR: | ||
586 | case REG_ASRIER: | ||
587 | case REG_ASRCNCR: | ||
588 | case REG_ASRCFG: | ||
589 | case REG_ASRCSR: | ||
590 | case REG_ASRCDR1: | ||
591 | case REG_ASRCDR2: | ||
592 | case REG_ASRSTR: | ||
593 | case REG_ASRPM1: | ||
594 | case REG_ASRPM2: | ||
595 | case REG_ASRPM3: | ||
596 | case REG_ASRPM4: | ||
597 | case REG_ASRPM5: | ||
598 | case REG_ASRTFR1: | ||
599 | case REG_ASRCCR: | ||
600 | case REG_ASRDOA: | ||
601 | case REG_ASRDOB: | ||
602 | case REG_ASRDOC: | ||
603 | case REG_ASRIDRHA: | ||
604 | case REG_ASRIDRLA: | ||
605 | case REG_ASRIDRHB: | ||
606 | case REG_ASRIDRLB: | ||
607 | case REG_ASRIDRHC: | ||
608 | case REG_ASRIDRLC: | ||
609 | case REG_ASR76K: | ||
610 | case REG_ASR56K: | ||
611 | case REG_ASRMCRA: | ||
612 | case REG_ASRFSTA: | ||
613 | case REG_ASRMCRB: | ||
614 | case REG_ASRFSTB: | ||
615 | case REG_ASRMCRC: | ||
616 | case REG_ASRFSTC: | ||
617 | case REG_ASRMCR1A: | ||
618 | case REG_ASRMCR1B: | ||
619 | case REG_ASRMCR1C: | ||
620 | return true; | ||
621 | default: | ||
622 | return false; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | static bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) | ||
627 | { | ||
628 | switch (reg) { | ||
629 | case REG_ASRSTR: | ||
630 | case REG_ASRDIA: | ||
631 | case REG_ASRDIB: | ||
632 | case REG_ASRDIC: | ||
633 | case REG_ASRDOA: | ||
634 | case REG_ASRDOB: | ||
635 | case REG_ASRDOC: | ||
636 | case REG_ASRFSTA: | ||
637 | case REG_ASRFSTB: | ||
638 | case REG_ASRFSTC: | ||
639 | case REG_ASRCFG: | ||
640 | return true; | ||
641 | default: | ||
642 | return false; | ||
643 | } | ||
644 | } | ||
645 | |||
646 | static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) | ||
647 | { | ||
648 | switch (reg) { | ||
649 | case REG_ASRCTR: | ||
650 | case REG_ASRIER: | ||
651 | case REG_ASRCNCR: | ||
652 | case REG_ASRCFG: | ||
653 | case REG_ASRCSR: | ||
654 | case REG_ASRCDR1: | ||
655 | case REG_ASRCDR2: | ||
656 | case REG_ASRSTR: | ||
657 | case REG_ASRPM1: | ||
658 | case REG_ASRPM2: | ||
659 | case REG_ASRPM3: | ||
660 | case REG_ASRPM4: | ||
661 | case REG_ASRPM5: | ||
662 | case REG_ASRTFR1: | ||
663 | case REG_ASRCCR: | ||
664 | case REG_ASRDIA: | ||
665 | case REG_ASRDIB: | ||
666 | case REG_ASRDIC: | ||
667 | case REG_ASRIDRHA: | ||
668 | case REG_ASRIDRLA: | ||
669 | case REG_ASRIDRHB: | ||
670 | case REG_ASRIDRLB: | ||
671 | case REG_ASRIDRHC: | ||
672 | case REG_ASRIDRLC: | ||
673 | case REG_ASR76K: | ||
674 | case REG_ASR56K: | ||
675 | case REG_ASRMCRA: | ||
676 | case REG_ASRMCRB: | ||
677 | case REG_ASRMCRC: | ||
678 | case REG_ASRMCR1A: | ||
679 | case REG_ASRMCR1B: | ||
680 | case REG_ASRMCR1C: | ||
681 | return true; | ||
682 | default: | ||
683 | return false; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | static struct regmap_config fsl_asrc_regmap_config = { | ||
688 | .reg_bits = 32, | ||
689 | .reg_stride = 4, | ||
690 | .val_bits = 32, | ||
691 | |||
692 | .max_register = REG_ASRMCR1C, | ||
693 | .readable_reg = fsl_asrc_readable_reg, | ||
694 | .volatile_reg = fsl_asrc_volatile_reg, | ||
695 | .writeable_reg = fsl_asrc_writeable_reg, | ||
696 | .cache_type = REGCACHE_RBTREE, | ||
697 | }; | ||
698 | |||
699 | /** | ||
700 | * Initialize ASRC registers with a default configurations | ||
701 | */ | ||
702 | static int fsl_asrc_init(struct fsl_asrc *asrc_priv) | ||
703 | { | ||
704 | /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ | ||
705 | regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN); | ||
706 | |||
707 | /* Disable interrupt by default */ | ||
708 | regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0); | ||
709 | |||
710 | /* Apply recommended settings for parameters from Reference Manual */ | ||
711 | regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff); | ||
712 | regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555); | ||
713 | regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280); | ||
714 | regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280); | ||
715 | regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280); | ||
716 | |||
717 | /* Base address for task queue FIFO. Set to 0x7C */ | ||
718 | regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1, | ||
719 | ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); | ||
720 | |||
721 | /* Set the processing clock for 76KHz to 133M */ | ||
722 | regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6); | ||
723 | |||
724 | /* Set the processing clock for 56KHz to 133M */ | ||
725 | return regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947); | ||
726 | } | ||
727 | |||
728 | /** | ||
729 | * Interrupt handler for ASRC | ||
730 | */ | ||
731 | static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) | ||
732 | { | ||
733 | struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id; | ||
734 | struct device *dev = &asrc_priv->pdev->dev; | ||
735 | enum asrc_pair_index index; | ||
736 | u32 status; | ||
737 | |||
738 | regmap_read(asrc_priv->regmap, REG_ASRSTR, &status); | ||
739 | |||
740 | /* Clean overload error */ | ||
741 | regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE); | ||
742 | |||
743 | /* | ||
744 | * We here use dev_dbg() for all exceptions because ASRC itself does | ||
745 | * not care if FIFO overflowed or underrun while a warning in the | ||
746 | * interrupt would result a ridged conversion. | ||
747 | */ | ||
748 | for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { | ||
749 | if (!asrc_priv->pair[index]) | ||
750 | continue; | ||
751 | |||
752 | if (status & ASRSTR_ATQOL) { | ||
753 | asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; | ||
754 | dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); | ||
755 | } | ||
756 | |||
757 | if (status & ASRSTR_AOOL(index)) { | ||
758 | asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; | ||
759 | pair_dbg("Output Task Overload\n"); | ||
760 | } | ||
761 | |||
762 | if (status & ASRSTR_AIOL(index)) { | ||
763 | asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; | ||
764 | pair_dbg("Input Task Overload\n"); | ||
765 | } | ||
766 | |||
767 | if (status & ASRSTR_AODO(index)) { | ||
768 | asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; | ||
769 | pair_dbg("Output Data Buffer has overflowed\n"); | ||
770 | } | ||
771 | |||
772 | if (status & ASRSTR_AIDU(index)) { | ||
773 | asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; | ||
774 | pair_dbg("Input Data Buffer has underflowed\n"); | ||
775 | } | ||
776 | } | ||
777 | |||
778 | return IRQ_HANDLED; | ||
779 | } | ||
780 | |||
781 | static int fsl_asrc_probe(struct platform_device *pdev) | ||
782 | { | ||
783 | struct device_node *np = pdev->dev.of_node; | ||
784 | struct fsl_asrc *asrc_priv; | ||
785 | struct resource *res; | ||
786 | void __iomem *regs; | ||
787 | int irq, ret, i; | ||
788 | char tmp[16]; | ||
789 | |||
790 | asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); | ||
791 | if (!asrc_priv) | ||
792 | return -ENOMEM; | ||
793 | |||
794 | asrc_priv->pdev = pdev; | ||
795 | strcpy(asrc_priv->name, np->name); | ||
796 | |||
797 | /* Get the addresses and IRQ */ | ||
798 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
799 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
800 | if (IS_ERR(regs)) | ||
801 | return PTR_ERR(regs); | ||
802 | |||
803 | asrc_priv->paddr = res->start; | ||
804 | |||
805 | /* Register regmap and let it prepare core clock */ | ||
806 | if (of_property_read_bool(np, "big-endian")) | ||
807 | fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
808 | |||
809 | asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, | ||
810 | &fsl_asrc_regmap_config); | ||
811 | if (IS_ERR(asrc_priv->regmap)) { | ||
812 | dev_err(&pdev->dev, "failed to init regmap\n"); | ||
813 | return PTR_ERR(asrc_priv->regmap); | ||
814 | } | ||
815 | |||
816 | irq = platform_get_irq(pdev, 0); | ||
817 | if (irq < 0) { | ||
818 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | ||
819 | return irq; | ||
820 | } | ||
821 | |||
822 | ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, | ||
823 | asrc_priv->name, asrc_priv); | ||
824 | if (ret) { | ||
825 | dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); | ||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem"); | ||
830 | if (IS_ERR(asrc_priv->mem_clk)) { | ||
831 | dev_err(&pdev->dev, "failed to get mem clock\n"); | ||
832 | return PTR_ERR(asrc_priv->mem_clk); | ||
833 | } | ||
834 | |||
835 | asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); | ||
836 | if (IS_ERR(asrc_priv->ipg_clk)) { | ||
837 | dev_err(&pdev->dev, "failed to get ipg clock\n"); | ||
838 | return PTR_ERR(asrc_priv->ipg_clk); | ||
839 | } | ||
840 | |||
841 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { | ||
842 | sprintf(tmp, "asrck_%x", i); | ||
843 | asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); | ||
844 | if (IS_ERR(asrc_priv->asrck_clk[i])) { | ||
845 | dev_err(&pdev->dev, "failed to get %s clock\n", tmp); | ||
846 | return PTR_ERR(asrc_priv->asrck_clk[i]); | ||
847 | } | ||
848 | } | ||
849 | |||
850 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx35-asrc")) { | ||
851 | asrc_priv->channel_bits = 3; | ||
852 | clk_map[IN] = input_clk_map_imx35; | ||
853 | clk_map[OUT] = output_clk_map_imx35; | ||
854 | } else { | ||
855 | asrc_priv->channel_bits = 4; | ||
856 | clk_map[IN] = input_clk_map_imx53; | ||
857 | clk_map[OUT] = output_clk_map_imx53; | ||
858 | } | ||
859 | |||
860 | ret = fsl_asrc_init(asrc_priv); | ||
861 | if (ret) { | ||
862 | dev_err(&pdev->dev, "failed to init asrc %d\n", ret); | ||
863 | return -EINVAL; | ||
864 | } | ||
865 | |||
866 | asrc_priv->channel_avail = 10; | ||
867 | |||
868 | ret = of_property_read_u32(np, "fsl,asrc-rate", | ||
869 | &asrc_priv->asrc_rate); | ||
870 | if (ret) { | ||
871 | dev_err(&pdev->dev, "failed to get output rate\n"); | ||
872 | return -EINVAL; | ||
873 | } | ||
874 | |||
875 | ret = of_property_read_u32(np, "fsl,asrc-width", | ||
876 | &asrc_priv->asrc_width); | ||
877 | if (ret) { | ||
878 | dev_err(&pdev->dev, "failed to get output width\n"); | ||
879 | return -EINVAL; | ||
880 | } | ||
881 | |||
882 | if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) { | ||
883 | dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); | ||
884 | asrc_priv->asrc_width = 24; | ||
885 | } | ||
886 | |||
887 | platform_set_drvdata(pdev, asrc_priv); | ||
888 | pm_runtime_enable(&pdev->dev); | ||
889 | spin_lock_init(&asrc_priv->lock); | ||
890 | |||
891 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, | ||
892 | &fsl_asrc_dai, 1); | ||
893 | if (ret) { | ||
894 | dev_err(&pdev->dev, "failed to register ASoC DAI\n"); | ||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | ret = devm_snd_soc_register_platform(&pdev->dev, &fsl_asrc_platform); | ||
899 | if (ret) { | ||
900 | dev_err(&pdev->dev, "failed to register ASoC platform\n"); | ||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | dev_info(&pdev->dev, "driver registered\n"); | ||
905 | |||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | #ifdef CONFIG_PM_RUNTIME | ||
910 | static int fsl_asrc_runtime_resume(struct device *dev) | ||
911 | { | ||
912 | struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); | ||
913 | int i; | ||
914 | |||
915 | clk_prepare_enable(asrc_priv->mem_clk); | ||
916 | clk_prepare_enable(asrc_priv->ipg_clk); | ||
917 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) | ||
918 | clk_prepare_enable(asrc_priv->asrck_clk[i]); | ||
919 | |||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | static int fsl_asrc_runtime_suspend(struct device *dev) | ||
924 | { | ||
925 | struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); | ||
926 | int i; | ||
927 | |||
928 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) | ||
929 | clk_disable_unprepare(asrc_priv->asrck_clk[i]); | ||
930 | clk_disable_unprepare(asrc_priv->ipg_clk); | ||
931 | clk_disable_unprepare(asrc_priv->mem_clk); | ||
932 | |||
933 | return 0; | ||
934 | } | ||
935 | #endif /* CONFIG_PM_RUNTIME */ | ||
936 | |||
937 | #ifdef CONFIG_PM_SLEEP | ||
938 | static int fsl_asrc_suspend(struct device *dev) | ||
939 | { | ||
940 | struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); | ||
941 | |||
942 | regcache_cache_only(asrc_priv->regmap, true); | ||
943 | regcache_mark_dirty(asrc_priv->regmap); | ||
944 | |||
945 | return 0; | ||
946 | } | ||
947 | |||
948 | static int fsl_asrc_resume(struct device *dev) | ||
949 | { | ||
950 | struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); | ||
951 | u32 asrctr; | ||
952 | |||
953 | /* Stop all pairs provisionally */ | ||
954 | regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr); | ||
955 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
956 | ASRCTR_ASRCEi_ALL_MASK, 0); | ||
957 | |||
958 | /* Restore all registers */ | ||
959 | regcache_cache_only(asrc_priv->regmap, false); | ||
960 | regcache_sync(asrc_priv->regmap); | ||
961 | |||
962 | /* Restart enabled pairs */ | ||
963 | regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, | ||
964 | ASRCTR_ASRCEi_ALL_MASK, asrctr); | ||
965 | |||
966 | return 0; | ||
967 | } | ||
968 | #endif /* CONFIG_PM_SLEEP */ | ||
969 | |||
970 | static const struct dev_pm_ops fsl_asrc_pm = { | ||
971 | SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) | ||
972 | SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) | ||
973 | }; | ||
974 | |||
975 | static const struct of_device_id fsl_asrc_ids[] = { | ||
976 | { .compatible = "fsl,imx35-asrc", }, | ||
977 | { .compatible = "fsl,imx53-asrc", }, | ||
978 | {} | ||
979 | }; | ||
980 | MODULE_DEVICE_TABLE(of, fsl_asrc_ids); | ||
981 | |||
982 | static struct platform_driver fsl_asrc_driver = { | ||
983 | .probe = fsl_asrc_probe, | ||
984 | .driver = { | ||
985 | .name = "fsl-asrc", | ||
986 | .of_match_table = fsl_asrc_ids, | ||
987 | .pm = &fsl_asrc_pm, | ||
988 | }, | ||
989 | }; | ||
990 | module_platform_driver(fsl_asrc_driver); | ||
991 | |||
992 | MODULE_DESCRIPTION("Freescale ASRC ASoC driver"); | ||
993 | MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); | ||
994 | MODULE_ALIAS("platform:fsl-asrc"); | ||
995 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h new file mode 100644 index 000000000000..a3f211f53c23 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc.h | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * fsl_asrc.h - Freescale ASRC ALSA SoC header file | ||
3 | * | ||
4 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Nicolin Chen <nicoleotsuka@gmail.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #ifndef _FSL_ASRC_H | ||
14 | #define _FSL_ASRC_H | ||
15 | |||
16 | #define IN 0 | ||
17 | #define OUT 1 | ||
18 | |||
19 | #define ASRC_DMA_BUFFER_NUM 2 | ||
20 | #define ASRC_INPUTFIFO_THRESHOLD 32 | ||
21 | #define ASRC_OUTPUTFIFO_THRESHOLD 32 | ||
22 | #define ASRC_FIFO_THRESHOLD_MIN 0 | ||
23 | #define ASRC_FIFO_THRESHOLD_MAX 63 | ||
24 | #define ASRC_DMA_BUFFER_SIZE (1024 * 48 * 4) | ||
25 | #define ASRC_MAX_BUFFER_SIZE (1024 * 48) | ||
26 | #define ASRC_OUTPUT_LAST_SAMPLE 8 | ||
27 | |||
28 | #define IDEAL_RATIO_RATE 1000000 | ||
29 | |||
30 | #define REG_ASRCTR 0x00 | ||
31 | #define REG_ASRIER 0x04 | ||
32 | #define REG_ASRCNCR 0x0C | ||
33 | #define REG_ASRCFG 0x10 | ||
34 | #define REG_ASRCSR 0x14 | ||
35 | |||
36 | #define REG_ASRCDR1 0x18 | ||
37 | #define REG_ASRCDR2 0x1C | ||
38 | #define REG_ASRCDR(i) ((i < 2) ? REG_ASRCDR1 : REG_ASRCDR2) | ||
39 | |||
40 | #define REG_ASRSTR 0x20 | ||
41 | #define REG_ASRRA 0x24 | ||
42 | #define REG_ASRRB 0x28 | ||
43 | #define REG_ASRRC 0x2C | ||
44 | #define REG_ASRPM1 0x40 | ||
45 | #define REG_ASRPM2 0x44 | ||
46 | #define REG_ASRPM3 0x48 | ||
47 | #define REG_ASRPM4 0x4C | ||
48 | #define REG_ASRPM5 0x50 | ||
49 | #define REG_ASRTFR1 0x54 | ||
50 | #define REG_ASRCCR 0x5C | ||
51 | |||
52 | #define REG_ASRDIA 0x60 | ||
53 | #define REG_ASRDOA 0x64 | ||
54 | #define REG_ASRDIB 0x68 | ||
55 | #define REG_ASRDOB 0x6C | ||
56 | #define REG_ASRDIC 0x70 | ||
57 | #define REG_ASRDOC 0x74 | ||
58 | #define REG_ASRDI(i) (REG_ASRDIA + (i << 3)) | ||
59 | #define REG_ASRDO(i) (REG_ASRDOA + (i << 3)) | ||
60 | #define REG_ASRDx(x, i) (x == IN ? REG_ASRDI(i) : REG_ASRDO(i)) | ||
61 | |||
62 | #define REG_ASRIDRHA 0x80 | ||
63 | #define REG_ASRIDRLA 0x84 | ||
64 | #define REG_ASRIDRHB 0x88 | ||
65 | #define REG_ASRIDRLB 0x8C | ||
66 | #define REG_ASRIDRHC 0x90 | ||
67 | #define REG_ASRIDRLC 0x94 | ||
68 | #define REG_ASRIDRH(i) (REG_ASRIDRHA + (i << 3)) | ||
69 | #define REG_ASRIDRL(i) (REG_ASRIDRLA + (i << 3)) | ||
70 | |||
71 | #define REG_ASR76K 0x98 | ||
72 | #define REG_ASR56K 0x9C | ||
73 | |||
74 | #define REG_ASRMCRA 0xA0 | ||
75 | #define REG_ASRFSTA 0xA4 | ||
76 | #define REG_ASRMCRB 0xA8 | ||
77 | #define REG_ASRFSTB 0xAC | ||
78 | #define REG_ASRMCRC 0xB0 | ||
79 | #define REG_ASRFSTC 0xB4 | ||
80 | #define REG_ASRMCR(i) (REG_ASRMCRA + (i << 3)) | ||
81 | #define REG_ASRFST(i) (REG_ASRFSTA + (i << 3)) | ||
82 | |||
83 | #define REG_ASRMCR1A 0xC0 | ||
84 | #define REG_ASRMCR1B 0xC4 | ||
85 | #define REG_ASRMCR1C 0xC8 | ||
86 | #define REG_ASRMCR1(i) (REG_ASRMCR1A + (i << 2)) | ||
87 | |||
88 | |||
89 | /* REG0 0x00 REG_ASRCTR */ | ||
90 | #define ASRCTR_ATSi_SHIFT(i) (20 + i) | ||
91 | #define ASRCTR_ATSi_MASK(i) (1 << ASRCTR_ATSi_SHIFT(i)) | ||
92 | #define ASRCTR_ATS(i) (1 << ASRCTR_ATSi_SHIFT(i)) | ||
93 | #define ASRCTR_USRi_SHIFT(i) (14 + (i << 1)) | ||
94 | #define ASRCTR_USRi_MASK(i) (1 << ASRCTR_USRi_SHIFT(i)) | ||
95 | #define ASRCTR_USR(i) (1 << ASRCTR_USRi_SHIFT(i)) | ||
96 | #define ASRCTR_IDRi_SHIFT(i) (13 + (i << 1)) | ||
97 | #define ASRCTR_IDRi_MASK(i) (1 << ASRCTR_IDRi_SHIFT(i)) | ||
98 | #define ASRCTR_IDR(i) (1 << ASRCTR_IDRi_SHIFT(i)) | ||
99 | #define ASRCTR_SRST_SHIFT 4 | ||
100 | #define ASRCTR_SRST_MASK (1 << ASRCTR_SRST_SHIFT) | ||
101 | #define ASRCTR_SRST (1 << ASRCTR_SRST_SHIFT) | ||
102 | #define ASRCTR_ASRCEi_SHIFT(i) (1 + i) | ||
103 | #define ASRCTR_ASRCEi_MASK(i) (1 << ASRCTR_ASRCEi_SHIFT(i)) | ||
104 | #define ASRCTR_ASRCE(i) (1 << ASRCTR_ASRCEi_SHIFT(i)) | ||
105 | #define ASRCTR_ASRCEi_ALL_MASK (0x7 << ASRCTR_ASRCEi_SHIFT(0)) | ||
106 | #define ASRCTR_ASRCEN_SHIFT 0 | ||
107 | #define ASRCTR_ASRCEN_MASK (1 << ASRCTR_ASRCEN_SHIFT) | ||
108 | #define ASRCTR_ASRCEN (1 << ASRCTR_ASRCEN_SHIFT) | ||
109 | |||
110 | /* REG1 0x04 REG_ASRIER */ | ||
111 | #define ASRIER_AFPWE_SHIFT 7 | ||
112 | #define ASRIER_AFPWE_MASK (1 << ASRIER_AFPWE_SHIFT) | ||
113 | #define ASRIER_AFPWE (1 << ASRIER_AFPWE_SHIFT) | ||
114 | #define ASRIER_AOLIE_SHIFT 6 | ||
115 | #define ASRIER_AOLIE_MASK (1 << ASRIER_AOLIE_SHIFT) | ||
116 | #define ASRIER_AOLIE (1 << ASRIER_AOLIE_SHIFT) | ||
117 | #define ASRIER_ADOEi_SHIFT(i) (3 + i) | ||
118 | #define ASRIER_ADOEi_MASK(i) (1 << ASRIER_ADOEi_SHIFT(i)) | ||
119 | #define ASRIER_ADOE(i) (1 << ASRIER_ADOEi_SHIFT(i)) | ||
120 | #define ASRIER_ADIEi_SHIFT(i) (0 + i) | ||
121 | #define ASRIER_ADIEi_MASK(i) (1 << ASRIER_ADIEi_SHIFT(i)) | ||
122 | #define ASRIER_ADIE(i) (1 << ASRIER_ADIEi_SHIFT(i)) | ||
123 | |||
124 | /* REG2 0x0C REG_ASRCNCR */ | ||
125 | #define ASRCNCR_ANCi_SHIFT(i, b) (b * i) | ||
126 | #define ASRCNCR_ANCi_MASK(i, b) (((1 << b) - 1) << ASRCNCR_ANCi_SHIFT(i, b)) | ||
127 | #define ASRCNCR_ANCi(i, v, b) ((v << ASRCNCR_ANCi_SHIFT(i, b)) & ASRCNCR_ANCi_MASK(i, b)) | ||
128 | |||
129 | /* REG3 0x10 REG_ASRCFG */ | ||
130 | #define ASRCFG_INIRQi_SHIFT(i) (21 + i) | ||
131 | #define ASRCFG_INIRQi_MASK(i) (1 << ASRCFG_INIRQi_SHIFT(i)) | ||
132 | #define ASRCFG_INIRQi (1 << ASRCFG_INIRQi_SHIFT(i)) | ||
133 | #define ASRCFG_NDPRi_SHIFT(i) (18 + i) | ||
134 | #define ASRCFG_NDPRi_MASK(i) (1 << ASRCFG_NDPRi_SHIFT(i)) | ||
135 | #define ASRCFG_NDPRi (1 << ASRCFG_NDPRi_SHIFT(i)) | ||
136 | #define ASRCFG_POSTMODi_SHIFT(i) (8 + (i << 2)) | ||
137 | #define ASRCFG_POSTMODi_WIDTH 2 | ||
138 | #define ASRCFG_POSTMODi_MASK(i) (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i)) | ||
139 | #define ASRCFG_POSTMOD(i, v) ((v) << ASRCFG_POSTMODi_SHIFT(i)) | ||
140 | #define ASRCFG_POSTMODi_UP(i) (0 << ASRCFG_POSTMODi_SHIFT(i)) | ||
141 | #define ASRCFG_POSTMODi_DCON(i) (1 << ASRCFG_POSTMODi_SHIFT(i)) | ||
142 | #define ASRCFG_POSTMODi_DOWN(i) (2 << ASRCFG_POSTMODi_SHIFT(i)) | ||
143 | #define ASRCFG_PREMODi_SHIFT(i) (6 + (i << 2)) | ||
144 | #define ASRCFG_PREMODi_WIDTH 2 | ||
145 | #define ASRCFG_PREMODi_MASK(i) (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i)) | ||
146 | #define ASRCFG_PREMOD(i, v) ((v) << ASRCFG_PREMODi_SHIFT(i)) | ||
147 | #define ASRCFG_PREMODi_UP(i) (0 << ASRCFG_PREMODi_SHIFT(i)) | ||
148 | #define ASRCFG_PREMODi_DCON(i) (1 << ASRCFG_PREMODi_SHIFT(i)) | ||
149 | #define ASRCFG_PREMODi_DOWN(i) (2 << ASRCFG_PREMODi_SHIFT(i)) | ||
150 | #define ASRCFG_PREMODi_BYPASS(i) (3 << ASRCFG_PREMODi_SHIFT(i)) | ||
151 | |||
152 | /* REG4 0x14 REG_ASRCSR */ | ||
153 | #define ASRCSR_AxCSi_WIDTH 4 | ||
154 | #define ASRCSR_AxCSi_MASK ((1 << ASRCSR_AxCSi_WIDTH) - 1) | ||
155 | #define ASRCSR_AOCSi_SHIFT(i) (12 + (i << 2)) | ||
156 | #define ASRCSR_AOCSi_MASK(i) (((1 << ASRCSR_AxCSi_WIDTH) - 1) << ASRCSR_AOCSi_SHIFT(i)) | ||
157 | #define ASRCSR_AOCS(i, v) ((v) << ASRCSR_AOCSi_SHIFT(i)) | ||
158 | #define ASRCSR_AICSi_SHIFT(i) (i << 2) | ||
159 | #define ASRCSR_AICSi_MASK(i) (((1 << ASRCSR_AxCSi_WIDTH) - 1) << ASRCSR_AICSi_SHIFT(i)) | ||
160 | #define ASRCSR_AICS(i, v) ((v) << ASRCSR_AICSi_SHIFT(i)) | ||
161 | |||
162 | /* REG5&6 0x18 & 0x1C REG_ASRCDR1 & ASRCDR2 */ | ||
163 | #define ASRCDRi_AxCPi_WIDTH 3 | ||
164 | #define ASRCDRi_AICPi_SHIFT(i) (0 + (i % 2) * 6) | ||
165 | #define ASRCDRi_AICPi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AICPi_SHIFT(i)) | ||
166 | #define ASRCDRi_AICP(i, v) ((v) << ASRCDRi_AICPi_SHIFT(i)) | ||
167 | #define ASRCDRi_AICDi_SHIFT(i) (3 + (i % 2) * 6) | ||
168 | #define ASRCDRi_AICDi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AICDi_SHIFT(i)) | ||
169 | #define ASRCDRi_AICD(i, v) ((v) << ASRCDRi_AICDi_SHIFT(i)) | ||
170 | #define ASRCDRi_AOCPi_SHIFT(i) ((i < 2) ? 12 + i * 6 : 6) | ||
171 | #define ASRCDRi_AOCPi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AOCPi_SHIFT(i)) | ||
172 | #define ASRCDRi_AOCP(i, v) ((v) << ASRCDRi_AOCPi_SHIFT(i)) | ||
173 | #define ASRCDRi_AOCDi_SHIFT(i) ((i < 2) ? 15 + i * 6 : 9) | ||
174 | #define ASRCDRi_AOCDi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AOCDi_SHIFT(i)) | ||
175 | #define ASRCDRi_AOCD(i, v) ((v) << ASRCDRi_AOCDi_SHIFT(i)) | ||
176 | |||
177 | /* REG7 0x20 REG_ASRSTR */ | ||
178 | #define ASRSTR_DSLCNT_SHIFT 21 | ||
179 | #define ASRSTR_DSLCNT_MASK (1 << ASRSTR_DSLCNT_SHIFT) | ||
180 | #define ASRSTR_DSLCNT (1 << ASRSTR_DSLCNT_SHIFT) | ||
181 | #define ASRSTR_ATQOL_SHIFT 20 | ||
182 | #define ASRSTR_ATQOL_MASK (1 << ASRSTR_ATQOL_SHIFT) | ||
183 | #define ASRSTR_ATQOL (1 << ASRSTR_ATQOL_SHIFT) | ||
184 | #define ASRSTR_AOOLi_SHIFT(i) (17 + i) | ||
185 | #define ASRSTR_AOOLi_MASK(i) (1 << ASRSTR_AOOLi_SHIFT(i)) | ||
186 | #define ASRSTR_AOOL(i) (1 << ASRSTR_AOOLi_SHIFT(i)) | ||
187 | #define ASRSTR_AIOLi_SHIFT(i) (14 + i) | ||
188 | #define ASRSTR_AIOLi_MASK(i) (1 << ASRSTR_AIOLi_SHIFT(i)) | ||
189 | #define ASRSTR_AIOL(i) (1 << ASRSTR_AIOLi_SHIFT(i)) | ||
190 | #define ASRSTR_AODOi_SHIFT(i) (11 + i) | ||
191 | #define ASRSTR_AODOi_MASK(i) (1 << ASRSTR_AODOi_SHIFT(i)) | ||
192 | #define ASRSTR_AODO(i) (1 << ASRSTR_AODOi_SHIFT(i)) | ||
193 | #define ASRSTR_AIDUi_SHIFT(i) (8 + i) | ||
194 | #define ASRSTR_AIDUi_MASK(i) (1 << ASRSTR_AIDUi_SHIFT(i)) | ||
195 | #define ASRSTR_AIDU(i) (1 << ASRSTR_AIDUi_SHIFT(i)) | ||
196 | #define ASRSTR_FPWT_SHIFT 7 | ||
197 | #define ASRSTR_FPWT_MASK (1 << ASRSTR_FPWT_SHIFT) | ||
198 | #define ASRSTR_FPWT (1 << ASRSTR_FPWT_SHIFT) | ||
199 | #define ASRSTR_AOLE_SHIFT 6 | ||
200 | #define ASRSTR_AOLE_MASK (1 << ASRSTR_AOLE_SHIFT) | ||
201 | #define ASRSTR_AOLE (1 << ASRSTR_AOLE_SHIFT) | ||
202 | #define ASRSTR_AODEi_SHIFT(i) (3 + i) | ||
203 | #define ASRSTR_AODFi_MASK(i) (1 << ASRSTR_AODEi_SHIFT(i)) | ||
204 | #define ASRSTR_AODF(i) (1 << ASRSTR_AODEi_SHIFT(i)) | ||
205 | #define ASRSTR_AIDEi_SHIFT(i) (0 + i) | ||
206 | #define ASRSTR_AIDEi_MASK(i) (1 << ASRSTR_AIDEi_SHIFT(i)) | ||
207 | #define ASRSTR_AIDE(i) (1 << ASRSTR_AIDEi_SHIFT(i)) | ||
208 | |||
209 | /* REG10 0x54 REG_ASRTFR1 */ | ||
210 | #define ASRTFR1_TF_BASE_WIDTH 7 | ||
211 | #define ASRTFR1_TF_BASE_SHIFT 6 | ||
212 | #define ASRTFR1_TF_BASE_MASK (((1 << ASRTFR1_TF_BASE_WIDTH) - 1) << ASRTFR1_TF_BASE_SHIFT) | ||
213 | #define ASRTFR1_TF_BASE(i) ((i) << ASRTFR1_TF_BASE_SHIFT) | ||
214 | |||
215 | /* | ||
216 | * REG22 0xA0 REG_ASRMCRA | ||
217 | * REG24 0xA8 REG_ASRMCRB | ||
218 | * REG26 0xB0 REG_ASRMCRC | ||
219 | */ | ||
220 | #define ASRMCRi_ZEROBUFi_SHIFT 23 | ||
221 | #define ASRMCRi_ZEROBUFi_MASK (1 << ASRMCRi_ZEROBUFi_SHIFT) | ||
222 | #define ASRMCRi_ZEROBUFi (1 << ASRMCRi_ZEROBUFi_SHIFT) | ||
223 | #define ASRMCRi_EXTTHRSHi_SHIFT 22 | ||
224 | #define ASRMCRi_EXTTHRSHi_MASK (1 << ASRMCRi_EXTTHRSHi_SHIFT) | ||
225 | #define ASRMCRi_EXTTHRSHi (1 << ASRMCRi_EXTTHRSHi_SHIFT) | ||
226 | #define ASRMCRi_BUFSTALLi_SHIFT 21 | ||
227 | #define ASRMCRi_BUFSTALLi_MASK (1 << ASRMCRi_BUFSTALLi_SHIFT) | ||
228 | #define ASRMCRi_BUFSTALLi (1 << ASRMCRi_BUFSTALLi_SHIFT) | ||
229 | #define ASRMCRi_BYPASSPOLYi_SHIFT 20 | ||
230 | #define ASRMCRi_BYPASSPOLYi_MASK (1 << ASRMCRi_BYPASSPOLYi_SHIFT) | ||
231 | #define ASRMCRi_BYPASSPOLYi (1 << ASRMCRi_BYPASSPOLYi_SHIFT) | ||
232 | #define ASRMCRi_OUTFIFO_THRESHOLD_WIDTH 6 | ||
233 | #define ASRMCRi_OUTFIFO_THRESHOLD_SHIFT 12 | ||
234 | #define ASRMCRi_OUTFIFO_THRESHOLD_MASK (((1 << ASRMCRi_OUTFIFO_THRESHOLD_WIDTH) - 1) << ASRMCRi_OUTFIFO_THRESHOLD_SHIFT) | ||
235 | #define ASRMCRi_OUTFIFO_THRESHOLD(v) (((v) << ASRMCRi_OUTFIFO_THRESHOLD_SHIFT) & ASRMCRi_OUTFIFO_THRESHOLD_MASK) | ||
236 | #define ASRMCRi_RSYNIFi_SHIFT 11 | ||
237 | #define ASRMCRi_RSYNIFi_MASK (1 << ASRMCRi_RSYNIFi_SHIFT) | ||
238 | #define ASRMCRi_RSYNIFi (1 << ASRMCRi_RSYNIFi_SHIFT) | ||
239 | #define ASRMCRi_RSYNOFi_SHIFT 10 | ||
240 | #define ASRMCRi_RSYNOFi_MASK (1 << ASRMCRi_RSYNOFi_SHIFT) | ||
241 | #define ASRMCRi_RSYNOFi (1 << ASRMCRi_RSYNOFi_SHIFT) | ||
242 | #define ASRMCRi_INFIFO_THRESHOLD_WIDTH 6 | ||
243 | #define ASRMCRi_INFIFO_THRESHOLD_SHIFT 0 | ||
244 | #define ASRMCRi_INFIFO_THRESHOLD_MASK (((1 << ASRMCRi_INFIFO_THRESHOLD_WIDTH) - 1) << ASRMCRi_INFIFO_THRESHOLD_SHIFT) | ||
245 | #define ASRMCRi_INFIFO_THRESHOLD(v) (((v) << ASRMCRi_INFIFO_THRESHOLD_SHIFT) & ASRMCRi_INFIFO_THRESHOLD_MASK) | ||
246 | |||
247 | /* | ||
248 | * REG23 0xA4 REG_ASRFSTA | ||
249 | * REG25 0xAC REG_ASRFSTB | ||
250 | * REG27 0xB4 REG_ASRFSTC | ||
251 | */ | ||
252 | #define ASRFSTi_OAFi_SHIFT 23 | ||
253 | #define ASRFSTi_OAFi_MASK (1 << ASRFSTi_OAFi_SHIFT) | ||
254 | #define ASRFSTi_OAFi (1 << ASRFSTi_OAFi_SHIFT) | ||
255 | #define ASRFSTi_OUTPUT_FIFO_WIDTH 7 | ||
256 | #define ASRFSTi_OUTPUT_FIFO_SHIFT 12 | ||
257 | #define ASRFSTi_OUTPUT_FIFO_MASK (((1 << ASRFSTi_OUTPUT_FIFO_WIDTH) - 1) << ASRFSTi_OUTPUT_FIFO_SHIFT) | ||
258 | #define ASRFSTi_IAEi_SHIFT 11 | ||
259 | #define ASRFSTi_IAEi_MASK (1 << ASRFSTi_OAFi_SHIFT) | ||
260 | #define ASRFSTi_IAEi (1 << ASRFSTi_OAFi_SHIFT) | ||
261 | #define ASRFSTi_INPUT_FIFO_WIDTH 7 | ||
262 | #define ASRFSTi_INPUT_FIFO_SHIFT 0 | ||
263 | #define ASRFSTi_INPUT_FIFO_MASK ((1 << ASRFSTi_INPUT_FIFO_WIDTH) - 1) | ||
264 | |||
265 | /* REG28 0xC0 & 0xC4 & 0xC8 REG_ASRMCR1i */ | ||
266 | #define ASRMCR1i_IWD_WIDTH 3 | ||
267 | #define ASRMCR1i_IWD_SHIFT 9 | ||
268 | #define ASRMCR1i_IWD_MASK (((1 << ASRMCR1i_IWD_WIDTH) - 1) << ASRMCR1i_IWD_SHIFT) | ||
269 | #define ASRMCR1i_IWD(v) ((v) << ASRMCR1i_IWD_SHIFT) | ||
270 | #define ASRMCR1i_IMSB_SHIFT 8 | ||
271 | #define ASRMCR1i_IMSB_MASK (1 << ASRMCR1i_IMSB_SHIFT) | ||
272 | #define ASRMCR1i_IMSB_MSB (1 << ASRMCR1i_IMSB_SHIFT) | ||
273 | #define ASRMCR1i_IMSB_LSB (0 << ASRMCR1i_IMSB_SHIFT) | ||
274 | #define ASRMCR1i_OMSB_SHIFT 2 | ||
275 | #define ASRMCR1i_OMSB_MASK (1 << ASRMCR1i_OMSB_SHIFT) | ||
276 | #define ASRMCR1i_OMSB_MSB (1 << ASRMCR1i_OMSB_SHIFT) | ||
277 | #define ASRMCR1i_OMSB_LSB (0 << ASRMCR1i_OMSB_SHIFT) | ||
278 | #define ASRMCR1i_OSGN_SHIFT 1 | ||
279 | #define ASRMCR1i_OSGN_MASK (1 << ASRMCR1i_OSGN_SHIFT) | ||
280 | #define ASRMCR1i_OSGN (1 << ASRMCR1i_OSGN_SHIFT) | ||
281 | #define ASRMCR1i_OW16_SHIFT 0 | ||
282 | #define ASRMCR1i_OW16_MASK (1 << ASRMCR1i_OW16_SHIFT) | ||
283 | #define ASRMCR1i_OW16(v) ((v) << ASRMCR1i_OW16_SHIFT) | ||
284 | |||
285 | |||
286 | enum asrc_pair_index { | ||
287 | ASRC_INVALID_PAIR = -1, | ||
288 | ASRC_PAIR_A = 0, | ||
289 | ASRC_PAIR_B = 1, | ||
290 | ASRC_PAIR_C = 2, | ||
291 | }; | ||
292 | |||
293 | #define ASRC_PAIR_MAX_NUM (ASRC_PAIR_C + 1) | ||
294 | |||
295 | enum asrc_inclk { | ||
296 | INCLK_NONE = 0x03, | ||
297 | INCLK_ESAI_RX = 0x00, | ||
298 | INCLK_SSI1_RX = 0x01, | ||
299 | INCLK_SSI2_RX = 0x02, | ||
300 | INCLK_SSI3_RX = 0x07, | ||
301 | INCLK_SPDIF_RX = 0x04, | ||
302 | INCLK_MLB_CLK = 0x05, | ||
303 | INCLK_PAD = 0x06, | ||
304 | INCLK_ESAI_TX = 0x08, | ||
305 | INCLK_SSI1_TX = 0x09, | ||
306 | INCLK_SSI2_TX = 0x0a, | ||
307 | INCLK_SSI3_TX = 0x0b, | ||
308 | INCLK_SPDIF_TX = 0x0c, | ||
309 | INCLK_ASRCK1_CLK = 0x0f, | ||
310 | }; | ||
311 | |||
312 | enum asrc_outclk { | ||
313 | OUTCLK_NONE = 0x03, | ||
314 | OUTCLK_ESAI_TX = 0x00, | ||
315 | OUTCLK_SSI1_TX = 0x01, | ||
316 | OUTCLK_SSI2_TX = 0x02, | ||
317 | OUTCLK_SSI3_TX = 0x07, | ||
318 | OUTCLK_SPDIF_TX = 0x04, | ||
319 | OUTCLK_MLB_CLK = 0x05, | ||
320 | OUTCLK_PAD = 0x06, | ||
321 | OUTCLK_ESAI_RX = 0x08, | ||
322 | OUTCLK_SSI1_RX = 0x09, | ||
323 | OUTCLK_SSI2_RX = 0x0a, | ||
324 | OUTCLK_SSI3_RX = 0x0b, | ||
325 | OUTCLK_SPDIF_RX = 0x0c, | ||
326 | OUTCLK_ASRCK1_CLK = 0x0f, | ||
327 | }; | ||
328 | |||
329 | #define ASRC_CLK_MAX_NUM 16 | ||
330 | |||
331 | enum asrc_word_width { | ||
332 | ASRC_WIDTH_24_BIT = 0, | ||
333 | ASRC_WIDTH_16_BIT = 1, | ||
334 | ASRC_WIDTH_8_BIT = 2, | ||
335 | }; | ||
336 | |||
337 | struct asrc_config { | ||
338 | enum asrc_pair_index pair; | ||
339 | unsigned int channel_num; | ||
340 | unsigned int buffer_num; | ||
341 | unsigned int dma_buffer_size; | ||
342 | unsigned int input_sample_rate; | ||
343 | unsigned int output_sample_rate; | ||
344 | enum asrc_word_width input_word_width; | ||
345 | enum asrc_word_width output_word_width; | ||
346 | enum asrc_inclk inclk; | ||
347 | enum asrc_outclk outclk; | ||
348 | }; | ||
349 | |||
350 | struct asrc_req { | ||
351 | unsigned int chn_num; | ||
352 | enum asrc_pair_index index; | ||
353 | }; | ||
354 | |||
355 | struct asrc_querybuf { | ||
356 | unsigned int buffer_index; | ||
357 | unsigned int input_length; | ||
358 | unsigned int output_length; | ||
359 | unsigned long input_offset; | ||
360 | unsigned long output_offset; | ||
361 | }; | ||
362 | |||
363 | struct asrc_convert_buffer { | ||
364 | void *input_buffer_vaddr; | ||
365 | void *output_buffer_vaddr; | ||
366 | unsigned int input_buffer_length; | ||
367 | unsigned int output_buffer_length; | ||
368 | }; | ||
369 | |||
370 | struct asrc_status_flags { | ||
371 | enum asrc_pair_index index; | ||
372 | unsigned int overload_error; | ||
373 | }; | ||
374 | |||
375 | enum asrc_error_status { | ||
376 | ASRC_TASK_Q_OVERLOAD = 0x01, | ||
377 | ASRC_OUTPUT_TASK_OVERLOAD = 0x02, | ||
378 | ASRC_INPUT_TASK_OVERLOAD = 0x04, | ||
379 | ASRC_OUTPUT_BUFFER_OVERFLOW = 0x08, | ||
380 | ASRC_INPUT_BUFFER_UNDERRUN = 0x10, | ||
381 | }; | ||
382 | |||
383 | struct dma_block { | ||
384 | dma_addr_t dma_paddr; | ||
385 | void *dma_vaddr; | ||
386 | unsigned int length; | ||
387 | }; | ||
388 | |||
389 | /** | ||
390 | * fsl_asrc_pair: ASRC Pair private data | ||
391 | * | ||
392 | * @asrc_priv: pointer to its parent module | ||
393 | * @config: configuration profile | ||
394 | * @error: error record | ||
395 | * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C) | ||
396 | * @channels: occupied channel number | ||
397 | * @desc: input and output dma descriptors | ||
398 | * @dma_chan: inputer and output DMA channels | ||
399 | * @dma_data: private dma data | ||
400 | * @pos: hardware pointer position | ||
401 | * @private: pair private area | ||
402 | */ | ||
403 | struct fsl_asrc_pair { | ||
404 | struct fsl_asrc *asrc_priv; | ||
405 | struct asrc_config *config; | ||
406 | unsigned int error; | ||
407 | |||
408 | enum asrc_pair_index index; | ||
409 | unsigned int channels; | ||
410 | |||
411 | struct dma_async_tx_descriptor *desc[2]; | ||
412 | struct dma_chan *dma_chan[2]; | ||
413 | struct imx_dma_data dma_data; | ||
414 | unsigned int pos; | ||
415 | |||
416 | void *private; | ||
417 | }; | ||
418 | |||
419 | /** | ||
420 | * fsl_asrc_pair: ASRC private data | ||
421 | * | ||
422 | * @dma_params_rx: DMA parameters for receive channel | ||
423 | * @dma_params_tx: DMA parameters for transmit channel | ||
424 | * @pdev: platform device pointer | ||
425 | * @regmap: regmap handler | ||
426 | * @paddr: physical address to the base address of registers | ||
427 | * @mem_clk: clock source to access register | ||
428 | * @ipg_clk: clock source to drive peripheral | ||
429 | * @asrck_clk: clock sources to driver ASRC internal logic | ||
430 | * @lock: spin lock for resource protection | ||
431 | * @pair: pair pointers | ||
432 | * @channel_bits: width of ASRCNCR register for each pair | ||
433 | * @channel_avail: non-occupied channel numbers | ||
434 | * @asrc_rate: default sample rate for ASoC Back-Ends | ||
435 | * @asrc_width: default sample width for ASoC Back-Ends | ||
436 | * @name: driver name | ||
437 | */ | ||
438 | struct fsl_asrc { | ||
439 | struct snd_dmaengine_dai_dma_data dma_params_rx; | ||
440 | struct snd_dmaengine_dai_dma_data dma_params_tx; | ||
441 | struct platform_device *pdev; | ||
442 | struct regmap *regmap; | ||
443 | unsigned long paddr; | ||
444 | struct clk *mem_clk; | ||
445 | struct clk *ipg_clk; | ||
446 | struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; | ||
447 | spinlock_t lock; | ||
448 | |||
449 | struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM]; | ||
450 | unsigned int channel_bits; | ||
451 | unsigned int channel_avail; | ||
452 | |||
453 | int asrc_rate; | ||
454 | int asrc_width; | ||
455 | |||
456 | char name[32]; | ||
457 | }; | ||
458 | |||
459 | extern struct snd_soc_platform_driver fsl_asrc_platform; | ||
460 | struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir); | ||
461 | #endif /* _FSL_ASRC_H */ | ||
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c new file mode 100644 index 000000000000..ffc000bc1f15 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_dma.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* | ||
2 | * Freescale ASRC ALSA SoC Platform (DMA) driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Nicolin Chen <nicoleotsuka@gmail.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/dma-mapping.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_data/dma-imx.h> | ||
16 | #include <sound/dmaengine_pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | |||
19 | #include "fsl_asrc.h" | ||
20 | |||
21 | #define FSL_ASRC_DMABUF_SIZE (256 * 1024) | ||
22 | |||
23 | static struct snd_pcm_hardware snd_imx_hardware = { | ||
24 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
25 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
26 | SNDRV_PCM_INFO_MMAP | | ||
27 | SNDRV_PCM_INFO_MMAP_VALID | | ||
28 | SNDRV_PCM_INFO_PAUSE | | ||
29 | SNDRV_PCM_INFO_RESUME, | ||
30 | .buffer_bytes_max = FSL_ASRC_DMABUF_SIZE, | ||
31 | .period_bytes_min = 128, | ||
32 | .period_bytes_max = 65535, /* Limited by SDMA engine */ | ||
33 | .periods_min = 2, | ||
34 | .periods_max = 255, | ||
35 | .fifo_size = 0, | ||
36 | }; | ||
37 | |||
38 | static bool filter(struct dma_chan *chan, void *param) | ||
39 | { | ||
40 | if (!imx_dma_is_general_purpose(chan)) | ||
41 | return false; | ||
42 | |||
43 | chan->private = param; | ||
44 | |||
45 | return true; | ||
46 | } | ||
47 | |||
48 | static void fsl_asrc_dma_complete(void *arg) | ||
49 | { | ||
50 | struct snd_pcm_substream *substream = arg; | ||
51 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
52 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
53 | |||
54 | pair->pos += snd_pcm_lib_period_bytes(substream); | ||
55 | if (pair->pos >= snd_pcm_lib_buffer_bytes(substream)) | ||
56 | pair->pos = 0; | ||
57 | |||
58 | snd_pcm_period_elapsed(substream); | ||
59 | } | ||
60 | |||
61 | static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream) | ||
62 | { | ||
63 | u8 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUT : IN; | ||
64 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
65 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
66 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
67 | struct device *dev = rtd->platform->dev; | ||
68 | unsigned long flags = DMA_CTRL_ACK; | ||
69 | |||
70 | /* Prepare and submit Front-End DMA channel */ | ||
71 | if (!substream->runtime->no_period_wakeup) | ||
72 | flags |= DMA_PREP_INTERRUPT; | ||
73 | |||
74 | pair->pos = 0; | ||
75 | pair->desc[!dir] = dmaengine_prep_dma_cyclic( | ||
76 | pair->dma_chan[!dir], runtime->dma_addr, | ||
77 | snd_pcm_lib_buffer_bytes(substream), | ||
78 | snd_pcm_lib_period_bytes(substream), | ||
79 | dir == OUT ? DMA_TO_DEVICE : DMA_FROM_DEVICE, flags); | ||
80 | if (!pair->desc[!dir]) { | ||
81 | dev_err(dev, "failed to prepare slave DMA for Front-End\n"); | ||
82 | return -ENOMEM; | ||
83 | } | ||
84 | |||
85 | pair->desc[!dir]->callback = fsl_asrc_dma_complete; | ||
86 | pair->desc[!dir]->callback_param = substream; | ||
87 | |||
88 | dmaengine_submit(pair->desc[!dir]); | ||
89 | |||
90 | /* Prepare and submit Back-End DMA channel */ | ||
91 | pair->desc[dir] = dmaengine_prep_dma_cyclic( | ||
92 | pair->dma_chan[dir], 0xffff, 64, 64, DMA_DEV_TO_DEV, 0); | ||
93 | if (!pair->desc[dir]) { | ||
94 | dev_err(dev, "failed to prepare slave DMA for Back-End\n"); | ||
95 | return -ENOMEM; | ||
96 | } | ||
97 | |||
98 | dmaengine_submit(pair->desc[dir]); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd) | ||
104 | { | ||
105 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
106 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
107 | int ret; | ||
108 | |||
109 | switch (cmd) { | ||
110 | case SNDRV_PCM_TRIGGER_START: | ||
111 | case SNDRV_PCM_TRIGGER_RESUME: | ||
112 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
113 | ret = fsl_asrc_dma_prepare_and_submit(substream); | ||
114 | if (ret) | ||
115 | return ret; | ||
116 | dma_async_issue_pending(pair->dma_chan[IN]); | ||
117 | dma_async_issue_pending(pair->dma_chan[OUT]); | ||
118 | break; | ||
119 | case SNDRV_PCM_TRIGGER_STOP: | ||
120 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
121 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
122 | dmaengine_terminate_all(pair->dma_chan[OUT]); | ||
123 | dmaengine_terminate_all(pair->dma_chan[IN]); | ||
124 | break; | ||
125 | default: | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, | ||
133 | struct snd_pcm_hw_params *params) | ||
134 | { | ||
135 | enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
136 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
137 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
138 | struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; | ||
139 | struct snd_dmaengine_dai_dma_data *dma_params_be = NULL; | ||
140 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
141 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
142 | struct fsl_asrc *asrc_priv = pair->asrc_priv; | ||
143 | struct dma_slave_config config_fe, config_be; | ||
144 | enum asrc_pair_index index = pair->index; | ||
145 | struct device *dev = rtd->platform->dev; | ||
146 | int stream = substream->stream; | ||
147 | struct imx_dma_data *tmp_data; | ||
148 | struct snd_soc_dpcm *dpcm; | ||
149 | struct dma_chan *tmp_chan; | ||
150 | struct device *dev_be; | ||
151 | u8 dir = tx ? OUT : IN; | ||
152 | dma_cap_mask_t mask; | ||
153 | int ret; | ||
154 | |||
155 | /* Fetch the Back-End dma_data from DPCM */ | ||
156 | list_for_each_entry(dpcm, &rtd->dpcm[stream].be_clients, list_be) { | ||
157 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
158 | struct snd_pcm_substream *substream_be; | ||
159 | struct snd_soc_dai *dai = be->cpu_dai; | ||
160 | |||
161 | if (dpcm->fe != rtd) | ||
162 | continue; | ||
163 | |||
164 | substream_be = snd_soc_dpcm_get_substream(be, stream); | ||
165 | dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be); | ||
166 | dev_be = dai->dev; | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | if (!dma_params_be) { | ||
171 | dev_err(dev, "failed to get the substream of Back-End\n"); | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | /* Override dma_data of the Front-End and config its dmaengine */ | ||
176 | dma_params_fe = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
177 | dma_params_fe->addr = asrc_priv->paddr + REG_ASRDx(!dir, index); | ||
178 | dma_params_fe->maxburst = dma_params_be->maxburst; | ||
179 | |||
180 | pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir); | ||
181 | if (!pair->dma_chan[!dir]) { | ||
182 | dev_err(dev, "failed to request DMA channel\n"); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | memset(&config_fe, 0, sizeof(config_fe)); | ||
187 | ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &config_fe); | ||
188 | if (ret) { | ||
189 | dev_err(dev, "failed to prepare DMA config for Front-End\n"); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | ret = dmaengine_slave_config(pair->dma_chan[!dir], &config_fe); | ||
194 | if (ret) { | ||
195 | dev_err(dev, "failed to config DMA channel for Front-End\n"); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /* Request and config DMA channel for Back-End */ | ||
200 | dma_cap_zero(mask); | ||
201 | dma_cap_set(DMA_SLAVE, mask); | ||
202 | dma_cap_set(DMA_CYCLIC, mask); | ||
203 | |||
204 | /* Get DMA request of Back-End */ | ||
205 | tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); | ||
206 | tmp_data = tmp_chan->private; | ||
207 | pair->dma_data.dma_request = tmp_data->dma_request; | ||
208 | dma_release_channel(tmp_chan); | ||
209 | |||
210 | /* Get DMA request of Front-End */ | ||
211 | tmp_chan = fsl_asrc_get_dma_channel(pair, dir); | ||
212 | tmp_data = tmp_chan->private; | ||
213 | pair->dma_data.dma_request2 = tmp_data->dma_request; | ||
214 | pair->dma_data.peripheral_type = tmp_data->peripheral_type; | ||
215 | pair->dma_data.priority = tmp_data->priority; | ||
216 | dma_release_channel(tmp_chan); | ||
217 | |||
218 | pair->dma_chan[dir] = dma_request_channel(mask, filter, &pair->dma_data); | ||
219 | if (!pair->dma_chan[dir]) { | ||
220 | dev_err(dev, "failed to request DMA channel for Back-End\n"); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | if (asrc_priv->asrc_width == 16) | ||
225 | buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
226 | else | ||
227 | buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
228 | |||
229 | config_be.direction = DMA_DEV_TO_DEV; | ||
230 | config_be.src_addr_width = buswidth; | ||
231 | config_be.src_maxburst = dma_params_be->maxburst; | ||
232 | config_be.dst_addr_width = buswidth; | ||
233 | config_be.dst_maxburst = dma_params_be->maxburst; | ||
234 | |||
235 | if (tx) { | ||
236 | config_be.src_addr = asrc_priv->paddr + REG_ASRDO(index); | ||
237 | config_be.dst_addr = dma_params_be->addr; | ||
238 | } else { | ||
239 | config_be.dst_addr = asrc_priv->paddr + REG_ASRDI(index); | ||
240 | config_be.src_addr = dma_params_be->addr; | ||
241 | } | ||
242 | |||
243 | ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be); | ||
244 | if (ret) { | ||
245 | dev_err(dev, "failed to config DMA channel for Back-End\n"); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream) | ||
255 | { | ||
256 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
257 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
258 | |||
259 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
260 | |||
261 | if (pair->dma_chan[IN]) | ||
262 | dma_release_channel(pair->dma_chan[IN]); | ||
263 | |||
264 | if (pair->dma_chan[OUT]) | ||
265 | dma_release_channel(pair->dma_chan[OUT]); | ||
266 | |||
267 | pair->dma_chan[IN] = NULL; | ||
268 | pair->dma_chan[OUT] = NULL; | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) | ||
274 | { | ||
275 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
276 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
277 | struct device *dev = rtd->platform->dev; | ||
278 | struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); | ||
279 | struct fsl_asrc_pair *pair; | ||
280 | |||
281 | pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL); | ||
282 | if (!pair) { | ||
283 | dev_err(dev, "failed to allocate pair\n"); | ||
284 | return -ENOMEM; | ||
285 | } | ||
286 | |||
287 | pair->asrc_priv = asrc_priv; | ||
288 | |||
289 | runtime->private_data = pair; | ||
290 | |||
291 | snd_pcm_hw_constraint_integer(substream->runtime, | ||
292 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
293 | snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream) | ||
299 | { | ||
300 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
301 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
302 | struct fsl_asrc *asrc_priv; | ||
303 | |||
304 | if (!pair) | ||
305 | return 0; | ||
306 | |||
307 | asrc_priv = pair->asrc_priv; | ||
308 | |||
309 | if (asrc_priv->pair[pair->index] == pair) | ||
310 | asrc_priv->pair[pair->index] = NULL; | ||
311 | |||
312 | kfree(pair); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *substream) | ||
318 | { | ||
319 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
320 | struct fsl_asrc_pair *pair = runtime->private_data; | ||
321 | |||
322 | return bytes_to_frames(substream->runtime, pair->pos); | ||
323 | } | ||
324 | |||
325 | static struct snd_pcm_ops fsl_asrc_dma_pcm_ops = { | ||
326 | .ioctl = snd_pcm_lib_ioctl, | ||
327 | .hw_params = fsl_asrc_dma_hw_params, | ||
328 | .hw_free = fsl_asrc_dma_hw_free, | ||
329 | .trigger = fsl_asrc_dma_trigger, | ||
330 | .open = fsl_asrc_dma_startup, | ||
331 | .close = fsl_asrc_dma_shutdown, | ||
332 | .pointer = fsl_asrc_dma_pcm_pointer, | ||
333 | }; | ||
334 | |||
335 | static int fsl_asrc_dma_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
336 | { | ||
337 | struct snd_card *card = rtd->card->snd_card; | ||
338 | struct snd_pcm_substream *substream; | ||
339 | struct snd_pcm *pcm = rtd->pcm; | ||
340 | int ret, i; | ||
341 | |||
342 | ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); | ||
343 | if (ret) { | ||
344 | dev_err(card->dev, "failed to set DMA mask\n"); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_LAST; i++) { | ||
349 | substream = pcm->streams[i].substream; | ||
350 | if (!substream) | ||
351 | continue; | ||
352 | |||
353 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, | ||
354 | FSL_ASRC_DMABUF_SIZE, &substream->dma_buffer); | ||
355 | if (ret) { | ||
356 | dev_err(card->dev, "failed to allocate DMA buffer\n"); | ||
357 | goto err; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | return 0; | ||
362 | |||
363 | err: | ||
364 | if (--i == 0 && pcm->streams[i].substream) | ||
365 | snd_dma_free_pages(&pcm->streams[i].substream->dma_buffer); | ||
366 | |||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm) | ||
371 | { | ||
372 | struct snd_pcm_substream *substream; | ||
373 | int i; | ||
374 | |||
375 | for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_LAST; i++) { | ||
376 | substream = pcm->streams[i].substream; | ||
377 | if (!substream) | ||
378 | continue; | ||
379 | |||
380 | snd_dma_free_pages(&substream->dma_buffer); | ||
381 | substream->dma_buffer.area = NULL; | ||
382 | substream->dma_buffer.addr = 0; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | struct snd_soc_platform_driver fsl_asrc_platform = { | ||
387 | .ops = &fsl_asrc_dma_pcm_ops, | ||
388 | .pcm_new = fsl_asrc_dma_pcm_new, | ||
389 | .pcm_free = fsl_asrc_dma_pcm_free, | ||
390 | }; | ||
391 | EXPORT_SYMBOL_GPL(fsl_asrc_platform); | ||
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 6bb0ea59284f..a609aafc994d 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -923,8 +923,8 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) | |||
923 | dma->dai.pcm_free = fsl_dma_free_dma_buffers; | 923 | dma->dai.pcm_free = fsl_dma_free_dma_buffers; |
924 | 924 | ||
925 | /* Store the SSI-specific information that we need */ | 925 | /* Store the SSI-specific information that we need */ |
926 | dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0); | 926 | dma->ssi_stx_phys = res.start + CCSR_SSI_STX0; |
927 | dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0); | 927 | dma->ssi_srx_phys = res.start + CCSR_SSI_SRX0; |
928 | 928 | ||
929 | iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); | 929 | iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); |
930 | if (iprop) | 930 | if (iprop) |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index d719caf26dc2..72d154e7dd03 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
@@ -624,12 +624,14 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai) | |||
624 | static struct snd_soc_dai_driver fsl_esai_dai = { | 624 | static struct snd_soc_dai_driver fsl_esai_dai = { |
625 | .probe = fsl_esai_dai_probe, | 625 | .probe = fsl_esai_dai_probe, |
626 | .playback = { | 626 | .playback = { |
627 | .stream_name = "CPU-Playback", | ||
627 | .channels_min = 1, | 628 | .channels_min = 1, |
628 | .channels_max = 12, | 629 | .channels_max = 12, |
629 | .rates = FSL_ESAI_RATES, | 630 | .rates = FSL_ESAI_RATES, |
630 | .formats = FSL_ESAI_FORMATS, | 631 | .formats = FSL_ESAI_FORMATS, |
631 | }, | 632 | }, |
632 | .capture = { | 633 | .capture = { |
634 | .stream_name = "CPU-Capture", | ||
633 | .channels_min = 1, | 635 | .channels_min = 1, |
634 | .channels_max = 8, | 636 | .channels_max = 8, |
635 | .rates = FSL_ESAI_RATES, | 637 | .rates = FSL_ESAI_RATES, |
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index c5a0e8af8226..faa049797897 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
@@ -106,7 +106,7 @@ irq_rx: | |||
106 | xcsr &= ~FSL_SAI_CSR_xF_MASK; | 106 | xcsr &= ~FSL_SAI_CSR_xF_MASK; |
107 | 107 | ||
108 | if (flags) | 108 | if (flags) |
109 | regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr); | 109 | regmap_write(sai->regmap, FSL_SAI_RCSR, flags | xcsr); |
110 | 110 | ||
111 | out: | 111 | out: |
112 | if (irq_none) | 112 | if (irq_none) |
@@ -327,7 +327,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
327 | { | 327 | { |
328 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 328 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
329 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 329 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
330 | u32 tcsr, rcsr; | 330 | u32 xcsr, count = 100; |
331 | 331 | ||
332 | /* | 332 | /* |
333 | * The transmitter bit clock and frame sync are to be | 333 | * The transmitter bit clock and frame sync are to be |
@@ -338,9 +338,6 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
338 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, | 338 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, |
339 | FSL_SAI_CR2_SYNC); | 339 | FSL_SAI_CR2_SYNC); |
340 | 340 | ||
341 | regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); | ||
342 | regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); | ||
343 | |||
344 | /* | 341 | /* |
345 | * It is recommended that the transmitter is the last enabled | 342 | * It is recommended that the transmitter is the last enabled |
346 | * and the first disabled. | 343 | * and the first disabled. |
@@ -349,17 +346,16 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
349 | case SNDRV_PCM_TRIGGER_START: | 346 | case SNDRV_PCM_TRIGGER_START: |
350 | case SNDRV_PCM_TRIGGER_RESUME: | 347 | case SNDRV_PCM_TRIGGER_RESUME: |
351 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 348 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
352 | if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) { | 349 | regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), |
353 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, | 350 | FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); |
354 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); | 351 | |
355 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, | 352 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, |
356 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); | 353 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); |
357 | } | 354 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, |
355 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); | ||
358 | 356 | ||
359 | regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), | 357 | regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), |
360 | FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); | 358 | FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); |
361 | regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), | ||
362 | FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); | ||
363 | break; | 359 | break; |
364 | case SNDRV_PCM_TRIGGER_STOP: | 360 | case SNDRV_PCM_TRIGGER_STOP: |
365 | case SNDRV_PCM_TRIGGER_SUSPEND: | 361 | case SNDRV_PCM_TRIGGER_SUSPEND: |
@@ -370,11 +366,24 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
370 | FSL_SAI_CSR_xIE_MASK, 0); | 366 | FSL_SAI_CSR_xIE_MASK, 0); |
371 | 367 | ||
372 | /* Check if the opposite FRDE is also disabled */ | 368 | /* Check if the opposite FRDE is also disabled */ |
373 | if (!(tx ? rcsr & FSL_SAI_CSR_FRDE : tcsr & FSL_SAI_CSR_FRDE)) { | 369 | regmap_read(sai->regmap, FSL_SAI_xCSR(!tx), &xcsr); |
370 | if (!(xcsr & FSL_SAI_CSR_FRDE)) { | ||
371 | /* Disable both directions and reset their FIFOs */ | ||
374 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, | 372 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, |
375 | FSL_SAI_CSR_TERE, 0); | 373 | FSL_SAI_CSR_TERE, 0); |
376 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, | 374 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, |
377 | FSL_SAI_CSR_TERE, 0); | 375 | FSL_SAI_CSR_TERE, 0); |
376 | |||
377 | /* TERE will remain set till the end of current frame */ | ||
378 | do { | ||
379 | udelay(10); | ||
380 | regmap_read(sai->regmap, FSL_SAI_xCSR(tx), &xcsr); | ||
381 | } while (--count && xcsr & FSL_SAI_CSR_TERE); | ||
382 | |||
383 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, | ||
384 | FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); | ||
385 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, | ||
386 | FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); | ||
378 | } | 387 | } |
379 | break; | 388 | break; |
380 | default: | 389 | default: |
@@ -446,12 +455,14 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) | |||
446 | static struct snd_soc_dai_driver fsl_sai_dai = { | 455 | static struct snd_soc_dai_driver fsl_sai_dai = { |
447 | .probe = fsl_sai_dai_probe, | 456 | .probe = fsl_sai_dai_probe, |
448 | .playback = { | 457 | .playback = { |
458 | .stream_name = "CPU-Playback", | ||
449 | .channels_min = 1, | 459 | .channels_min = 1, |
450 | .channels_max = 2, | 460 | .channels_max = 2, |
451 | .rates = SNDRV_PCM_RATE_8000_96000, | 461 | .rates = SNDRV_PCM_RATE_8000_96000, |
452 | .formats = FSL_SAI_FORMATS, | 462 | .formats = FSL_SAI_FORMATS, |
453 | }, | 463 | }, |
454 | .capture = { | 464 | .capture = { |
465 | .stream_name = "CPU-Capture", | ||
455 | .channels_min = 1, | 466 | .channels_min = 1, |
456 | .channels_max = 2, | 467 | .channels_max = 2, |
457 | .rates = SNDRV_PCM_RATE_8000_96000, | 468 | .rates = SNDRV_PCM_RATE_8000_96000, |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index b912d45a2a4c..70acfe4a9bd5 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -32,10 +32,13 @@ | |||
32 | #define FSL_SPDIF_TXFIFO_WML 0x8 | 32 | #define FSL_SPDIF_TXFIFO_WML 0x8 |
33 | #define FSL_SPDIF_RXFIFO_WML 0x8 | 33 | #define FSL_SPDIF_RXFIFO_WML 0x8 |
34 | 34 | ||
35 | #define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC) | 35 | #define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC) |
36 | #define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL | INT_URX_OV|\ | 36 | #define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL |\ |
37 | INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\ | 37 | INT_URX_OV | INT_QRX_FUL | INT_QRX_OV |\ |
38 | INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED) | 38 | INT_UQ_SYNC | INT_UQ_ERR | INT_RXFIFO_RESYNC |\ |
39 | INT_LOSS_LOCK | INT_DPLL_LOCKED) | ||
40 | |||
41 | #define SIE_INTR_FOR(tx) (tx ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE) | ||
39 | 42 | ||
40 | /* Index list for the values that has if (DPLL Locked) condition */ | 43 | /* Index list for the values that has if (DPLL Locked) condition */ |
41 | static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; | 44 | static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; |
@@ -96,7 +99,7 @@ struct fsl_spdif_priv { | |||
96 | struct platform_device *pdev; | 99 | struct platform_device *pdev; |
97 | struct regmap *regmap; | 100 | struct regmap *regmap; |
98 | bool dpll_locked; | 101 | bool dpll_locked; |
99 | u16 txrate[SPDIF_TXRATE_MAX]; | 102 | u32 txrate[SPDIF_TXRATE_MAX]; |
100 | u8 txclk_df[SPDIF_TXRATE_MAX]; | 103 | u8 txclk_df[SPDIF_TXRATE_MAX]; |
101 | u8 sysclk_df[SPDIF_TXRATE_MAX]; | 104 | u8 sysclk_df[SPDIF_TXRATE_MAX]; |
102 | u8 txclk_src[SPDIF_TXRATE_MAX]; | 105 | u8 txclk_src[SPDIF_TXRATE_MAX]; |
@@ -137,10 +140,9 @@ static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv) | |||
137 | 140 | ||
138 | dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n"); | 141 | dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n"); |
139 | 142 | ||
140 | if (!spdif_priv->dpll_locked) { | 143 | /* Clear illegal symbol if DPLL unlocked since no audio stream */ |
141 | /* DPLL unlocked seems no audio stream */ | 144 | if (!spdif_priv->dpll_locked) |
142 | regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0); | 145 | regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0); |
143 | } | ||
144 | } | 146 | } |
145 | 147 | ||
146 | /* U/Q Channel receive register full */ | 148 | /* U/Q Channel receive register full */ |
@@ -335,8 +337,8 @@ static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv) | |||
335 | u32 ch_status; | 337 | u32 ch_status; |
336 | 338 | ||
337 | ch_status = (bitrev8(ctrl->ch_status[0]) << 16) | | 339 | ch_status = (bitrev8(ctrl->ch_status[0]) << 16) | |
338 | (bitrev8(ctrl->ch_status[1]) << 8) | | 340 | (bitrev8(ctrl->ch_status[1]) << 8) | |
339 | bitrev8(ctrl->ch_status[2]); | 341 | bitrev8(ctrl->ch_status[2]); |
340 | regmap_write(regmap, REG_SPDIF_STCSCH, ch_status); | 342 | regmap_write(regmap, REG_SPDIF_STCSCH, ch_status); |
341 | 343 | ||
342 | dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status); | 344 | dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status); |
@@ -390,6 +392,14 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, | |||
390 | rate = SPDIF_TXRATE_48000; | 392 | rate = SPDIF_TXRATE_48000; |
391 | csfs = IEC958_AES3_CON_FS_48000; | 393 | csfs = IEC958_AES3_CON_FS_48000; |
392 | break; | 394 | break; |
395 | case 96000: | ||
396 | rate = SPDIF_TXRATE_96000; | ||
397 | csfs = IEC958_AES3_CON_FS_96000; | ||
398 | break; | ||
399 | case 192000: | ||
400 | rate = SPDIF_TXRATE_192000; | ||
401 | csfs = IEC958_AES3_CON_FS_192000; | ||
402 | break; | ||
393 | default: | 403 | default: |
394 | dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate); | 404 | dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate); |
395 | return -EINVAL; | 405 | return -EINVAL; |
@@ -433,13 +443,12 @@ clk_set_bypass: | |||
433 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); | 443 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); |
434 | 444 | ||
435 | /* select clock source and divisor */ | 445 | /* select clock source and divisor */ |
436 | stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DF(txclk_df); | 446 | stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | |
437 | mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DF_MASK; | 447 | STC_TXCLK_DF(txclk_df) | STC_SYSCLK_DF(sysclk_df); |
448 | mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | | ||
449 | STC_TXCLK_DF_MASK | STC_SYSCLK_DF_MASK; | ||
438 | regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); | 450 | regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); |
439 | 451 | ||
440 | regmap_update_bits(regmap, REG_SPDIF_STC, | ||
441 | STC_SYSCLK_DF_MASK, STC_SYSCLK_DF(sysclk_df)); | ||
442 | |||
443 | dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n", | 452 | dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n", |
444 | spdif_priv->txrate[rate], sample_rate); | 453 | spdif_priv->txrate[rate], sample_rate); |
445 | 454 | ||
@@ -553,7 +562,7 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, | |||
553 | return ret; | 562 | return ret; |
554 | } | 563 | } |
555 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK, | 564 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK, |
556 | IEC958_AES3_CON_CLOCK_1000PPM); | 565 | IEC958_AES3_CON_CLOCK_1000PPM); |
557 | spdif_write_channel_status(spdif_priv); | 566 | spdif_write_channel_status(spdif_priv); |
558 | } else { | 567 | } else { |
559 | /* Setup rx clock source */ | 568 | /* Setup rx clock source */ |
@@ -569,9 +578,9 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream, | |||
569 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 578 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
570 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | 579 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
571 | struct regmap *regmap = spdif_priv->regmap; | 580 | struct regmap *regmap = spdif_priv->regmap; |
572 | int is_playack = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | 581 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
573 | u32 intr = is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE; | 582 | u32 intr = SIE_INTR_FOR(tx); |
574 | u32 dmaen = is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;; | 583 | u32 dmaen = SCR_DMA_xX_EN(tx); |
575 | 584 | ||
576 | switch (cmd) { | 585 | switch (cmd) { |
577 | case SNDRV_PCM_TRIGGER_START: | 586 | case SNDRV_PCM_TRIGGER_START: |
@@ -662,9 +671,8 @@ static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol, | |||
662 | u32 cstatus, val; | 671 | u32 cstatus, val; |
663 | 672 | ||
664 | regmap_read(regmap, REG_SPDIF_SIS, &val); | 673 | regmap_read(regmap, REG_SPDIF_SIS, &val); |
665 | if (!(val & INT_CNEW)) { | 674 | if (!(val & INT_CNEW)) |
666 | return -EAGAIN; | 675 | return -EAGAIN; |
667 | } | ||
668 | 676 | ||
669 | regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); | 677 | regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); |
670 | ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; | 678 | ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; |
@@ -693,15 +701,14 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, | |||
693 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | 701 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
694 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | 702 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; |
695 | unsigned long flags; | 703 | unsigned long flags; |
696 | int ret = 0; | 704 | int ret = -EAGAIN; |
697 | 705 | ||
698 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | 706 | spin_lock_irqsave(&ctrl->ctl_lock, flags); |
699 | if (ctrl->ready_buf) { | 707 | if (ctrl->ready_buf) { |
700 | int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; | 708 | int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; |
701 | memcpy(&ucontrol->value.iec958.subcode[0], | 709 | memcpy(&ucontrol->value.iec958.subcode[0], |
702 | &ctrl->subcode[idx], SPDIF_UBITS_SIZE); | 710 | &ctrl->subcode[idx], SPDIF_UBITS_SIZE); |
703 | } else { | 711 | ret = 0; |
704 | ret = -EAGAIN; | ||
705 | } | 712 | } |
706 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | 713 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); |
707 | 714 | ||
@@ -726,15 +733,14 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, | |||
726 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | 733 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
727 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | 734 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; |
728 | unsigned long flags; | 735 | unsigned long flags; |
729 | int ret = 0; | 736 | int ret = -EAGAIN; |
730 | 737 | ||
731 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | 738 | spin_lock_irqsave(&ctrl->ctl_lock, flags); |
732 | if (ctrl->ready_buf) { | 739 | if (ctrl->ready_buf) { |
733 | int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; | 740 | int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; |
734 | memcpy(&ucontrol->value.bytes.data[0], | 741 | memcpy(&ucontrol->value.bytes.data[0], |
735 | &ctrl->qsub[idx], SPDIF_QSUB_SIZE); | 742 | &ctrl->qsub[idx], SPDIF_QSUB_SIZE); |
736 | } else { | 743 | ret = 0; |
737 | ret = -EAGAIN; | ||
738 | } | 744 | } |
739 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | 745 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); |
740 | 746 | ||
@@ -762,7 +768,7 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, | |||
762 | struct regmap *regmap = spdif_priv->regmap; | 768 | struct regmap *regmap = spdif_priv->regmap; |
763 | u32 val; | 769 | u32 val; |
764 | 770 | ||
765 | val = regmap_read(regmap, REG_SPDIF_SIS, &val); | 771 | regmap_read(regmap, REG_SPDIF_SIS, &val); |
766 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; | 772 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; |
767 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); | 773 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); |
768 | 774 | ||
@@ -799,10 +805,10 @@ static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, | |||
799 | regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); | 805 | regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); |
800 | 806 | ||
801 | clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; | 807 | clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; |
802 | if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) { | 808 | |
803 | /* Get bus clock from system */ | 809 | /* Get bus clock from system */ |
810 | if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) | ||
804 | busclk_freq = clk_get_rate(spdif_priv->sysclk); | 811 | busclk_freq = clk_get_rate(spdif_priv->sysclk); |
805 | } | ||
806 | 812 | ||
807 | /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ | 813 | /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ |
808 | tmpval64 = (u64) busclk_freq * freqmeas; | 814 | tmpval64 = (u64) busclk_freq * freqmeas; |
@@ -826,12 +832,12 @@ static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, | |||
826 | { | 832 | { |
827 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | 833 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
828 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | 834 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
829 | int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); | 835 | int rate = 0; |
830 | 836 | ||
831 | if (spdif_priv->dpll_locked) | 837 | if (spdif_priv->dpll_locked) |
832 | ucontrol->value.integer.value[0] = rate; | 838 | rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); |
833 | else | 839 | |
834 | ucontrol->value.integer.value[0] = 0; | 840 | ucontrol->value.integer.value[0] = rate; |
835 | 841 | ||
836 | return 0; | 842 | return 0; |
837 | } | 843 | } |
@@ -969,12 +975,14 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | |||
969 | static struct snd_soc_dai_driver fsl_spdif_dai = { | 975 | static struct snd_soc_dai_driver fsl_spdif_dai = { |
970 | .probe = &fsl_spdif_dai_probe, | 976 | .probe = &fsl_spdif_dai_probe, |
971 | .playback = { | 977 | .playback = { |
978 | .stream_name = "CPU-Playback", | ||
972 | .channels_min = 2, | 979 | .channels_min = 2, |
973 | .channels_max = 2, | 980 | .channels_max = 2, |
974 | .rates = FSL_SPDIF_RATES_PLAYBACK, | 981 | .rates = FSL_SPDIF_RATES_PLAYBACK, |
975 | .formats = FSL_SPDIF_FORMATS_PLAYBACK, | 982 | .formats = FSL_SPDIF_FORMATS_PLAYBACK, |
976 | }, | 983 | }, |
977 | .capture = { | 984 | .capture = { |
985 | .stream_name = "CPU-Capture", | ||
978 | .channels_min = 2, | 986 | .channels_min = 2, |
979 | .channels_max = 2, | 987 | .channels_max = 2, |
980 | .rates = FSL_SPDIF_RATES_CAPTURE, | 988 | .rates = FSL_SPDIF_RATES_CAPTURE, |
@@ -1046,7 +1054,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | |||
1046 | struct clk *clk, u64 savesub, | 1054 | struct clk *clk, u64 savesub, |
1047 | enum spdif_txrate index, bool round) | 1055 | enum spdif_txrate index, bool round) |
1048 | { | 1056 | { |
1049 | const u32 rate[] = { 32000, 44100, 48000 }; | 1057 | const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; |
1050 | bool is_sysclk = clk == spdif_priv->sysclk; | 1058 | bool is_sysclk = clk == spdif_priv->sysclk; |
1051 | u64 rate_ideal, rate_actual, sub; | 1059 | u64 rate_ideal, rate_actual, sub; |
1052 | u32 sysclk_dfmin, sysclk_dfmax; | 1060 | u32 sysclk_dfmin, sysclk_dfmax; |
@@ -1076,7 +1084,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | |||
1076 | goto out; | 1084 | goto out; |
1077 | } else if (arate / rate[index] == 1) { | 1085 | } else if (arate / rate[index] == 1) { |
1078 | /* A little bigger than expect */ | 1086 | /* A little bigger than expect */ |
1079 | sub = (arate - rate[index]) * 100000; | 1087 | sub = (u64)(arate - rate[index]) * 100000; |
1080 | do_div(sub, rate[index]); | 1088 | do_div(sub, rate[index]); |
1081 | if (sub >= savesub) | 1089 | if (sub >= savesub) |
1082 | continue; | 1090 | continue; |
@@ -1086,7 +1094,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | |||
1086 | spdif_priv->txrate[index] = arate; | 1094 | spdif_priv->txrate[index] = arate; |
1087 | } else if (rate[index] / arate == 1) { | 1095 | } else if (rate[index] / arate == 1) { |
1088 | /* A little smaller than expect */ | 1096 | /* A little smaller than expect */ |
1089 | sub = (rate[index] - arate) * 100000; | 1097 | sub = (u64)(rate[index] - arate) * 100000; |
1090 | do_div(sub, rate[index]); | 1098 | do_div(sub, rate[index]); |
1091 | if (sub >= savesub) | 1099 | if (sub >= savesub) |
1092 | continue; | 1100 | continue; |
@@ -1105,7 +1113,7 @@ out: | |||
1105 | static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, | 1113 | static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, |
1106 | enum spdif_txrate index) | 1114 | enum spdif_txrate index) |
1107 | { | 1115 | { |
1108 | const u32 rate[] = { 32000, 44100, 48000 }; | 1116 | const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; |
1109 | struct platform_device *pdev = spdif_priv->pdev; | 1117 | struct platform_device *pdev = spdif_priv->pdev; |
1110 | struct device *dev = &pdev->dev; | 1118 | struct device *dev = &pdev->dev; |
1111 | u64 savesub = 100000, ret; | 1119 | u64 savesub = 100000, ret; |
@@ -1238,12 +1246,12 @@ static int fsl_spdif_probe(struct platform_device *pdev) | |||
1238 | spin_lock_init(&ctrl->ctl_lock); | 1246 | spin_lock_init(&ctrl->ctl_lock); |
1239 | 1247 | ||
1240 | /* Init tx channel status default value */ | 1248 | /* Init tx channel status default value */ |
1241 | ctrl->ch_status[0] = | 1249 | ctrl->ch_status[0] = IEC958_AES0_CON_NOT_COPYRIGHT | |
1242 | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015; | 1250 | IEC958_AES0_CON_EMPHASIS_5015; |
1243 | ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; | 1251 | ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; |
1244 | ctrl->ch_status[2] = 0x00; | 1252 | ctrl->ch_status[2] = 0x00; |
1245 | ctrl->ch_status[3] = | 1253 | ctrl->ch_status[3] = IEC958_AES3_CON_FS_44100 | |
1246 | IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM; | 1254 | IEC958_AES3_CON_CLOCK_1000PPM; |
1247 | 1255 | ||
1248 | spdif_priv->dpll_locked = false; | 1256 | spdif_priv->dpll_locked = false; |
1249 | 1257 | ||
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index 16fde4b927d3..00bd3514c610 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h | |||
@@ -93,6 +93,8 @@ | |||
93 | #define SCR_USRC_SEL_RECV (0x1 << SCR_USRC_SEL_OFFSET) | 93 | #define SCR_USRC_SEL_RECV (0x1 << SCR_USRC_SEL_OFFSET) |
94 | #define SCR_USRC_SEL_CHIP (0x3 << SCR_USRC_SEL_OFFSET) | 94 | #define SCR_USRC_SEL_CHIP (0x3 << SCR_USRC_SEL_OFFSET) |
95 | 95 | ||
96 | #define SCR_DMA_xX_EN(tx) (tx ? SCR_DMA_TX_EN : SCR_DMA_RX_EN) | ||
97 | |||
96 | /* SPDIF CDText control */ | 98 | /* SPDIF CDText control */ |
97 | #define SRCD_CD_USER_OFFSET 1 | 99 | #define SRCD_CD_USER_OFFSET 1 |
98 | #define SRCD_CD_USER (1 << SRCD_CD_USER_OFFSET) | 100 | #define SRCD_CD_USER (1 << SRCD_CD_USER_OFFSET) |
@@ -164,8 +166,10 @@ enum spdif_txrate { | |||
164 | SPDIF_TXRATE_32000 = 0, | 166 | SPDIF_TXRATE_32000 = 0, |
165 | SPDIF_TXRATE_44100, | 167 | SPDIF_TXRATE_44100, |
166 | SPDIF_TXRATE_48000, | 168 | SPDIF_TXRATE_48000, |
169 | SPDIF_TXRATE_96000, | ||
170 | SPDIF_TXRATE_192000, | ||
167 | }; | 171 | }; |
168 | #define SPDIF_TXRATE_MAX (SPDIF_TXRATE_48000 + 1) | 172 | #define SPDIF_TXRATE_MAX (SPDIF_TXRATE_192000 + 1) |
169 | 173 | ||
170 | 174 | ||
171 | #define SPDIF_CSTATUS_BYTE 6 | 175 | #define SPDIF_CSTATUS_BYTE 6 |
@@ -175,7 +179,9 @@ enum spdif_txrate { | |||
175 | 179 | ||
176 | #define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ | 180 | #define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ |
177 | SNDRV_PCM_RATE_44100 | \ | 181 | SNDRV_PCM_RATE_44100 | \ |
178 | SNDRV_PCM_RATE_48000) | 182 | SNDRV_PCM_RATE_48000 | \ |
183 | SNDRV_PCM_RATE_96000 | \ | ||
184 | SNDRV_PCM_RATE_192000) | ||
179 | 185 | ||
180 | #define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \ | 186 | #define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \ |
181 | SNDRV_PCM_RATE_32000 | \ | 187 | SNDRV_PCM_RATE_32000 | \ |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 9bfef55d77d1..87eb5776a39b 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -590,8 +590,8 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, | |||
590 | else | 590 | else |
591 | clkrate = clk_round_rate(ssi_private->baudclk, tmprate); | 591 | clkrate = clk_round_rate(ssi_private->baudclk, tmprate); |
592 | 592 | ||
593 | do_div(clkrate, factor); | 593 | clkrate /= factor; |
594 | afreq = (u32)clkrate / (i + 1); | 594 | afreq = clkrate / (i + 1); |
595 | 595 | ||
596 | if (freq == afreq) | 596 | if (freq == afreq) |
597 | sub = 0; | 597 | sub = 0; |
@@ -1032,12 +1032,14 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { | |||
1032 | static struct snd_soc_dai_driver fsl_ssi_dai_template = { | 1032 | static struct snd_soc_dai_driver fsl_ssi_dai_template = { |
1033 | .probe = fsl_ssi_dai_probe, | 1033 | .probe = fsl_ssi_dai_probe, |
1034 | .playback = { | 1034 | .playback = { |
1035 | .stream_name = "CPU-Playback", | ||
1035 | .channels_min = 1, | 1036 | .channels_min = 1, |
1036 | .channels_max = 2, | 1037 | .channels_max = 2, |
1037 | .rates = FSLSSI_I2S_RATES, | 1038 | .rates = FSLSSI_I2S_RATES, |
1038 | .formats = FSLSSI_I2S_FORMATS, | 1039 | .formats = FSLSSI_I2S_FORMATS, |
1039 | }, | 1040 | }, |
1040 | .capture = { | 1041 | .capture = { |
1042 | .stream_name = "CPU-Capture", | ||
1041 | .channels_min = 1, | 1043 | .channels_min = 1, |
1042 | .channels_max = 2, | 1044 | .channels_max = 2, |
1043 | .rates = FSLSSI_I2S_RATES, | 1045 | .rates = FSLSSI_I2S_RATES, |
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 267717aa96c1..46f9beb6b273 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c | |||
@@ -67,7 +67,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, | |||
67 | { | 67 | { |
68 | ssize_t ret; | 68 | ssize_t ret; |
69 | char *buf; | 69 | char *buf; |
70 | int port = (int)file->private_data; | 70 | uintptr_t port = (uintptr_t)file->private_data; |
71 | u32 pdcr, ptcr; | 71 | u32 pdcr, ptcr; |
72 | 72 | ||
73 | if (audmux_clk) { | 73 | if (audmux_clk) { |
@@ -147,7 +147,7 @@ static const struct file_operations audmux_debugfs_fops = { | |||
147 | 147 | ||
148 | static void audmux_debugfs_init(void) | 148 | static void audmux_debugfs_init(void) |
149 | { | 149 | { |
150 | int i; | 150 | uintptr_t i; |
151 | char buf[20]; | 151 | char buf[20]; |
152 | 152 | ||
153 | audmux_debugfs_root = debugfs_create_dir("audmux", NULL); | 153 | audmux_debugfs_root = debugfs_create_dir("audmux", NULL); |
@@ -157,10 +157,10 @@ static void audmux_debugfs_init(void) | |||
157 | } | 157 | } |
158 | 158 | ||
159 | for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) { | 159 | for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) { |
160 | snprintf(buf, sizeof(buf), "ssi%d", i); | 160 | snprintf(buf, sizeof(buf), "ssi%lu", i); |
161 | if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, | 161 | if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, |
162 | (void *)i, &audmux_debugfs_fops)) | 162 | (void *)i, &audmux_debugfs_fops)) |
163 | pr_warning("Failed to create AUDMUX port %d debugfs file\n", | 163 | pr_warning("Failed to create AUDMUX port %lu debugfs file\n", |
164 | i); | 164 | i); |
165 | } | 165 | } |
166 | } | 166 | } |
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 0849b7b83f0a..0db94f492e97 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c | |||
@@ -59,7 +59,6 @@ int imx_pcm_dma_init(struct platform_device *pdev) | |||
59 | { | 59 | { |
60 | return devm_snd_dmaengine_pcm_register(&pdev->dev, | 60 | return devm_snd_dmaengine_pcm_register(&pdev->dev, |
61 | &imx_dmaengine_pcm_config, | 61 | &imx_dmaengine_pcm_config, |
62 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | ||
63 | SND_DMAENGINE_PCM_FLAG_COMPAT); | 62 | SND_DMAENGINE_PCM_FLAG_COMPAT); |
64 | } | 63 | } |
65 | EXPORT_SYMBOL_GPL(imx_pcm_dma_init); | 64 | EXPORT_SYMBOL_GPL(imx_pcm_dma_init); |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 03a7fdcdf114..159e517fa09a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -116,6 +116,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
116 | { | 116 | { |
117 | struct device_node *node; | 117 | struct device_node *node; |
118 | struct clk *clk; | 118 | struct clk *clk; |
119 | u32 val; | ||
119 | int ret; | 120 | int ret; |
120 | 121 | ||
121 | /* | 122 | /* |
@@ -151,10 +152,8 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
151 | } | 152 | } |
152 | 153 | ||
153 | dai->sysclk = clk_get_rate(clk); | 154 | dai->sysclk = clk_get_rate(clk); |
154 | } else if (of_property_read_bool(np, "system-clock-frequency")) { | 155 | } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { |
155 | of_property_read_u32(np, | 156 | dai->sysclk = val; |
156 | "system-clock-frequency", | ||
157 | &dai->sysclk); | ||
158 | } else { | 157 | } else { |
159 | clk = of_clk_get(node, 0); | 158 | clk = of_clk_get(node, 0); |
160 | if (!IS_ERR(clk)) | 159 | if (!IS_ERR(clk)) |
@@ -303,6 +302,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
303 | { | 302 | { |
304 | struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; | 303 | struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; |
305 | struct simple_dai_props *dai_props = priv->dai_props; | 304 | struct simple_dai_props *dai_props = priv->dai_props; |
305 | u32 val; | ||
306 | int ret; | 306 | int ret; |
307 | 307 | ||
308 | /* parsing the card name from DT */ | 308 | /* parsing the card name from DT */ |
@@ -325,8 +325,9 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
325 | } | 325 | } |
326 | 326 | ||
327 | /* Factor to mclk, used in hw_params() */ | 327 | /* Factor to mclk, used in hw_params() */ |
328 | of_property_read_u32(node, "simple-audio-card,mclk-fs", | 328 | ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val); |
329 | &priv->mclk_fs); | 329 | if (ret == 0) |
330 | priv->mclk_fs = val; | ||
330 | 331 | ||
331 | dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? | 332 | dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? |
332 | priv->snd_card.name : ""); | 333 | priv->snd_card.name : ""); |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c30fedb3e149..f5b4a9c79cdf 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -58,3 +58,15 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH | |||
58 | help | 58 | help |
59 | This adds audio driver for Intel Baytrail platform based boards | 59 | This adds audio driver for Intel Baytrail platform based boards |
60 | with the MAX98090 audio codec. | 60 | with the MAX98090 audio codec. |
61 | |||
62 | config SND_SOC_INTEL_BROADWELL_MACH | ||
63 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | ||
64 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC | ||
65 | select SND_SOC_INTEL_HASWELL | ||
66 | select SND_COMPRESS_OFFLOAD | ||
67 | select SND_SOC_RT286 | ||
68 | help | ||
69 | This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell | ||
70 | Ultrabook platforms. | ||
71 | Say Y if you have such a device | ||
72 | If unsure select "N". | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 4bfca79a42ba..7acbfc43a0c6 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -24,7 +24,9 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o | |||
24 | snd-soc-sst-haswell-objs := haswell.o | 24 | snd-soc-sst-haswell-objs := haswell.o |
25 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 25 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
26 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 26 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
27 | snd-soc-sst-broadwell-objs := broadwell.o | ||
27 | 28 | ||
28 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 29 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
29 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 30 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
30 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | 31 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o |
32 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | ||
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c new file mode 100644 index 000000000000..0e550f14028f --- /dev/null +++ b/sound/soc/intel/broadwell.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * Intel Broadwell Wildcatpoint SST Audio | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | |||
24 | #include "sst-dsp.h" | ||
25 | #include "sst-haswell-ipc.h" | ||
26 | |||
27 | #include "../codecs/rt286.h" | ||
28 | |||
29 | static const struct snd_soc_dapm_widget broadwell_widgets[] = { | ||
30 | SND_SOC_DAPM_HP("Headphones", NULL), | ||
31 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
32 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
33 | SND_SOC_DAPM_MIC("DMIC1", NULL), | ||
34 | SND_SOC_DAPM_MIC("DMIC2", NULL), | ||
35 | SND_SOC_DAPM_LINE("Line Jack", NULL), | ||
36 | }; | ||
37 | |||
38 | static const struct snd_soc_dapm_route broadwell_rt286_map[] = { | ||
39 | |||
40 | /* speaker */ | ||
41 | {"Speaker", NULL, "SPOR"}, | ||
42 | {"Speaker", NULL, "SPOL"}, | ||
43 | |||
44 | /* HP jack connectors - unknown if we have jack deteck */ | ||
45 | {"Headphones", NULL, "HPO Pin"}, | ||
46 | |||
47 | /* other jacks */ | ||
48 | {"MIC1", NULL, "Mic Jack"}, | ||
49 | {"LINE1", NULL, "Line Jack"}, | ||
50 | |||
51 | /* digital mics */ | ||
52 | {"DMIC1 Pin", NULL, "DMIC1"}, | ||
53 | {"DMIC2 Pin", NULL, "DMIC2"}, | ||
54 | |||
55 | /* CODEC BE connections */ | ||
56 | {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, | ||
57 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | ||
58 | }; | ||
59 | |||
60 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | ||
61 | struct snd_pcm_hw_params *params) | ||
62 | { | ||
63 | struct snd_interval *rate = hw_param_interval(params, | ||
64 | SNDRV_PCM_HW_PARAM_RATE); | ||
65 | struct snd_interval *channels = hw_param_interval(params, | ||
66 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
67 | |||
68 | /* The ADSP will covert the FE rate to 48k, stereo */ | ||
69 | rate->min = rate->max = 48000; | ||
70 | channels->min = channels->max = 2; | ||
71 | |||
72 | /* set SSP0 to 16 bit */ | ||
73 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
74 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
75 | SNDRV_PCM_FORMAT_S16_LE); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, | ||
80 | struct snd_pcm_hw_params *params) | ||
81 | { | ||
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
83 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
84 | int ret; | ||
85 | |||
86 | ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, | ||
87 | SND_SOC_CLOCK_IN); | ||
88 | |||
89 | if (ret < 0) { | ||
90 | dev_err(rtd->dev, "can't set codec sysclk configuration\n"); | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | static struct snd_soc_ops broadwell_rt286_ops = { | ||
98 | .hw_params = broadwell_rt286_hw_params, | ||
99 | }; | ||
100 | |||
101 | static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) | ||
102 | { | ||
103 | struct snd_soc_codec *codec = rtd->codec; | ||
104 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
105 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); | ||
106 | struct sst_hsw *broadwell = pdata->dsp; | ||
107 | int ret; | ||
108 | |||
109 | /* Set ADSP SSP port settings */ | ||
110 | ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, | ||
111 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
112 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
113 | if (ret < 0) { | ||
114 | dev_err(rtd->dev, "error: failed to set device config\n"); | ||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | /* always connected - check HP for jack detect */ | ||
119 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | ||
120 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | ||
121 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | ||
122 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | ||
123 | snd_soc_dapm_enable_pin(dapm, "DMIC1"); | ||
124 | snd_soc_dapm_enable_pin(dapm, "DMIC2"); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | /* broadwell digital audio interface glue - connects codec <--> CPU */ | ||
130 | static struct snd_soc_dai_link broadwell_rt286_dais[] = { | ||
131 | /* Front End DAI links */ | ||
132 | { | ||
133 | .name = "System PCM", | ||
134 | .stream_name = "System Playback", | ||
135 | .cpu_dai_name = "System Pin", | ||
136 | .platform_name = "haswell-pcm-audio", | ||
137 | .dynamic = 1, | ||
138 | .codec_name = "snd-soc-dummy", | ||
139 | .codec_dai_name = "snd-soc-dummy-dai", | ||
140 | .init = broadwell_rtd_init, | ||
141 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
142 | .dpcm_playback = 1, | ||
143 | }, | ||
144 | { | ||
145 | .name = "Offload0", | ||
146 | .stream_name = "Offload0 Playback", | ||
147 | .cpu_dai_name = "Offload0 Pin", | ||
148 | .platform_name = "haswell-pcm-audio", | ||
149 | .dynamic = 1, | ||
150 | .codec_name = "snd-soc-dummy", | ||
151 | .codec_dai_name = "snd-soc-dummy-dai", | ||
152 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
153 | .dpcm_playback = 1, | ||
154 | }, | ||
155 | { | ||
156 | .name = "Offload1", | ||
157 | .stream_name = "Offload1 Playback", | ||
158 | .cpu_dai_name = "Offload1 Pin", | ||
159 | .platform_name = "haswell-pcm-audio", | ||
160 | .dynamic = 1, | ||
161 | .codec_name = "snd-soc-dummy", | ||
162 | .codec_dai_name = "snd-soc-dummy-dai", | ||
163 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
164 | .dpcm_playback = 1, | ||
165 | }, | ||
166 | { | ||
167 | .name = "Loopback PCM", | ||
168 | .stream_name = "Loopback", | ||
169 | .cpu_dai_name = "Loopback Pin", | ||
170 | .platform_name = "haswell-pcm-audio", | ||
171 | .dynamic = 0, | ||
172 | .codec_name = "snd-soc-dummy", | ||
173 | .codec_dai_name = "snd-soc-dummy-dai", | ||
174 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
175 | .dpcm_capture = 1, | ||
176 | }, | ||
177 | { | ||
178 | .name = "Capture PCM", | ||
179 | .stream_name = "Capture", | ||
180 | .cpu_dai_name = "Capture Pin", | ||
181 | .platform_name = "haswell-pcm-audio", | ||
182 | .dynamic = 1, | ||
183 | .codec_name = "snd-soc-dummy", | ||
184 | .codec_dai_name = "snd-soc-dummy-dai", | ||
185 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
186 | .dpcm_capture = 1, | ||
187 | }, | ||
188 | |||
189 | /* Back End DAI links */ | ||
190 | { | ||
191 | /* SSP0 - Codec */ | ||
192 | .name = "Codec", | ||
193 | .be_id = 0, | ||
194 | .cpu_dai_name = "snd-soc-dummy-dai", | ||
195 | .platform_name = "snd-soc-dummy", | ||
196 | .no_pcm = 1, | ||
197 | .codec_name = "i2c-INT343A:00", | ||
198 | .codec_dai_name = "rt286-aif1", | ||
199 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
200 | SND_SOC_DAIFMT_CBS_CFS, | ||
201 | .ignore_suspend = 1, | ||
202 | .ignore_pmdown_time = 1, | ||
203 | .be_hw_params_fixup = broadwell_ssp0_fixup, | ||
204 | .ops = &broadwell_rt286_ops, | ||
205 | .dpcm_playback = 1, | ||
206 | .dpcm_capture = 1, | ||
207 | }, | ||
208 | }; | ||
209 | |||
210 | /* broadwell audio machine driver for WPT + RT286S */ | ||
211 | static struct snd_soc_card broadwell_rt286 = { | ||
212 | .name = "broadwell-rt286", | ||
213 | .owner = THIS_MODULE, | ||
214 | .dai_link = broadwell_rt286_dais, | ||
215 | .num_links = ARRAY_SIZE(broadwell_rt286_dais), | ||
216 | .dapm_widgets = broadwell_widgets, | ||
217 | .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), | ||
218 | .dapm_routes = broadwell_rt286_map, | ||
219 | .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), | ||
220 | .fully_routed = true, | ||
221 | }; | ||
222 | |||
223 | static int broadwell_audio_probe(struct platform_device *pdev) | ||
224 | { | ||
225 | broadwell_rt286.dev = &pdev->dev; | ||
226 | |||
227 | return snd_soc_register_card(&broadwell_rt286); | ||
228 | } | ||
229 | |||
230 | static int broadwell_audio_remove(struct platform_device *pdev) | ||
231 | { | ||
232 | snd_soc_unregister_card(&broadwell_rt286); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static struct platform_driver broadwell_audio = { | ||
237 | .probe = broadwell_audio_probe, | ||
238 | .remove = broadwell_audio_remove, | ||
239 | .driver = { | ||
240 | .name = "broadwell-audio", | ||
241 | .owner = THIS_MODULE, | ||
242 | }, | ||
243 | }; | ||
244 | |||
245 | module_platform_driver(broadwell_audio) | ||
246 | |||
247 | /* Module information */ | ||
248 | MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); | ||
249 | MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell"); | ||
250 | MODULE_LICENSE("GPL v2"); | ||
251 | MODULE_ALIAS("platform:broadwell-audio"); | ||
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index 5fc98c64a3f4..b8b8af571ef1 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c | |||
@@ -39,8 +39,7 @@ static const struct snd_soc_dapm_widget byt_max98090_widgets[] = { | |||
39 | 39 | ||
40 | static const struct snd_soc_dapm_route byt_max98090_audio_map[] = { | 40 | static const struct snd_soc_dapm_route byt_max98090_audio_map[] = { |
41 | {"IN34", NULL, "Headset Mic"}, | 41 | {"IN34", NULL, "Headset Mic"}, |
42 | {"IN34", NULL, "MICBIAS"}, | 42 | {"Headset Mic", NULL, "MICBIAS"}, |
43 | {"MICBIAS", NULL, "Headset Mic"}, | ||
44 | {"DMICL", NULL, "Int Mic"}, | 43 | {"DMICL", NULL, "Int Mic"}, |
45 | {"Headphone", NULL, "HPL"}, | 44 | {"Headphone", NULL, "HPL"}, |
46 | {"Headphone", NULL, "HPR"}, | 45 | {"Headphone", NULL, "HPR"}, |
@@ -64,14 +63,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { | |||
64 | .pin = "Headset Mic", | 63 | .pin = "Headset Mic", |
65 | .mask = SND_JACK_MICROPHONE, | 64 | .mask = SND_JACK_MICROPHONE, |
66 | }, | 65 | }, |
67 | { | ||
68 | .pin = "Ext Spk", | ||
69 | .mask = SND_JACK_LINEOUT, | ||
70 | }, | ||
71 | { | ||
72 | .pin = "Int Mic", | ||
73 | .mask = SND_JACK_LINEIN, | ||
74 | }, | ||
75 | }; | 66 | }; |
76 | 67 | ||
77 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { | 68 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { |
@@ -84,7 +75,8 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = { | |||
84 | { | 75 | { |
85 | .name = "mic-gpio", | 76 | .name = "mic-gpio", |
86 | .idx = 1, | 77 | .idx = 1, |
87 | .report = SND_JACK_MICROPHONE | SND_JACK_LINEIN, | 78 | .invert = 1, |
79 | .report = SND_JACK_MICROPHONE, | ||
88 | .debounce_time = 200, | 80 | .debounce_time = 200, |
89 | }, | 81 | }, |
90 | }; | 82 | }; |
@@ -108,7 +100,8 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) | |||
108 | } | 100 | } |
109 | 101 | ||
110 | /* Enable jack detection */ | 102 | /* Enable jack detection */ |
111 | ret = snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, jack); | 103 | ret = snd_soc_jack_new(codec, "Headset", |
104 | SND_JACK_LINEOUT | SND_JACK_HEADSET, jack); | ||
112 | if (ret) | 105 | if (ret) |
113 | return ret; | 106 | return ret; |
114 | 107 | ||
@@ -117,13 +110,9 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) | |||
117 | if (ret) | 110 | if (ret) |
118 | return ret; | 111 | return ret; |
119 | 112 | ||
120 | ret = snd_soc_jack_add_gpiods(card->dev->parent, jack, | 113 | return snd_soc_jack_add_gpiods(card->dev->parent, jack, |
121 | ARRAY_SIZE(hs_jack_gpios), | 114 | ARRAY_SIZE(hs_jack_gpios), |
122 | hs_jack_gpios); | 115 | hs_jack_gpios); |
123 | if (ret) | ||
124 | return ret; | ||
125 | |||
126 | return max98090_mic_detect(codec, jack); | ||
127 | } | 116 | } |
128 | 117 | ||
129 | static struct snd_soc_dai_link byt_max98090_dais[] = { | 118 | static struct snd_soc_dai_link byt_max98090_dais[] = { |
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 53d160d39972..234a58de3c53 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c | |||
@@ -34,6 +34,7 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | |||
34 | }; | 34 | }; |
35 | 35 | ||
36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | 36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { |
37 | {"Headset Mic", NULL, "MICBIAS1"}, | ||
37 | {"IN2P", NULL, "Headset Mic"}, | 38 | {"IN2P", NULL, "Headset Mic"}, |
38 | {"IN2N", NULL, "Headset Mic"}, | 39 | {"IN2N", NULL, "Headset Mic"}, |
39 | {"DMIC1", NULL, "Internal Mic"}, | 40 | {"DMIC1", NULL, "Internal Mic"}, |
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h new file mode 100644 index 000000000000..14063ab8c7c5 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013-14 Intel Corp | ||
3 | * Author: Ramesh Babu <ramesh.babu.koul@intel.com> | ||
4 | * Omair M Abdullah <omair.m.abdullah@intel.com> | ||
5 | * Samreen Nilofer <samreen.nilofer@intel.com> | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #ifndef __SST_CONTROLS_V2_H__ | ||
22 | #define __SST_CONTROLS_V2_H__ | ||
23 | |||
24 | enum { | ||
25 | MERR_DPCM_AUDIO = 0, | ||
26 | MERR_DPCM_COMPR, | ||
27 | }; | ||
28 | |||
29 | |||
30 | #endif | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d207b22ea330..67673a2c0f41 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
@@ -122,6 +122,26 @@ struct sst_byt_tstamp { | |||
122 | u32 channel_peak[8]; | 122 | u32 channel_peak[8]; |
123 | } __packed; | 123 | } __packed; |
124 | 124 | ||
125 | struct sst_byt_fw_version { | ||
126 | u8 build; | ||
127 | u8 minor; | ||
128 | u8 major; | ||
129 | u8 type; | ||
130 | } __packed; | ||
131 | |||
132 | struct sst_byt_fw_build_info { | ||
133 | u8 date[16]; | ||
134 | u8 time[16]; | ||
135 | } __packed; | ||
136 | |||
137 | struct sst_byt_fw_init { | ||
138 | struct sst_byt_fw_version fw_version; | ||
139 | struct sst_byt_fw_build_info build_info; | ||
140 | u16 result; | ||
141 | u8 module_id; | ||
142 | u8 debug_info; | ||
143 | } __packed; | ||
144 | |||
125 | /* driver internal IPC message structure */ | 145 | /* driver internal IPC message structure */ |
126 | struct ipc_message { | 146 | struct ipc_message { |
127 | struct list_head list; | 147 | struct list_head list; |
@@ -868,6 +888,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
868 | { | 888 | { |
869 | struct sst_byt *byt; | 889 | struct sst_byt *byt; |
870 | struct sst_fw *byt_sst_fw; | 890 | struct sst_fw *byt_sst_fw; |
891 | struct sst_byt_fw_init init; | ||
871 | int err; | 892 | int err; |
872 | 893 | ||
873 | dev_dbg(dev, "initialising Byt DSP IPC\n"); | 894 | dev_dbg(dev, "initialising Byt DSP IPC\n"); |
@@ -929,6 +950,15 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
929 | goto boot_err; | 950 | goto boot_err; |
930 | } | 951 | } |
931 | 952 | ||
953 | /* show firmware information */ | ||
954 | sst_dsp_inbox_read(byt->dsp, &init, sizeof(init)); | ||
955 | dev_info(byt->dev, "FW version: %02x.%02x.%02x.%02x\n", | ||
956 | init.fw_version.major, init.fw_version.minor, | ||
957 | init.fw_version.build, init.fw_version.type); | ||
958 | dev_info(byt->dev, "Build type: %x\n", init.fw_version.type); | ||
959 | dev_info(byt->dev, "Build date: %s %s\n", | ||
960 | init.build_info.date, init.build_info.time); | ||
961 | |||
932 | pdata->dsp = byt; | 962 | pdata->dsp = byt; |
933 | byt->fw = byt_sst_fw; | 963 | byt->fw = byt_sst_fw; |
934 | 964 | ||
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 8eab97368ea7..599401c0c655 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c | |||
@@ -32,7 +32,7 @@ static const struct snd_pcm_hardware sst_byt_pcm_hardware = { | |||
32 | SNDRV_PCM_INFO_PAUSE | | 32 | SNDRV_PCM_INFO_PAUSE | |
33 | SNDRV_PCM_INFO_RESUME, | 33 | SNDRV_PCM_INFO_RESUME, |
34 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 34 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
35 | SNDRV_PCM_FORMAT_S24_LE, | 35 | SNDRV_PCM_FMTBIT_S24_LE, |
36 | .period_bytes_min = 384, | 36 | .period_bytes_min = 384, |
37 | .period_bytes_max = 48000, | 37 | .period_bytes_max = 48000, |
38 | .periods_min = 2, | 38 | .periods_min = 2, |
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 0b715b20a2d7..cd23060a0d86 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c | |||
@@ -224,19 +224,23 @@ EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); | |||
224 | 224 | ||
225 | void sst_dsp_dump(struct sst_dsp *sst) | 225 | void sst_dsp_dump(struct sst_dsp *sst) |
226 | { | 226 | { |
227 | sst->ops->dump(sst); | 227 | if (sst->ops->dump) |
228 | sst->ops->dump(sst); | ||
228 | } | 229 | } |
229 | EXPORT_SYMBOL_GPL(sst_dsp_dump); | 230 | EXPORT_SYMBOL_GPL(sst_dsp_dump); |
230 | 231 | ||
231 | void sst_dsp_reset(struct sst_dsp *sst) | 232 | void sst_dsp_reset(struct sst_dsp *sst) |
232 | { | 233 | { |
233 | sst->ops->reset(sst); | 234 | if (sst->ops->reset) |
235 | sst->ops->reset(sst); | ||
234 | } | 236 | } |
235 | EXPORT_SYMBOL_GPL(sst_dsp_reset); | 237 | EXPORT_SYMBOL_GPL(sst_dsp_reset); |
236 | 238 | ||
237 | int sst_dsp_boot(struct sst_dsp *sst) | 239 | int sst_dsp_boot(struct sst_dsp *sst) |
238 | { | 240 | { |
239 | sst->ops->boot(sst); | 241 | if (sst->ops->boot) |
242 | sst->ops->boot(sst); | ||
243 | |||
240 | return 0; | 244 | return 0; |
241 | } | 245 | } |
242 | EXPORT_SYMBOL_GPL(sst_dsp_boot); | 246 | EXPORT_SYMBOL_GPL(sst_dsp_boot); |
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index e44423be66c4..3165dfa97408 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h | |||
@@ -52,7 +52,11 @@ | |||
52 | #define SST_CLKCTL 0x78 | 52 | #define SST_CLKCTL 0x78 |
53 | #define SST_CSR2 0x80 | 53 | #define SST_CSR2 0x80 |
54 | #define SST_LTRC 0xE0 | 54 | #define SST_LTRC 0xE0 |
55 | #define SST_HDMC 0xE8 | 55 | #define SST_HMDC 0xE8 |
56 | |||
57 | #define SST_SHIM_BEGIN SST_CSR | ||
58 | #define SST_SHIM_END SST_HDMC | ||
59 | |||
56 | #define SST_DBGO 0xF0 | 60 | #define SST_DBGO 0xF0 |
57 | 61 | ||
58 | #define SST_SHIM_SIZE 0x100 | 62 | #define SST_SHIM_SIZE 0x100 |
@@ -73,6 +77,8 @@ | |||
73 | #define SST_CSR_S0IOCS (0x1 << 21) | 77 | #define SST_CSR_S0IOCS (0x1 << 21) |
74 | #define SST_CSR_S1IOCS (0x1 << 23) | 78 | #define SST_CSR_S1IOCS (0x1 << 23) |
75 | #define SST_CSR_LPCS (0x1 << 31) | 79 | #define SST_CSR_LPCS (0x1 << 31) |
80 | #define SST_CSR_24MHZ_LPCS (SST_CSR_SBCS0 | SST_CSR_SBCS1 | SST_CSR_LPCS) | ||
81 | #define SST_CSR_24MHZ_NO_LPCS (SST_CSR_SBCS0 | SST_CSR_SBCS1) | ||
76 | #define SST_BYT_CSR_RST (0x1 << 0) | 82 | #define SST_BYT_CSR_RST (0x1 << 0) |
77 | #define SST_BYT_CSR_VECTOR_SEL (0x1 << 1) | 83 | #define SST_BYT_CSR_VECTOR_SEL (0x1 << 1) |
78 | #define SST_BYT_CSR_STALL (0x1 << 2) | 84 | #define SST_BYT_CSR_STALL (0x1 << 2) |
@@ -92,6 +98,14 @@ | |||
92 | #define SST_IMRX_DONE (0x1 << 0) | 98 | #define SST_IMRX_DONE (0x1 << 0) |
93 | #define SST_BYT_IMRX_REQUEST (0x1 << 1) | 99 | #define SST_BYT_IMRX_REQUEST (0x1 << 1) |
94 | 100 | ||
101 | /* IMRD / IMD */ | ||
102 | #define SST_IMRD_DONE (0x1 << 0) | ||
103 | #define SST_IMRD_BUSY (0x1 << 1) | ||
104 | #define SST_IMRD_SSP0 (0x1 << 16) | ||
105 | #define SST_IMRD_DMAC0 (0x1 << 21) | ||
106 | #define SST_IMRD_DMAC1 (0x1 << 22) | ||
107 | #define SST_IMRD_DMAC (SST_IMRD_DMAC0 | SST_IMRD_DMAC1) | ||
108 | |||
95 | /* IPCX / IPCC */ | 109 | /* IPCX / IPCC */ |
96 | #define SST_IPCX_DONE (0x1 << 30) | 110 | #define SST_IPCX_DONE (0x1 << 30) |
97 | #define SST_IPCX_BUSY (0x1 << 31) | 111 | #define SST_IPCX_BUSY (0x1 << 31) |
@@ -118,9 +132,21 @@ | |||
118 | /* LTRC */ | 132 | /* LTRC */ |
119 | #define SST_LTRC_VAL(x) (x << 0) | 133 | #define SST_LTRC_VAL(x) (x << 0) |
120 | 134 | ||
121 | /* HDMC */ | 135 | /* HMDC */ |
122 | #define SST_HDMC_HDDA0(x) (x << 0) | 136 | #define SST_HMDC_HDDA0(x) (x << 0) |
123 | #define SST_HDMC_HDDA1(x) (x << 7) | 137 | #define SST_HMDC_HDDA1(x) (x << 7) |
138 | #define SST_HMDC_HDDA_E0_CH0 1 | ||
139 | #define SST_HMDC_HDDA_E0_CH1 2 | ||
140 | #define SST_HMDC_HDDA_E0_CH2 4 | ||
141 | #define SST_HMDC_HDDA_E0_CH3 8 | ||
142 | #define SST_HMDC_HDDA_E1_CH0 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH0) | ||
143 | #define SST_HMDC_HDDA_E1_CH1 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH1) | ||
144 | #define SST_HMDC_HDDA_E1_CH2 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH2) | ||
145 | #define SST_HMDC_HDDA_E1_CH3 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH3) | ||
146 | #define SST_HMDC_HDDA_E0_ALLCH (SST_HMDC_HDDA_E0_CH0 | SST_HMDC_HDDA_E0_CH1 | \ | ||
147 | SST_HMDC_HDDA_E0_CH2 | SST_HMDC_HDDA_E0_CH3) | ||
148 | #define SST_HMDC_HDDA_E1_ALLCH (SST_HMDC_HDDA_E1_CH0 | SST_HMDC_HDDA_E1_CH1 | \ | ||
149 | SST_HMDC_HDDA_E1_CH2 | SST_HMDC_HDDA_E1_CH3) | ||
124 | 150 | ||
125 | 151 | ||
126 | /* SST Vendor Defined Registers and bits */ | 152 | /* SST Vendor Defined Registers and bits */ |
@@ -130,11 +156,16 @@ | |||
130 | #define SST_VDRTCTL3 0xaC | 156 | #define SST_VDRTCTL3 0xaC |
131 | 157 | ||
132 | /* VDRTCTL0 */ | 158 | /* VDRTCTL0 */ |
159 | #define SST_VDRTCL0_APLLSE_MASK 1 | ||
133 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 | 160 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 |
134 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) | 161 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) |
135 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 | 162 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 |
136 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) | 163 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) |
137 | 164 | ||
165 | /* PMCS */ | ||
166 | #define SST_PMCS 0x84 | ||
167 | #define SST_PMCS_PS_MASK 0x3 | ||
168 | |||
138 | struct sst_dsp; | 169 | struct sst_dsp; |
139 | 170 | ||
140 | /* | 171 | /* |
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 535f517629fd..4b6c163c10ff 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
@@ -28,9 +28,6 @@ | |||
28 | #include <linux/firmware.h> | 28 | #include <linux/firmware.h> |
29 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
30 | 30 | ||
31 | #include <linux/acpi.h> | ||
32 | #include <acpi/acpi_bus.h> | ||
33 | |||
34 | #include "sst-dsp.h" | 31 | #include "sst-dsp.h" |
35 | #include "sst-dsp-priv.h" | 32 | #include "sst-dsp-priv.h" |
36 | #include "sst-haswell-ipc.h" | 33 | #include "sst-haswell-ipc.h" |
@@ -272,9 +269,9 @@ static void hsw_boot(struct sst_dsp *sst) | |||
272 | SST_CSR2_SDFD_SSP1); | 269 | SST_CSR2_SDFD_SSP1); |
273 | 270 | ||
274 | /* enable DMA engine 0,1 all channels to access host memory */ | 271 | /* enable DMA engine 0,1 all channels to access host memory */ |
275 | sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC, | 272 | sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC, |
276 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff), | 273 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff), |
277 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff)); | 274 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff)); |
278 | 275 | ||
279 | /* disable all clock gating */ | 276 | /* disable all clock gating */ |
280 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); | 277 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); |
@@ -313,9 +310,7 @@ static const struct sst_adsp_memregion lp_region[] = { | |||
313 | 310 | ||
314 | /* wild cat point ADSP mem regions */ | 311 | /* wild cat point ADSP mem regions */ |
315 | static const struct sst_adsp_memregion wpt_region[] = { | 312 | static const struct sst_adsp_memregion wpt_region[] = { |
316 | {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | 313 | {0x00000, 0xA0000, 20, SST_MEM_DRAM}, /* D-SRAM0,D-SRAM1,D-SRAM2 - 20 * 32kB */ |
317 | {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */ | ||
318 | {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */ | ||
319 | {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */ | 314 | {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */ |
320 | }; | 315 | }; |
321 | 316 | ||
@@ -339,26 +334,56 @@ static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
339 | return 0; | 334 | return 0; |
340 | } | 335 | } |
341 | 336 | ||
337 | struct sst_sram_shift { | ||
338 | u32 dev_id; /* SST Device IDs */ | ||
339 | u32 iram_shift; | ||
340 | u32 dram_shift; | ||
341 | }; | ||
342 | |||
343 | static const struct sst_sram_shift sram_shift[] = { | ||
344 | {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */ | ||
345 | {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */ | ||
346 | }; | ||
342 | static u32 hsw_block_get_bit(struct sst_mem_block *block) | 347 | static u32 hsw_block_get_bit(struct sst_mem_block *block) |
343 | { | 348 | { |
344 | u32 bit = 0, shift = 0; | 349 | u32 bit = 0, shift = 0, index; |
350 | struct sst_dsp *sst = block->dsp; | ||
345 | 351 | ||
346 | switch (block->type) { | 352 | for (index = 0; index < ARRAY_SIZE(sram_shift); index++) { |
347 | case SST_MEM_DRAM: | 353 | if (sram_shift[index].dev_id == sst->id) |
348 | shift = 16; | 354 | break; |
349 | break; | ||
350 | case SST_MEM_IRAM: | ||
351 | shift = 6; | ||
352 | break; | ||
353 | default: | ||
354 | return 0; | ||
355 | } | 355 | } |
356 | 356 | ||
357 | if (index < ARRAY_SIZE(sram_shift)) { | ||
358 | switch (block->type) { | ||
359 | case SST_MEM_DRAM: | ||
360 | shift = sram_shift[index].dram_shift; | ||
361 | break; | ||
362 | case SST_MEM_IRAM: | ||
363 | shift = sram_shift[index].iram_shift; | ||
364 | break; | ||
365 | default: | ||
366 | shift = 0; | ||
367 | } | ||
368 | } else | ||
369 | shift = 0; | ||
370 | |||
357 | bit = 1 << (block->index + shift); | 371 | bit = 1 << (block->index + shift); |
358 | 372 | ||
359 | return bit; | 373 | return bit; |
360 | } | 374 | } |
361 | 375 | ||
376 | /*dummy read a SRAM block.*/ | ||
377 | static void sst_mem_block_dummy_read(struct sst_mem_block *block) | ||
378 | { | ||
379 | u32 size; | ||
380 | u8 tmp_buf[4]; | ||
381 | struct sst_dsp *sst = block->dsp; | ||
382 | |||
383 | size = block->size > 4 ? 4 : block->size; | ||
384 | memcpy_fromio(tmp_buf, sst->addr.lpe + block->offset, size); | ||
385 | } | ||
386 | |||
362 | /* enable 32kB memory block - locks held by caller */ | 387 | /* enable 32kB memory block - locks held by caller */ |
363 | static int hsw_block_enable(struct sst_mem_block *block) | 388 | static int hsw_block_enable(struct sst_mem_block *block) |
364 | { | 389 | { |
@@ -378,6 +403,8 @@ static int hsw_block_enable(struct sst_mem_block *block) | |||
378 | /* wait 18 DSP clock ticks */ | 403 | /* wait 18 DSP clock ticks */ |
379 | udelay(10); | 404 | udelay(10); |
380 | 405 | ||
406 | /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/ | ||
407 | sst_mem_block_dummy_read(block); | ||
381 | return 0; | 408 | return 0; |
382 | } | 409 | } |
383 | 410 | ||
@@ -488,8 +515,9 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
488 | } | 515 | } |
489 | } | 516 | } |
490 | 517 | ||
491 | /* set default power gating mask */ | 518 | /* set default power gating control, enable power gating control for all blocks. that is, |
492 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0); | 519 | can't be accessed, please enable each block before accessing. */ |
520 | writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
493 | 521 | ||
494 | return 0; | 522 | return 0; |
495 | } | 523 | } |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 434236343ddf..b6291516dbbf 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -183,7 +183,7 @@ struct sst_hsw_ipc_fw_ready { | |||
183 | u32 inbox_size; | 183 | u32 inbox_size; |
184 | u32 outbox_size; | 184 | u32 outbox_size; |
185 | u32 fw_info_size; | 185 | u32 fw_info_size; |
186 | u8 fw_info[1]; | 186 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; |
187 | } __attribute__((packed)); | 187 | } __attribute__((packed)); |
188 | 188 | ||
189 | struct ipc_message { | 189 | struct ipc_message { |
@@ -457,9 +457,10 @@ static void ipc_tx_msgs(struct kthread_work *work) | |||
457 | return; | 457 | return; |
458 | } | 458 | } |
459 | 459 | ||
460 | /* if the DSP is busy we will TX messages after IRQ */ | 460 | /* if the DSP is busy, we will TX messages after IRQ. |
461 | * also postpone if we are in the middle of procesing completion irq*/ | ||
461 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); | 462 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); |
462 | if (ipcx & SST_IPCX_BUSY) { | 463 | if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { |
463 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | 464 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); |
464 | return; | 465 | return; |
465 | } | 466 | } |
@@ -502,6 +503,7 @@ static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg, | |||
502 | ipc_shim_dbg(hsw, "message timeout"); | 503 | ipc_shim_dbg(hsw, "message timeout"); |
503 | 504 | ||
504 | trace_ipc_error("error message timeout for", msg->header); | 505 | trace_ipc_error("error message timeout for", msg->header); |
506 | list_del(&msg->list); | ||
505 | ret = -ETIMEDOUT; | 507 | ret = -ETIMEDOUT; |
506 | } else { | 508 | } else { |
507 | 509 | ||
@@ -569,6 +571,9 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | |||
569 | { | 571 | { |
570 | struct sst_hsw_ipc_fw_ready fw_ready; | 572 | struct sst_hsw_ipc_fw_ready fw_ready; |
571 | u32 offset; | 573 | u32 offset; |
574 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; | ||
575 | char *tmp[5], *pinfo; | ||
576 | int i = 0; | ||
572 | 577 | ||
573 | offset = (header & 0x1FFFFFFF) << 3; | 578 | offset = (header & 0x1FFFFFFF) << 3; |
574 | 579 | ||
@@ -589,6 +594,19 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | |||
589 | fw_ready.inbox_offset, fw_ready.inbox_size); | 594 | fw_ready.inbox_offset, fw_ready.inbox_size); |
590 | dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n", | 595 | dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n", |
591 | fw_ready.outbox_offset, fw_ready.outbox_size); | 596 | fw_ready.outbox_offset, fw_ready.outbox_size); |
597 | if (fw_ready.fw_info_size < sizeof(fw_ready.fw_info)) { | ||
598 | fw_ready.fw_info[fw_ready.fw_info_size] = 0; | ||
599 | dev_dbg(hsw->dev, " Firmware info: %s \n", fw_ready.fw_info); | ||
600 | |||
601 | /* log the FW version info got from the mailbox here. */ | ||
602 | memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size); | ||
603 | pinfo = &fw_info[0]; | ||
604 | for (i = 0; i < sizeof(tmp) / sizeof(char *); i++) | ||
605 | tmp[i] = strsep(&pinfo, " "); | ||
606 | dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - " | ||
607 | "version: %s.%s, build %s, source commit id: %s\n", | ||
608 | tmp[0], tmp[1], tmp[2], tmp[3], tmp[4]); | ||
609 | } | ||
592 | } | 610 | } |
593 | 611 | ||
594 | static void hsw_notification_work(struct work_struct *work) | 612 | static void hsw_notification_work(struct work_struct *work) |
@@ -671,7 +689,9 @@ static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) | |||
671 | switch (stream_msg) { | 689 | switch (stream_msg) { |
672 | case IPC_STR_STAGE_MESSAGE: | 690 | case IPC_STR_STAGE_MESSAGE: |
673 | case IPC_STR_NOTIFICATION: | 691 | case IPC_STR_NOTIFICATION: |
692 | break; | ||
674 | case IPC_STR_RESET: | 693 | case IPC_STR_RESET: |
694 | trace_ipc_notification("stream reset", stream->reply.stream_hw_id); | ||
675 | break; | 695 | break; |
676 | case IPC_STR_PAUSE: | 696 | case IPC_STR_PAUSE: |
677 | stream->running = false; | 697 | stream->running = false; |
@@ -762,7 +782,8 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
762 | } | 782 | } |
763 | 783 | ||
764 | /* update any stream states */ | 784 | /* update any stream states */ |
765 | hsw_stream_update(hsw, msg); | 785 | if (msg_get_global_type(header) == IPC_GLB_STREAM_MESSAGE) |
786 | hsw_stream_update(hsw, msg); | ||
766 | 787 | ||
767 | /* wake up and return the error if we have waiters on this message ? */ | 788 | /* wake up and return the error if we have waiters on this message ? */ |
768 | list_del(&msg->list); | 789 | list_del(&msg->list); |
@@ -1628,7 +1649,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1628 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) | 1649 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) |
1629 | { | 1650 | { |
1630 | u32 header, state_; | 1651 | u32 header, state_; |
1631 | int ret; | 1652 | int ret, item; |
1632 | 1653 | ||
1633 | header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); | 1654 | header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); |
1634 | state_ = state; | 1655 | state_ = state; |
@@ -1642,6 +1663,13 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1642 | return ret; | 1663 | return ret; |
1643 | } | 1664 | } |
1644 | 1665 | ||
1666 | for (item = 0; item < dx->entries_no; item++) { | ||
1667 | dev_dbg(hsw->dev, | ||
1668 | "Item[%d] offset[%x] - size[%x] - source[%x]\n", | ||
1669 | item, dx->mem_info[item].offset, | ||
1670 | dx->mem_info[item].size, | ||
1671 | dx->mem_info[item].source); | ||
1672 | } | ||
1645 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", | 1673 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", |
1646 | dx->entries_no, state); | 1674 | dx->entries_no, state); |
1647 | 1675 | ||
@@ -1775,8 +1803,6 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1775 | 1803 | ||
1776 | /* get the FW version */ | 1804 | /* get the FW version */ |
1777 | sst_hsw_fw_get_version(hsw, &version); | 1805 | sst_hsw_fw_get_version(hsw, &version); |
1778 | dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n", | ||
1779 | version.type, version.major, version.minor, version.build); | ||
1780 | 1806 | ||
1781 | /* get the globalmixer */ | 1807 | /* get the globalmixer */ |
1782 | ret = sst_hsw_mixer_get_info(hsw); | 1808 | ret = sst_hsw_mixer_get_info(hsw); |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 058efb17c568..61bf6da4bb02 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -80,7 +80,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { | |||
80 | SNDRV_PCM_INFO_PAUSE | | 80 | SNDRV_PCM_INFO_PAUSE | |
81 | SNDRV_PCM_INFO_RESUME | | 81 | SNDRV_PCM_INFO_RESUME | |
82 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | 82 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, |
83 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE | | 83 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | |
84 | SNDRV_PCM_FMTBIT_S32_LE, | 84 | SNDRV_PCM_FMTBIT_S32_LE, |
85 | .period_bytes_min = PAGE_SIZE, | 85 | .period_bytes_min = PAGE_SIZE, |
86 | .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE, | 86 | .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE, |
@@ -400,7 +400,15 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
400 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16); | 400 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16); |
401 | break; | 401 | break; |
402 | case SNDRV_PCM_FORMAT_S24_LE: | 402 | case SNDRV_PCM_FORMAT_S24_LE: |
403 | bits = SST_HSW_DEPTH_24BIT; | 403 | bits = SST_HSW_DEPTH_32BIT; |
404 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 24); | ||
405 | break; | ||
406 | case SNDRV_PCM_FORMAT_S8: | ||
407 | bits = SST_HSW_DEPTH_8BIT; | ||
408 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 8); | ||
409 | break; | ||
410 | case SNDRV_PCM_FORMAT_S32_LE: | ||
411 | bits = SST_HSW_DEPTH_32BIT; | ||
404 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32); | 412 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32); |
405 | break; | 413 | break; |
406 | default: | 414 | default: |
@@ -685,8 +693,9 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
685 | } | 693 | } |
686 | 694 | ||
687 | #define HSW_FORMATS \ | 695 | #define HSW_FORMATS \ |
688 | (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ | 696 | (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ |
689 | SNDRV_PCM_FMTBIT_S32_LE) | 697 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ |
698 | SNDRV_PCM_FMTBIT_S8) | ||
690 | 699 | ||
691 | static struct snd_soc_dai_driver hsw_dais[] = { | 700 | static struct snd_soc_dai_driver hsw_dais[] = { |
692 | { | 701 | { |
@@ -696,7 +705,7 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
696 | .channels_min = 2, | 705 | .channels_min = 2, |
697 | .channels_max = 2, | 706 | .channels_max = 2, |
698 | .rates = SNDRV_PCM_RATE_48000, | 707 | .rates = SNDRV_PCM_RATE_48000, |
699 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 708 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
700 | }, | 709 | }, |
701 | }, | 710 | }, |
702 | { | 711 | { |
@@ -727,8 +736,8 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
727 | .stream_name = "Loopback Capture", | 736 | .stream_name = "Loopback Capture", |
728 | .channels_min = 2, | 737 | .channels_min = 2, |
729 | .channels_max = 2, | 738 | .channels_max = 2, |
730 | .rates = SNDRV_PCM_RATE_8000_192000, | 739 | .rates = SNDRV_PCM_RATE_48000, |
731 | .formats = HSW_FORMATS, | 740 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
732 | }, | 741 | }, |
733 | }, | 742 | }, |
734 | { | 743 | { |
@@ -737,8 +746,8 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
737 | .stream_name = "Analog Capture", | 746 | .stream_name = "Analog Capture", |
738 | .channels_min = 2, | 747 | .channels_min = 2, |
739 | .channels_max = 2, | 748 | .channels_max = 2, |
740 | .rates = SNDRV_PCM_RATE_8000_192000, | 749 | .rates = SNDRV_PCM_RATE_48000, |
741 | .formats = HSW_FORMATS, | 750 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
742 | }, | 751 | }, |
743 | }, | 752 | }, |
744 | }; | 753 | }; |
diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/sst-mfld-dsp.h index 8d482d76475a..4257263157cd 100644 --- a/sound/soc/intel/sst-mfld-dsp.h +++ b/sound/soc/intel/sst-mfld-dsp.h | |||
@@ -3,7 +3,7 @@ | |||
3 | /* | 3 | /* |
4 | * sst_mfld_dsp.h - Intel SST Driver for audio engine | 4 | * sst_mfld_dsp.h - Intel SST Driver for audio engine |
5 | * | 5 | * |
6 | * Copyright (C) 2008-12 Intel Corporation | 6 | * Copyright (C) 2008-14 Intel Corporation |
7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> | 7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> |
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
9 | * | 9 | * |
@@ -19,6 +19,142 @@ | |||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define SST_MAX_BIN_BYTES 1024 | ||
23 | |||
24 | #define MAX_DBG_RW_BYTES 80 | ||
25 | #define MAX_NUM_SCATTER_BUFFERS 8 | ||
26 | #define MAX_LOOP_BACK_DWORDS 8 | ||
27 | /* IPC base address and mailbox, timestamp offsets */ | ||
28 | #define SST_MAILBOX_SIZE 0x0400 | ||
29 | #define SST_MAILBOX_SEND 0x0000 | ||
30 | #define SST_TIME_STAMP 0x1800 | ||
31 | #define SST_TIME_STAMP_MRFLD 0x800 | ||
32 | #define SST_RESERVED_OFFSET 0x1A00 | ||
33 | #define SST_SCU_LPE_MAILBOX 0x1000 | ||
34 | #define SST_LPE_SCU_MAILBOX 0x1400 | ||
35 | #define SST_SCU_LPE_LOG_BUF (SST_SCU_LPE_MAILBOX+16) | ||
36 | #define PROCESS_MSG 0x80 | ||
37 | |||
38 | /* Message ID's for IPC messages */ | ||
39 | /* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */ | ||
40 | |||
41 | /* I2L Firmware/Codec Download msgs */ | ||
42 | #define IPC_IA_PREP_LIB_DNLD 0x01 | ||
43 | #define IPC_IA_LIB_DNLD_CMPLT 0x02 | ||
44 | #define IPC_IA_GET_FW_VERSION 0x04 | ||
45 | #define IPC_IA_GET_FW_BUILD_INF 0x05 | ||
46 | #define IPC_IA_GET_FW_INFO 0x06 | ||
47 | #define IPC_IA_GET_FW_CTXT 0x07 | ||
48 | #define IPC_IA_SET_FW_CTXT 0x08 | ||
49 | #define IPC_IA_PREPARE_SHUTDOWN 0x31 | ||
50 | /* I2L Codec Config/control msgs */ | ||
51 | #define IPC_PREP_D3 0x10 | ||
52 | #define IPC_IA_SET_CODEC_PARAMS 0x10 | ||
53 | #define IPC_IA_GET_CODEC_PARAMS 0x11 | ||
54 | #define IPC_IA_SET_PPP_PARAMS 0x12 | ||
55 | #define IPC_IA_GET_PPP_PARAMS 0x13 | ||
56 | #define IPC_SST_PERIOD_ELAPSED_MRFLD 0xA | ||
57 | #define IPC_IA_ALG_PARAMS 0x1A | ||
58 | #define IPC_IA_TUNING_PARAMS 0x1B | ||
59 | #define IPC_IA_SET_RUNTIME_PARAMS 0x1C | ||
60 | #define IPC_IA_SET_PARAMS 0x1 | ||
61 | #define IPC_IA_GET_PARAMS 0x2 | ||
62 | |||
63 | #define IPC_EFFECTS_CREATE 0xE | ||
64 | #define IPC_EFFECTS_DESTROY 0xF | ||
65 | |||
66 | /* I2L Stream config/control msgs */ | ||
67 | #define IPC_IA_ALLOC_STREAM_MRFLD 0x2 | ||
68 | #define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */ | ||
69 | #define IPC_IA_FREE_STREAM_MRFLD 0x03 | ||
70 | #define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */ | ||
71 | #define IPC_IA_SET_STREAM_PARAMS 0x22 | ||
72 | #define IPC_IA_SET_STREAM_PARAMS_MRFLD 0x12 | ||
73 | #define IPC_IA_GET_STREAM_PARAMS 0x23 | ||
74 | #define IPC_IA_PAUSE_STREAM 0x24 | ||
75 | #define IPC_IA_PAUSE_STREAM_MRFLD 0x4 | ||
76 | #define IPC_IA_RESUME_STREAM 0x25 | ||
77 | #define IPC_IA_RESUME_STREAM_MRFLD 0x5 | ||
78 | #define IPC_IA_DROP_STREAM 0x26 | ||
79 | #define IPC_IA_DROP_STREAM_MRFLD 0x07 | ||
80 | #define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */ | ||
81 | #define IPC_IA_DRAIN_STREAM_MRFLD 0x8 | ||
82 | #define IPC_IA_CONTROL_ROUTING 0x29 | ||
83 | #define IPC_IA_VTSV_UPDATE_MODULES 0x20 | ||
84 | #define IPC_IA_VTSV_DETECTED 0x21 | ||
85 | |||
86 | #define IPC_IA_START_STREAM_MRFLD 0X06 | ||
87 | #define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */ | ||
88 | |||
89 | #define IPC_IA_SET_GAIN_MRFLD 0x21 | ||
90 | /* Debug msgs */ | ||
91 | #define IPC_IA_DBG_MEM_READ 0x40 | ||
92 | #define IPC_IA_DBG_MEM_WRITE 0x41 | ||
93 | #define IPC_IA_DBG_LOOP_BACK 0x42 | ||
94 | #define IPC_IA_DBG_LOG_ENABLE 0x45 | ||
95 | #define IPC_IA_DBG_SET_PROBE_PARAMS 0x47 | ||
96 | |||
97 | /* L2I Firmware/Codec Download msgs */ | ||
98 | #define IPC_IA_FW_INIT_CMPLT 0x81 | ||
99 | #define IPC_IA_FW_INIT_CMPLT_MRFLD 0x01 | ||
100 | #define IPC_IA_FW_ASYNC_ERR_MRFLD 0x11 | ||
101 | |||
102 | /* L2I Codec Config/control msgs */ | ||
103 | #define IPC_SST_FRAGMENT_ELPASED 0x90 /* Request IA more data */ | ||
104 | |||
105 | #define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */ | ||
106 | #define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */ | ||
107 | #define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */ | ||
108 | #define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */ | ||
109 | #define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */ | ||
110 | #define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */ | ||
111 | |||
112 | #define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */ | ||
113 | /* L2S messages */ | ||
114 | #define IPC_SC_DDR_LINK_UP 0xC0 | ||
115 | #define IPC_SC_DDR_LINK_DOWN 0xC1 | ||
116 | #define IPC_SC_SET_LPECLK_REQ 0xC2 | ||
117 | #define IPC_SC_SSP_BIT_BANG 0xC3 | ||
118 | |||
119 | /* L2I Error reporting msgs */ | ||
120 | #define IPC_IA_MEM_ALLOC_FAIL 0xE0 | ||
121 | #define IPC_IA_PROC_ERR 0xE1 /* error in processing a | ||
122 | stream can be used by playback and | ||
123 | capture modules */ | ||
124 | |||
125 | /* L2I Debug msgs */ | ||
126 | #define IPC_IA_PRINT_STRING 0xF0 | ||
127 | |||
128 | /* Buffer under-run */ | ||
129 | #define IPC_IA_BUF_UNDER_RUN_MRFLD 0x0B | ||
130 | |||
131 | /* Mrfld specific defines: | ||
132 | * For asynchronous messages(INIT_CMPLT, PERIOD_ELAPSED, ASYNC_ERROR) | ||
133 | * received from FW, the format is: | ||
134 | * - IPC High: pvt_id is set to zero. Always short message. | ||
135 | * - msg_id is in lower 16-bits of IPC low payload. | ||
136 | * - pipe_id is in higher 16-bits of IPC low payload for period_elapsed. | ||
137 | * - error id is in higher 16-bits of IPC low payload for async errors. | ||
138 | */ | ||
139 | #define SST_ASYNC_DRV_ID 0 | ||
140 | |||
141 | /* Command Response or Acknowledge message to any IPC message will have | ||
142 | * same message ID and stream ID information which is sent. | ||
143 | * There is no specific Ack message ID. The data field is used as response | ||
144 | * meaning. | ||
145 | */ | ||
146 | enum ackData { | ||
147 | IPC_ACK_SUCCESS = 0, | ||
148 | IPC_ACK_FAILURE, | ||
149 | }; | ||
150 | |||
151 | enum ipc_ia_msg_id { | ||
152 | IPC_CMD = 1, /*!< Task Control message ID */ | ||
153 | IPC_SET_PARAMS = 2,/*!< Task Set param message ID */ | ||
154 | IPC_GET_PARAMS = 3, /*!< Task Get param message ID */ | ||
155 | IPC_INVALID = 0xFF, /*!<Task Get param message ID */ | ||
156 | }; | ||
157 | |||
22 | enum sst_codec_types { | 158 | enum sst_codec_types { |
23 | /* AUDIO/MUSIC CODEC Type Definitions */ | 159 | /* AUDIO/MUSIC CODEC Type Definitions */ |
24 | SST_CODEC_TYPE_UNKNOWN = 0, | 160 | SST_CODEC_TYPE_UNKNOWN = 0, |
@@ -35,14 +171,157 @@ enum stream_type { | |||
35 | SST_STREAM_TYPE_MUSIC = 1, | 171 | SST_STREAM_TYPE_MUSIC = 1, |
36 | }; | 172 | }; |
37 | 173 | ||
174 | enum sst_error_codes { | ||
175 | /* Error code,response to msgId: Description */ | ||
176 | /* Common error codes */ | ||
177 | SST_SUCCESS = 0, /* Success */ | ||
178 | SST_ERR_INVALID_STREAM_ID = 1, | ||
179 | SST_ERR_INVALID_MSG_ID = 2, | ||
180 | SST_ERR_INVALID_STREAM_OP = 3, | ||
181 | SST_ERR_INVALID_PARAMS = 4, | ||
182 | SST_ERR_INVALID_CODEC = 5, | ||
183 | SST_ERR_INVALID_MEDIA_TYPE = 6, | ||
184 | SST_ERR_STREAM_ERR = 7, | ||
185 | |||
186 | SST_ERR_STREAM_IN_USE = 15, | ||
187 | }; | ||
188 | |||
189 | struct ipc_dsp_hdr { | ||
190 | u16 mod_index_id:8; /*!< DSP Command ID specific to tasks */ | ||
191 | u16 pipe_id:8; /*!< instance of the module in the pipeline */ | ||
192 | u16 mod_id; /*!< Pipe_id */ | ||
193 | u16 cmd_id; /*!< Module ID = lpe_algo_types_t */ | ||
194 | u16 length; /*!< Length of the payload only */ | ||
195 | } __packed; | ||
196 | |||
197 | union ipc_header_high { | ||
198 | struct { | ||
199 | u32 msg_id:8; /* Message ID - Max 256 Message Types */ | ||
200 | u32 task_id:4; /* Task ID associated with this comand */ | ||
201 | u32 drv_id:4; /* Identifier for the driver to track*/ | ||
202 | u32 rsvd1:8; /* Reserved */ | ||
203 | u32 result:4; /* Reserved */ | ||
204 | u32 res_rqd:1; /* Response rqd */ | ||
205 | u32 large:1; /* Large Message if large = 1 */ | ||
206 | u32 done:1; /* bit 30 - Done bit */ | ||
207 | u32 busy:1; /* bit 31 - busy bit*/ | ||
208 | } part; | ||
209 | u32 full; | ||
210 | } __packed; | ||
211 | /* IPC header */ | ||
212 | union ipc_header_mrfld { | ||
213 | struct { | ||
214 | u32 header_low_payload; | ||
215 | union ipc_header_high header_high; | ||
216 | } p; | ||
217 | u64 full; | ||
218 | } __packed; | ||
219 | /* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/ | ||
220 | |||
221 | /* IPC Header */ | ||
222 | union ipc_header { | ||
223 | struct { | ||
224 | u32 msg_id:8; /* Message ID - Max 256 Message Types */ | ||
225 | u32 str_id:5; | ||
226 | u32 large:1; /* Large Message if large = 1 */ | ||
227 | u32 reserved:2; /* Reserved for future use */ | ||
228 | u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */ | ||
229 | u32 done:1; /* bit 30 */ | ||
230 | u32 busy:1; /* bit 31 */ | ||
231 | } part; | ||
232 | u32 full; | ||
233 | } __packed; | ||
234 | |||
235 | /* Firmware build info */ | ||
236 | struct sst_fw_build_info { | ||
237 | unsigned char date[16]; /* Firmware build date */ | ||
238 | unsigned char time[16]; /* Firmware build time */ | ||
239 | } __packed; | ||
240 | |||
241 | /* Firmware Version info */ | ||
242 | struct snd_sst_fw_version { | ||
243 | u8 build; /* build number*/ | ||
244 | u8 minor; /* minor number*/ | ||
245 | u8 major; /* major number*/ | ||
246 | u8 type; /* build type */ | ||
247 | }; | ||
248 | |||
249 | struct ipc_header_fw_init { | ||
250 | struct snd_sst_fw_version fw_version;/* Firmware version details */ | ||
251 | struct sst_fw_build_info build_info; | ||
252 | u16 result; /* Fw init result */ | ||
253 | u8 module_id; /* Module ID in case of error */ | ||
254 | u8 debug_info; /* Debug info from Module ID in case of fail */ | ||
255 | } __packed; | ||
256 | |||
257 | struct snd_sst_tstamp { | ||
258 | u64 ring_buffer_counter; /* PB/CP: Bytes copied from/to DDR. */ | ||
259 | u64 hardware_counter; /* PB/CP: Bytes DMAed to/from SSP. */ | ||
260 | u64 frames_decoded; | ||
261 | u64 bytes_decoded; | ||
262 | u64 bytes_copied; | ||
263 | u32 sampling_frequency; | ||
264 | u32 channel_peak[8]; | ||
265 | } __packed; | ||
266 | |||
267 | /* Stream type params struture for Alloc stream */ | ||
268 | struct snd_sst_str_type { | ||
269 | u8 codec_type; /* Codec type */ | ||
270 | u8 str_type; /* 1 = voice 2 = music */ | ||
271 | u8 operation; /* Playback or Capture */ | ||
272 | u8 protected_str; /* 0=Non DRM, 1=DRM */ | ||
273 | u8 time_slots; | ||
274 | u8 reserved; /* Reserved */ | ||
275 | u16 result; /* Result used for acknowledgment */ | ||
276 | } __packed; | ||
277 | |||
278 | /* Library info structure */ | ||
279 | struct module_info { | ||
280 | u32 lib_version; | ||
281 | u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/ | ||
282 | u32 media_type; | ||
283 | u8 lib_name[12]; | ||
284 | u32 lib_caps; | ||
285 | unsigned char b_date[16]; /* Lib build date */ | ||
286 | unsigned char b_time[16]; /* Lib build time */ | ||
287 | } __packed; | ||
288 | |||
289 | /* Library slot info */ | ||
290 | struct lib_slot_info { | ||
291 | u8 slot_num; /* 1 or 2 */ | ||
292 | u8 reserved1; | ||
293 | u16 reserved2; | ||
294 | u32 iram_size; /* slot size in IRAM */ | ||
295 | u32 dram_size; /* slot size in DRAM */ | ||
296 | u32 iram_offset; /* starting offset of slot in IRAM */ | ||
297 | u32 dram_offset; /* starting offset of slot in DRAM */ | ||
298 | } __packed; | ||
299 | |||
300 | struct snd_ppp_mixer_params { | ||
301 | __u32 type; /*Type of the parameter */ | ||
302 | __u32 size; | ||
303 | __u32 input_stream_bitmap; /*Input stream Bit Map*/ | ||
304 | } __packed; | ||
305 | |||
306 | struct snd_sst_lib_download { | ||
307 | struct module_info lib_info; /* library info type, capabilities etc */ | ||
308 | struct lib_slot_info slot_info; /* slot info to be downloaded */ | ||
309 | u32 mod_entry_pt; | ||
310 | }; | ||
311 | |||
312 | struct snd_sst_lib_download_info { | ||
313 | struct snd_sst_lib_download dload_lib; | ||
314 | u16 result; /* Result used for acknowledgment */ | ||
315 | u8 pvt_id; /* Private ID */ | ||
316 | u8 reserved; /* for alignment */ | ||
317 | }; | ||
38 | struct snd_pcm_params { | 318 | struct snd_pcm_params { |
39 | u8 num_chan; /* 1=Mono, 2=Stereo */ | 319 | u8 num_chan; /* 1=Mono, 2=Stereo */ |
40 | u8 pcm_wd_sz; /* 16/24 - bit*/ | 320 | u8 pcm_wd_sz; /* 16/24 - bit*/ |
41 | u32 reserved; /* Bitrate in bits per second */ | 321 | u8 use_offload_path; /* 0-PCM using period elpased & ALSA interfaces |
42 | u32 sfreq; /* Sampling rate in Hz */ | 322 | 1-PCM stream via compressed interface */ |
43 | u8 use_offload_path; | ||
44 | u8 reserved2; | 323 | u8 reserved2; |
45 | u16 reserved3; | 324 | u32 sfreq; /* Sampling rate in Hz */ |
46 | u8 channel_map[8]; | 325 | u8 channel_map[8]; |
47 | } __packed; | 326 | } __packed; |
48 | 327 | ||
@@ -76,6 +355,7 @@ struct snd_aac_params { | |||
76 | struct snd_wma_params { | 355 | struct snd_wma_params { |
77 | u8 num_chan; /* 1=Mono, 2=Stereo */ | 356 | u8 num_chan; /* 1=Mono, 2=Stereo */ |
78 | u8 pcm_wd_sz; /* 16/24 - bit*/ | 357 | u8 pcm_wd_sz; /* 16/24 - bit*/ |
358 | u16 reserved1; | ||
79 | u32 brate; /* Use the hard coded value. */ | 359 | u32 brate; /* Use the hard coded value. */ |
80 | u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ | 360 | u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ |
81 | u32 channel_mask; /* Channel Mask */ | 361 | u32 channel_mask; /* Channel Mask */ |
@@ -101,26 +381,153 @@ struct sst_address_info { | |||
101 | }; | 381 | }; |
102 | 382 | ||
103 | struct snd_sst_alloc_params_ext { | 383 | struct snd_sst_alloc_params_ext { |
104 | struct sst_address_info ring_buf_info[8]; | 384 | __u16 sg_count; |
105 | u8 sg_count; | 385 | __u16 reserved; |
106 | u8 reserved; | 386 | __u32 frag_size; /*Number of samples after which period elapsed |
107 | u16 reserved2; | ||
108 | u32 frag_size; /*Number of samples after which period elapsed | ||
109 | message is sent valid only if path = 0*/ | 387 | message is sent valid only if path = 0*/ |
110 | } __packed; | 388 | struct sst_address_info ring_buf_info[8]; |
389 | }; | ||
111 | 390 | ||
112 | struct snd_sst_stream_params { | 391 | struct snd_sst_stream_params { |
113 | union snd_sst_codec_params uc; | 392 | union snd_sst_codec_params uc; |
114 | } __packed; | 393 | } __packed; |
115 | 394 | ||
116 | struct snd_sst_params { | 395 | struct snd_sst_params { |
396 | u32 result; | ||
117 | u32 stream_id; | 397 | u32 stream_id; |
118 | u8 codec; | 398 | u8 codec; |
119 | u8 ops; | 399 | u8 ops; |
120 | u8 stream_type; | 400 | u8 stream_type; |
121 | u8 device_type; | 401 | u8 device_type; |
402 | u8 task; | ||
122 | struct snd_sst_stream_params sparams; | 403 | struct snd_sst_stream_params sparams; |
123 | struct snd_sst_alloc_params_ext aparams; | 404 | struct snd_sst_alloc_params_ext aparams; |
124 | }; | 405 | }; |
125 | 406 | ||
407 | struct snd_sst_alloc_mrfld { | ||
408 | u16 codec_type; | ||
409 | u8 operation; | ||
410 | u8 sg_count; | ||
411 | struct sst_address_info ring_buf_info[8]; | ||
412 | u32 frag_size; | ||
413 | u32 ts; | ||
414 | struct snd_sst_stream_params codec_params; | ||
415 | } __packed; | ||
416 | |||
417 | /* Alloc stream params structure */ | ||
418 | struct snd_sst_alloc_params { | ||
419 | struct snd_sst_str_type str_type; | ||
420 | struct snd_sst_stream_params stream_params; | ||
421 | struct snd_sst_alloc_params_ext alloc_params; | ||
422 | } __packed; | ||
423 | |||
424 | /* Alloc stream response message */ | ||
425 | struct snd_sst_alloc_response { | ||
426 | struct snd_sst_str_type str_type; /* Stream type for allocation */ | ||
427 | struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */ | ||
428 | }; | ||
429 | |||
430 | /* Drop response */ | ||
431 | struct snd_sst_drop_response { | ||
432 | u32 result; | ||
433 | u32 bytes; | ||
434 | }; | ||
435 | |||
436 | struct snd_sst_async_msg { | ||
437 | u32 msg_id; /* Async msg id */ | ||
438 | u32 payload[0]; | ||
439 | }; | ||
440 | |||
441 | struct snd_sst_async_err_msg { | ||
442 | u32 fw_resp; /* Firmware Result */ | ||
443 | u32 lib_resp; /*Library result */ | ||
444 | } __packed; | ||
445 | |||
446 | struct snd_sst_vol { | ||
447 | u32 stream_id; | ||
448 | s32 volume; | ||
449 | u32 ramp_duration; | ||
450 | u32 ramp_type; /* Ramp type, default=0 */ | ||
451 | }; | ||
452 | |||
453 | /* Gain library parameters for mrfld | ||
454 | * based on DSP command spec v0.82 | ||
455 | */ | ||
456 | struct snd_sst_gain_v2 { | ||
457 | u16 gain_cell_num; /* num of gain cells to modify*/ | ||
458 | u8 cell_nbr_idx; /* instance index*/ | ||
459 | u8 cell_path_idx; /* pipe-id */ | ||
460 | u16 module_id; /*module id */ | ||
461 | u16 left_cell_gain; /* left gain value in dB*/ | ||
462 | u16 right_cell_gain; /* right gain value in dB*/ | ||
463 | u16 gain_time_const; /* gain time constant*/ | ||
464 | } __packed; | ||
465 | |||
466 | struct snd_sst_mute { | ||
467 | u32 stream_id; | ||
468 | u32 mute; | ||
469 | }; | ||
470 | |||
471 | struct snd_sst_runtime_params { | ||
472 | u8 type; | ||
473 | u8 str_id; | ||
474 | u8 size; | ||
475 | u8 rsvd; | ||
476 | void *addr; | ||
477 | } __packed; | ||
478 | |||
479 | enum stream_param_type { | ||
480 | SST_SET_TIME_SLOT = 0, | ||
481 | SST_SET_CHANNEL_INFO = 1, | ||
482 | OTHERS = 2, /*reserved for future params*/ | ||
483 | }; | ||
484 | |||
485 | /* CSV Voice call routing structure */ | ||
486 | struct snd_sst_control_routing { | ||
487 | u8 control; /* 0=start, 1=Stop */ | ||
488 | u8 reserved[3]; /* Reserved- for 32 bit alignment */ | ||
489 | }; | ||
490 | |||
491 | struct ipc_post { | ||
492 | struct list_head node; | ||
493 | union ipc_header header; /* driver specific */ | ||
494 | bool is_large; | ||
495 | bool is_process_reply; | ||
496 | union ipc_header_mrfld mrfld_header; | ||
497 | char *mailbox_data; | ||
498 | }; | ||
499 | |||
500 | struct snd_sst_ctxt_params { | ||
501 | u32 address; /* Physical Address in DDR where the context is stored */ | ||
502 | u32 size; /* size of the context */ | ||
503 | }; | ||
504 | |||
505 | struct snd_sst_lpe_log_params { | ||
506 | u8 dbg_type; | ||
507 | u8 module_id; | ||
508 | u8 log_level; | ||
509 | u8 reserved; | ||
510 | } __packed; | ||
511 | |||
512 | enum snd_sst_bytes_type { | ||
513 | SND_SST_BYTES_SET = 0x1, | ||
514 | SND_SST_BYTES_GET = 0x2, | ||
515 | }; | ||
516 | |||
517 | struct snd_sst_bytes_v2 { | ||
518 | u8 type; | ||
519 | u8 ipc_msg; | ||
520 | u8 block; | ||
521 | u8 task_id; | ||
522 | u8 pipe_id; | ||
523 | u8 rsvd; | ||
524 | u16 len; | ||
525 | char bytes[0]; | ||
526 | }; | ||
527 | |||
528 | #define MAX_VTSV_FILES 2 | ||
529 | struct snd_sst_vtsv_info { | ||
530 | struct sst_address_info vfiles[MAX_VTSV_FILES]; | ||
531 | } __packed; | ||
532 | |||
126 | #endif /* __SST_MFLD_DSP_H__ */ | 533 | #endif /* __SST_MFLD_DSP_H__ */ |
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 02abd19fce1d..29c059ca19e8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c | |||
@@ -100,14 +100,19 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, | |||
100 | int retval; | 100 | int retval; |
101 | struct snd_sst_params str_params; | 101 | struct snd_sst_params str_params; |
102 | struct sst_compress_cb cb; | 102 | struct sst_compress_cb cb; |
103 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
104 | struct snd_soc_platform *platform = rtd->platform; | ||
105 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | ||
103 | 106 | ||
104 | stream = cstream->runtime->private_data; | 107 | stream = cstream->runtime->private_data; |
105 | /* construct fw structure for this*/ | 108 | /* construct fw structure for this*/ |
106 | memset(&str_params, 0, sizeof(str_params)); | 109 | memset(&str_params, 0, sizeof(str_params)); |
107 | 110 | ||
108 | str_params.ops = STREAM_OPS_PLAYBACK; | 111 | /* fill the device type and stream id to pass to SST driver */ |
109 | str_params.stream_type = SST_STREAM_TYPE_MUSIC; | 112 | retval = sst_fill_stream_params(cstream, ctx, &str_params, true); |
110 | str_params.device_type = SND_SST_DEVICE_COMPRESS; | 113 | pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval); |
114 | if (retval < 0) | ||
115 | return retval; | ||
111 | 116 | ||
112 | switch (params->codec.id) { | 117 | switch (params->codec.id) { |
113 | case SND_AUDIOCODEC_MP3: { | 118 | case SND_AUDIOCODEC_MP3: { |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7c790f51d259..706212a6a68c 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * sst_mfld_platform.c - Intel MID Platform driver | 2 | * sst_mfld_platform.c - Intel MID Platform driver |
3 | * | 3 | * |
4 | * Copyright (C) 2010-2013 Intel Corp | 4 | * Copyright (C) 2010-2014 Intel Corp |
5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
6 | * Author: Harsha Priya <priya.harsha@intel.com> | 6 | * Author: Harsha Priya <priya.harsha@intel.com> |
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
@@ -27,7 +27,9 @@ | |||
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | #include <sound/compress_driver.h> | 29 | #include <sound/compress_driver.h> |
30 | #include <asm/platform_sst_audio.h> | ||
30 | #include "sst-mfld-platform.h" | 31 | #include "sst-mfld-platform.h" |
32 | #include "sst-atom-controls.h" | ||
31 | 33 | ||
32 | struct sst_device *sst; | 34 | struct sst_device *sst; |
33 | static DEFINE_MUTEX(sst_lock); | 35 | static DEFINE_MUTEX(sst_lock); |
@@ -92,6 +94,13 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = { | |||
92 | .fifo_size = SST_FIFO_SIZE, | 94 | .fifo_size = SST_FIFO_SIZE, |
93 | }; | 95 | }; |
94 | 96 | ||
97 | static struct sst_dev_stream_map dpcm_strm_map[] = { | ||
98 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */ | ||
99 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0}, | ||
100 | {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0}, | ||
101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, | ||
102 | }; | ||
103 | |||
95 | /* MFLD - MSIC */ | 104 | /* MFLD - MSIC */ |
96 | static struct snd_soc_dai_driver sst_platform_dai[] = { | 105 | static struct snd_soc_dai_driver sst_platform_dai[] = { |
97 | { | 106 | { |
@@ -143,58 +152,142 @@ static inline int sst_get_stream_status(struct sst_runtime_stream *stream) | |||
143 | return state; | 152 | return state; |
144 | } | 153 | } |
145 | 154 | ||
155 | static void sst_fill_alloc_params(struct snd_pcm_substream *substream, | ||
156 | struct snd_sst_alloc_params_ext *alloc_param) | ||
157 | { | ||
158 | unsigned int channels; | ||
159 | snd_pcm_uframes_t period_size; | ||
160 | ssize_t periodbytes; | ||
161 | ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream); | ||
162 | u32 buffer_addr = virt_to_phys(substream->dma_buffer.area); | ||
163 | |||
164 | channels = substream->runtime->channels; | ||
165 | period_size = substream->runtime->period_size; | ||
166 | periodbytes = samples_to_bytes(substream->runtime, period_size); | ||
167 | alloc_param->ring_buf_info[0].addr = buffer_addr; | ||
168 | alloc_param->ring_buf_info[0].size = buffer_bytes; | ||
169 | alloc_param->sg_count = 1; | ||
170 | alloc_param->reserved = 0; | ||
171 | alloc_param->frag_size = periodbytes * channels; | ||
172 | |||
173 | } | ||
146 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, | 174 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, |
147 | struct sst_pcm_params *param) | 175 | struct snd_sst_stream_params *param) |
148 | { | 176 | { |
177 | param->uc.pcm_params.num_chan = (u8) substream->runtime->channels; | ||
178 | param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; | ||
179 | param->uc.pcm_params.sfreq = substream->runtime->rate; | ||
180 | |||
181 | /* PCM stream via ALSA interface */ | ||
182 | param->uc.pcm_params.use_offload_path = 0; | ||
183 | param->uc.pcm_params.reserved2 = 0; | ||
184 | memset(param->uc.pcm_params.channel_map, 0, sizeof(u8)); | ||
149 | 185 | ||
150 | param->num_chan = (u8) substream->runtime->channels; | ||
151 | param->pcm_wd_sz = substream->runtime->sample_bits; | ||
152 | param->reserved = 0; | ||
153 | param->sfreq = substream->runtime->rate; | ||
154 | param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
155 | param->period_count = substream->runtime->period_size; | ||
156 | param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area); | ||
157 | pr_debug("period_cnt = %d\n", param->period_count); | ||
158 | pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz); | ||
159 | } | 186 | } |
160 | 187 | ||
161 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream) | 188 | static int sst_get_stream_mapping(int dev, int sdev, int dir, |
189 | struct sst_dev_stream_map *map, int size) | ||
190 | { | ||
191 | int i; | ||
192 | |||
193 | if (map == NULL) | ||
194 | return -EINVAL; | ||
195 | |||
196 | |||
197 | /* index 0 is not used in stream map */ | ||
198 | for (i = 1; i < size; i++) { | ||
199 | if ((map[i].dev_num == dev) && (map[i].direction == dir)) | ||
200 | return i; | ||
201 | } | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | int sst_fill_stream_params(void *substream, | ||
206 | const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress) | ||
207 | { | ||
208 | int map_size; | ||
209 | int index; | ||
210 | struct sst_dev_stream_map *map; | ||
211 | struct snd_pcm_substream *pstream = NULL; | ||
212 | struct snd_compr_stream *cstream = NULL; | ||
213 | |||
214 | map = ctx->pdata->pdev_strm_map; | ||
215 | map_size = ctx->pdata->strm_map_size; | ||
216 | |||
217 | if (is_compress == true) | ||
218 | cstream = (struct snd_compr_stream *)substream; | ||
219 | else | ||
220 | pstream = (struct snd_pcm_substream *)substream; | ||
221 | |||
222 | str_params->stream_type = SST_STREAM_TYPE_MUSIC; | ||
223 | |||
224 | /* For pcm streams */ | ||
225 | if (pstream) { | ||
226 | index = sst_get_stream_mapping(pstream->pcm->device, | ||
227 | pstream->number, pstream->stream, | ||
228 | map, map_size); | ||
229 | if (index <= 0) | ||
230 | return -EINVAL; | ||
231 | |||
232 | str_params->stream_id = index; | ||
233 | str_params->device_type = map[index].device_id; | ||
234 | str_params->task = map[index].task_id; | ||
235 | |||
236 | str_params->ops = (u8)pstream->stream; | ||
237 | } | ||
238 | |||
239 | if (cstream) { | ||
240 | index = sst_get_stream_mapping(cstream->device->device, | ||
241 | 0, cstream->direction, | ||
242 | map, map_size); | ||
243 | if (index <= 0) | ||
244 | return -EINVAL; | ||
245 | str_params->stream_id = index; | ||
246 | str_params->device_type = map[index].device_id; | ||
247 | str_params->task = map[index].task_id; | ||
248 | |||
249 | str_params->ops = (u8)cstream->direction; | ||
250 | } | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, | ||
255 | struct snd_soc_platform *platform) | ||
162 | { | 256 | { |
163 | struct sst_runtime_stream *stream = | 257 | struct sst_runtime_stream *stream = |
164 | substream->runtime->private_data; | 258 | substream->runtime->private_data; |
165 | struct sst_pcm_params param = {0}; | 259 | struct snd_sst_stream_params param = {{{0,},},}; |
166 | struct sst_stream_params str_params = {0}; | 260 | struct snd_sst_params str_params = {0}; |
167 | int ret_val; | 261 | struct snd_sst_alloc_params_ext alloc_params = {0}; |
262 | int ret_val = 0; | ||
263 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | ||
168 | 264 | ||
169 | /* set codec params and inform SST driver the same */ | 265 | /* set codec params and inform SST driver the same */ |
170 | sst_fill_pcm_params(substream, ¶m); | 266 | sst_fill_pcm_params(substream, ¶m); |
267 | sst_fill_alloc_params(substream, &alloc_params); | ||
171 | substream->runtime->dma_area = substream->dma_buffer.area; | 268 | substream->runtime->dma_area = substream->dma_buffer.area; |
172 | str_params.sparams = param; | 269 | str_params.sparams = param; |
173 | str_params.codec = param.codec; | 270 | str_params.aparams = alloc_params; |
174 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 271 | str_params.codec = SST_CODEC_TYPE_PCM; |
175 | str_params.ops = STREAM_OPS_PLAYBACK; | 272 | |
176 | str_params.device_type = substream->pcm->device + 1; | 273 | /* fill the device type and stream id to pass to SST driver */ |
177 | pr_debug("Playbck stream,Device %d\n", | 274 | ret_val = sst_fill_stream_params(substream, ctx, &str_params, false); |
178 | substream->pcm->device); | ||
179 | } else { | ||
180 | str_params.ops = STREAM_OPS_CAPTURE; | ||
181 | str_params.device_type = SND_SST_DEVICE_CAPTURE; | ||
182 | pr_debug("Capture stream,Device %d\n", | ||
183 | substream->pcm->device); | ||
184 | } | ||
185 | ret_val = stream->ops->open(&str_params); | ||
186 | pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); | ||
187 | if (ret_val < 0) | 275 | if (ret_val < 0) |
188 | return ret_val; | 276 | return ret_val; |
189 | 277 | ||
190 | stream->stream_info.str_id = ret_val; | 278 | stream->stream_info.str_id = str_params.stream_id; |
191 | pr_debug("str id : %d\n", stream->stream_info.str_id); | 279 | |
280 | ret_val = stream->ops->open(&str_params); | ||
281 | if (ret_val <= 0) | ||
282 | return ret_val; | ||
283 | |||
284 | |||
192 | return ret_val; | 285 | return ret_val; |
193 | } | 286 | } |
194 | 287 | ||
195 | static void sst_period_elapsed(void *mad_substream) | 288 | static void sst_period_elapsed(void *arg) |
196 | { | 289 | { |
197 | struct snd_pcm_substream *substream = mad_substream; | 290 | struct snd_pcm_substream *substream = arg; |
198 | struct sst_runtime_stream *stream; | 291 | struct sst_runtime_stream *stream; |
199 | int status; | 292 | int status; |
200 | 293 | ||
@@ -218,7 +311,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
218 | pr_debug("setting buffer ptr param\n"); | 311 | pr_debug("setting buffer ptr param\n"); |
219 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 312 | sst_set_stream_status(stream, SST_PLATFORM_INIT); |
220 | stream->stream_info.period_elapsed = sst_period_elapsed; | 313 | stream->stream_info.period_elapsed = sst_period_elapsed; |
221 | stream->stream_info.mad_substream = substream; | 314 | stream->stream_info.arg = substream; |
222 | stream->stream_info.buffer_ptr = 0; | 315 | stream->stream_info.buffer_ptr = 0; |
223 | stream->stream_info.sfreq = substream->runtime->rate; | 316 | stream->stream_info.sfreq = substream->runtime->rate; |
224 | ret_val = stream->ops->device_control( | 317 | ret_val = stream->ops->device_control( |
@@ -230,19 +323,12 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
230 | } | 323 | } |
231 | /* end -- helper functions */ | 324 | /* end -- helper functions */ |
232 | 325 | ||
233 | static int sst_platform_open(struct snd_pcm_substream *substream) | 326 | static int sst_media_open(struct snd_pcm_substream *substream, |
327 | struct snd_soc_dai *dai) | ||
234 | { | 328 | { |
329 | int ret_val = 0; | ||
235 | struct snd_pcm_runtime *runtime = substream->runtime; | 330 | struct snd_pcm_runtime *runtime = substream->runtime; |
236 | struct sst_runtime_stream *stream; | 331 | struct sst_runtime_stream *stream; |
237 | int ret_val; | ||
238 | |||
239 | pr_debug("sst_platform_open called\n"); | ||
240 | |||
241 | snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw); | ||
242 | ret_val = snd_pcm_hw_constraint_integer(runtime, | ||
243 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
244 | if (ret_val < 0) | ||
245 | return ret_val; | ||
246 | 332 | ||
247 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 333 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
248 | if (!stream) | 334 | if (!stream) |
@@ -251,50 +337,69 @@ static int sst_platform_open(struct snd_pcm_substream *substream) | |||
251 | 337 | ||
252 | /* get the sst ops */ | 338 | /* get the sst ops */ |
253 | mutex_lock(&sst_lock); | 339 | mutex_lock(&sst_lock); |
254 | if (!sst) { | 340 | if (!sst || |
341 | !try_module_get(sst->dev->driver->owner)) { | ||
255 | pr_err("no device available to run\n"); | 342 | pr_err("no device available to run\n"); |
256 | mutex_unlock(&sst_lock); | 343 | ret_val = -ENODEV; |
257 | kfree(stream); | 344 | goto out_ops; |
258 | return -ENODEV; | ||
259 | } | ||
260 | if (!try_module_get(sst->dev->driver->owner)) { | ||
261 | mutex_unlock(&sst_lock); | ||
262 | kfree(stream); | ||
263 | return -ENODEV; | ||
264 | } | 345 | } |
265 | stream->ops = sst->ops; | 346 | stream->ops = sst->ops; |
266 | mutex_unlock(&sst_lock); | 347 | mutex_unlock(&sst_lock); |
267 | 348 | ||
268 | stream->stream_info.str_id = 0; | 349 | stream->stream_info.str_id = 0; |
269 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 350 | |
270 | stream->stream_info.mad_substream = substream; | 351 | stream->stream_info.arg = substream; |
271 | /* allocate memory for SST API set */ | 352 | /* allocate memory for SST API set */ |
272 | runtime->private_data = stream; | 353 | runtime->private_data = stream; |
273 | 354 | ||
274 | return 0; | 355 | /* Make sure, that the period size is always even */ |
356 | snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
357 | SNDRV_PCM_HW_PARAM_PERIODS, 2); | ||
358 | |||
359 | return snd_pcm_hw_constraint_integer(runtime, | ||
360 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
361 | out_ops: | ||
362 | kfree(stream); | ||
363 | mutex_unlock(&sst_lock); | ||
364 | return ret_val; | ||
275 | } | 365 | } |
276 | 366 | ||
277 | static int sst_platform_close(struct snd_pcm_substream *substream) | 367 | static void sst_media_close(struct snd_pcm_substream *substream, |
368 | struct snd_soc_dai *dai) | ||
278 | { | 369 | { |
279 | struct sst_runtime_stream *stream; | 370 | struct sst_runtime_stream *stream; |
280 | int ret_val = 0, str_id; | 371 | int ret_val = 0, str_id; |
281 | 372 | ||
282 | pr_debug("sst_platform_close called\n"); | ||
283 | stream = substream->runtime->private_data; | 373 | stream = substream->runtime->private_data; |
284 | str_id = stream->stream_info.str_id; | 374 | str_id = stream->stream_info.str_id; |
285 | if (str_id) | 375 | if (str_id) |
286 | ret_val = stream->ops->close(str_id); | 376 | ret_val = stream->ops->close(str_id); |
287 | module_put(sst->dev->driver->owner); | 377 | module_put(sst->dev->driver->owner); |
288 | kfree(stream); | 378 | kfree(stream); |
289 | return ret_val; | ||
290 | } | 379 | } |
291 | 380 | ||
292 | static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | 381 | static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, |
382 | struct snd_pcm_substream *substream) | ||
383 | { | ||
384 | struct sst_data *sst = snd_soc_platform_get_drvdata(platform); | ||
385 | struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; | ||
386 | struct sst_runtime_stream *stream = | ||
387 | substream->runtime->private_data; | ||
388 | u32 str_id = stream->stream_info.str_id; | ||
389 | unsigned int pipe_id; | ||
390 | pipe_id = map[str_id].device_id; | ||
391 | |||
392 | pr_debug("%s: got pipe_id = %#x for str_id = %d\n", | ||
393 | __func__, pipe_id, str_id); | ||
394 | return pipe_id; | ||
395 | } | ||
396 | |||
397 | static int sst_media_prepare(struct snd_pcm_substream *substream, | ||
398 | struct snd_soc_dai *dai) | ||
293 | { | 399 | { |
294 | struct sst_runtime_stream *stream; | 400 | struct sst_runtime_stream *stream; |
295 | int ret_val = 0, str_id; | 401 | int ret_val = 0, str_id; |
296 | 402 | ||
297 | pr_debug("sst_platform_pcm_prepare called\n"); | ||
298 | stream = substream->runtime->private_data; | 403 | stream = substream->runtime->private_data; |
299 | str_id = stream->stream_info.str_id; | 404 | str_id = stream->stream_info.str_id; |
300 | if (stream->stream_info.str_id) { | 405 | if (stream->stream_info.str_id) { |
@@ -303,8 +408,8 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | |||
303 | return ret_val; | 408 | return ret_val; |
304 | } | 409 | } |
305 | 410 | ||
306 | ret_val = sst_platform_alloc_stream(substream); | 411 | ret_val = sst_platform_alloc_stream(substream, dai->platform); |
307 | if (ret_val < 0) | 412 | if (ret_val <= 0) |
308 | return ret_val; | 413 | return ret_val; |
309 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), | 414 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), |
310 | "%d", stream->stream_info.str_id); | 415 | "%d", stream->stream_info.str_id); |
@@ -316,6 +421,41 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | |||
316 | return ret_val; | 421 | return ret_val; |
317 | } | 422 | } |
318 | 423 | ||
424 | static int sst_media_hw_params(struct snd_pcm_substream *substream, | ||
425 | struct snd_pcm_hw_params *params, | ||
426 | struct snd_soc_dai *dai) | ||
427 | { | ||
428 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
429 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int sst_media_hw_free(struct snd_pcm_substream *substream, | ||
434 | struct snd_soc_dai *dai) | ||
435 | { | ||
436 | return snd_pcm_lib_free_pages(substream); | ||
437 | } | ||
438 | |||
439 | static struct snd_soc_dai_ops sst_media_dai_ops = { | ||
440 | .startup = sst_media_open, | ||
441 | .shutdown = sst_media_close, | ||
442 | .prepare = sst_media_prepare, | ||
443 | .hw_params = sst_media_hw_params, | ||
444 | .hw_free = sst_media_hw_free, | ||
445 | }; | ||
446 | |||
447 | static int sst_platform_open(struct snd_pcm_substream *substream) | ||
448 | { | ||
449 | struct snd_pcm_runtime *runtime; | ||
450 | |||
451 | if (substream->pcm->internal) | ||
452 | return 0; | ||
453 | |||
454 | runtime = substream->runtime; | ||
455 | runtime->hw = sst_platform_pcm_hw; | ||
456 | return 0; | ||
457 | } | ||
458 | |||
319 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | 459 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, |
320 | int cmd) | 460 | int cmd) |
321 | { | 461 | { |
@@ -331,7 +471,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
331 | pr_debug("sst: Trigger Start\n"); | 471 | pr_debug("sst: Trigger Start\n"); |
332 | str_cmd = SST_SND_START; | 472 | str_cmd = SST_SND_START; |
333 | status = SST_PLATFORM_RUNNING; | 473 | status = SST_PLATFORM_RUNNING; |
334 | stream->stream_info.mad_substream = substream; | 474 | stream->stream_info.arg = substream; |
335 | break; | 475 | break; |
336 | case SNDRV_PCM_TRIGGER_STOP: | 476 | case SNDRV_PCM_TRIGGER_STOP: |
337 | pr_debug("sst: in stop\n"); | 477 | pr_debug("sst: in stop\n"); |
@@ -377,32 +517,15 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer | |||
377 | pr_err("sst: error code = %d\n", ret_val); | 517 | pr_err("sst: error code = %d\n", ret_val); |
378 | return ret_val; | 518 | return ret_val; |
379 | } | 519 | } |
380 | return stream->stream_info.buffer_ptr; | 520 | substream->runtime->delay = str_info->pcm_delay; |
381 | } | 521 | return str_info->buffer_ptr; |
382 | |||
383 | static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, | ||
384 | struct snd_pcm_hw_params *params) | ||
385 | { | ||
386 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
387 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) | ||
393 | { | ||
394 | return snd_pcm_lib_free_pages(substream); | ||
395 | } | 522 | } |
396 | 523 | ||
397 | static struct snd_pcm_ops sst_platform_ops = { | 524 | static struct snd_pcm_ops sst_platform_ops = { |
398 | .open = sst_platform_open, | 525 | .open = sst_platform_open, |
399 | .close = sst_platform_close, | ||
400 | .ioctl = snd_pcm_lib_ioctl, | 526 | .ioctl = snd_pcm_lib_ioctl, |
401 | .prepare = sst_platform_pcm_prepare, | ||
402 | .trigger = sst_platform_pcm_trigger, | 527 | .trigger = sst_platform_pcm_trigger, |
403 | .pointer = sst_platform_pcm_pointer, | 528 | .pointer = sst_platform_pcm_pointer, |
404 | .hw_params = sst_platform_pcm_hw_params, | ||
405 | .hw_free = sst_platform_pcm_hw_free, | ||
406 | }; | 529 | }; |
407 | 530 | ||
408 | static void sst_pcm_free(struct snd_pcm *pcm) | 531 | static void sst_pcm_free(struct snd_pcm *pcm) |
@@ -413,15 +536,15 @@ static void sst_pcm_free(struct snd_pcm *pcm) | |||
413 | 536 | ||
414 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) | 537 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) |
415 | { | 538 | { |
539 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
416 | struct snd_pcm *pcm = rtd->pcm; | 540 | struct snd_pcm *pcm = rtd->pcm; |
417 | int retval = 0; | 541 | int retval = 0; |
418 | 542 | ||
419 | pr_debug("sst_pcm_new called\n"); | 543 | if (dai->driver->playback.channels_min || |
420 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | 544 | dai->driver->capture.channels_min) { |
421 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
422 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, | 545 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, |
423 | SNDRV_DMA_TYPE_CONTINUOUS, | 546 | SNDRV_DMA_TYPE_CONTINUOUS, |
424 | snd_dma_continuous_data(GFP_KERNEL), | 547 | snd_dma_continuous_data(GFP_DMA), |
425 | SST_MIN_BUFFER, SST_MAX_BUFFER); | 548 | SST_MIN_BUFFER, SST_MAX_BUFFER); |
426 | if (retval) { | 549 | if (retval) { |
427 | pr_err("dma buffer allocationf fail\n"); | 550 | pr_err("dma buffer allocationf fail\n"); |
@@ -445,10 +568,28 @@ static const struct snd_soc_component_driver sst_component = { | |||
445 | 568 | ||
446 | static int sst_platform_probe(struct platform_device *pdev) | 569 | static int sst_platform_probe(struct platform_device *pdev) |
447 | { | 570 | { |
571 | struct sst_data *drv; | ||
448 | int ret; | 572 | int ret; |
573 | struct sst_platform_data *pdata; | ||
574 | |||
575 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); | ||
576 | if (drv == NULL) { | ||
577 | pr_err("kzalloc failed\n"); | ||
578 | return -ENOMEM; | ||
579 | } | ||
580 | |||
581 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
582 | if (pdata == NULL) { | ||
583 | pr_err("kzalloc failed for pdata\n"); | ||
584 | return -ENOMEM; | ||
585 | } | ||
586 | |||
587 | pdata->pdev_strm_map = dpcm_strm_map; | ||
588 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); | ||
589 | drv->pdata = pdata; | ||
590 | mutex_init(&drv->lock); | ||
591 | dev_set_drvdata(&pdev->dev, drv); | ||
449 | 592 | ||
450 | pr_debug("sst_platform_probe called\n"); | ||
451 | sst = NULL; | ||
452 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); | 593 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); |
453 | if (ret) { | 594 | if (ret) { |
454 | pr_err("registering soc platform failed\n"); | 595 | pr_err("registering soc platform failed\n"); |
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c5e7dc49e3c..6c6a42c08e24 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
@@ -39,9 +39,10 @@ extern struct sst_device *sst; | |||
39 | 39 | ||
40 | struct pcm_stream_info { | 40 | struct pcm_stream_info { |
41 | int str_id; | 41 | int str_id; |
42 | void *mad_substream; | 42 | void *arg; |
43 | void (*period_elapsed) (void *mad_substream); | 43 | void (*period_elapsed) (void *arg); |
44 | unsigned long long buffer_ptr; | 44 | unsigned long long buffer_ptr; |
45 | unsigned long long pcm_delay; | ||
45 | int sfreq; | 46 | int sfreq; |
46 | }; | 47 | }; |
47 | 48 | ||
@@ -62,7 +63,9 @@ enum sst_controls { | |||
62 | SST_SND_BUFFER_POINTER = 0x05, | 63 | SST_SND_BUFFER_POINTER = 0x05, |
63 | SST_SND_STREAM_INIT = 0x06, | 64 | SST_SND_STREAM_INIT = 0x06, |
64 | SST_SND_START = 0x07, | 65 | SST_SND_START = 0x07, |
65 | SST_MAX_CONTROLS = 0x07, | 66 | SST_SET_BYTE_STREAM = 0x100A, |
67 | SST_GET_BYTE_STREAM = 0x100B, | ||
68 | SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, | ||
66 | }; | 69 | }; |
67 | 70 | ||
68 | enum sst_stream_ops { | 71 | enum sst_stream_ops { |
@@ -124,8 +127,9 @@ struct compress_sst_ops { | |||
124 | }; | 127 | }; |
125 | 128 | ||
126 | struct sst_ops { | 129 | struct sst_ops { |
127 | int (*open) (struct sst_stream_params *str_param); | 130 | int (*open) (struct snd_sst_params *str_param); |
128 | int (*device_control) (int cmd, void *arg); | 131 | int (*device_control) (int cmd, void *arg); |
132 | int (*set_generic_params)(enum sst_controls cmd, void *arg); | ||
129 | int (*close) (unsigned int str_id); | 133 | int (*close) (unsigned int str_id); |
130 | }; | 134 | }; |
131 | 135 | ||
@@ -143,10 +147,27 @@ struct sst_device { | |||
143 | char *name; | 147 | char *name; |
144 | struct device *dev; | 148 | struct device *dev; |
145 | struct sst_ops *ops; | 149 | struct sst_ops *ops; |
150 | struct platform_device *pdev; | ||
146 | struct compress_sst_ops *compr_ops; | 151 | struct compress_sst_ops *compr_ops; |
147 | }; | 152 | }; |
148 | 153 | ||
154 | struct sst_data; | ||
149 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); | 155 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); |
156 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, | ||
157 | struct snd_sst_params *str_params, bool is_compress); | ||
158 | |||
159 | struct sst_algo_int_control_v2 { | ||
160 | struct soc_mixer_control mc; | ||
161 | u16 module_id; /* module identifieer */ | ||
162 | u16 pipe_id; /* location info: pipe_id + instance_id */ | ||
163 | u16 instance_id; | ||
164 | unsigned int value; /* Value received is stored here */ | ||
165 | }; | ||
166 | struct sst_data { | ||
167 | struct platform_device *pdev; | ||
168 | struct sst_platform_data *pdata; | ||
169 | struct mutex lock; | ||
170 | }; | ||
150 | int sst_register_dsp(struct sst_device *sst); | 171 | int sst_register_dsp(struct sst_device *sst); |
151 | int sst_unregister_dsp(struct sst_device *sst); | 172 | int sst_unregister_dsp(struct sst_device *sst); |
152 | #endif | 173 | #endif |
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index 06f4e8aa93ae..132bb83f8e99 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_KIRKWOOD_SOC | 1 | config SND_KIRKWOOD_SOC |
2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" | 2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" |
3 | depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU || MACH_KIRKWOOD || COMPILE_TEST | 3 | depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the Kirkwood I2S interface. You will also need to select the | 6 | the Kirkwood I2S interface. You will also need to select the |
@@ -15,20 +15,3 @@ config SND_KIRKWOOD_SOC_ARMADA370_DB | |||
15 | Say Y if you want to add support for SoC audio on | 15 | Say Y if you want to add support for SoC audio on |
16 | the Armada 370 Development Board. | 16 | the Armada 370 Development Board. |
17 | 17 | ||
18 | config SND_KIRKWOOD_SOC_OPENRD | ||
19 | tristate "SoC Audio support for Kirkwood Openrd Client" | ||
20 | depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST) | ||
21 | depends on I2C | ||
22 | select SND_SOC_CS42L51 | ||
23 | help | ||
24 | Say Y if you want to add support for SoC audio on | ||
25 | Openrd Client. | ||
26 | |||
27 | config SND_KIRKWOOD_SOC_T5325 | ||
28 | tristate "SoC Audio support for HP t5325" | ||
29 | depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C | ||
30 | select SND_SOC_ALC5623 | ||
31 | help | ||
32 | Say Y if you want to add support for SoC audio on | ||
33 | the HP t5325 thin client. | ||
34 | |||
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile index 7c1d8fe09e6b..c36b03d8006c 100644 --- a/sound/soc/kirkwood/Makefile +++ b/sound/soc/kirkwood/Makefile | |||
@@ -2,10 +2,6 @@ snd-soc-kirkwood-objs := kirkwood-dma.o kirkwood-i2s.o | |||
2 | 2 | ||
3 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o | 3 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o |
4 | 4 | ||
5 | snd-soc-openrd-objs := kirkwood-openrd.o | ||
6 | snd-soc-t5325-objs := kirkwood-t5325.o | ||
7 | snd-soc-armada-370-db-objs := armada-370-db.o | 5 | snd-soc-armada-370-db-objs := armada-370-db.o |
8 | 6 | ||
9 | obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o | 7 | obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o |
10 | obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o | ||
11 | obj-$(CONFIG_SND_KIRKWOOD_SOC_T5325) += snd-soc-t5325.o | ||
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index aac22fccdcdc..4cf2245950d7 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c | |||
@@ -28,11 +28,12 @@ static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) | |||
28 | } | 28 | } |
29 | 29 | ||
30 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { | 30 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { |
31 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | 31 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
32 | SNDRV_PCM_INFO_MMAP | | 32 | SNDRV_PCM_INFO_MMAP | |
33 | SNDRV_PCM_INFO_MMAP_VALID | | 33 | SNDRV_PCM_INFO_MMAP_VALID | |
34 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 34 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
35 | SNDRV_PCM_INFO_PAUSE), | 35 | SNDRV_PCM_INFO_PAUSE | |
36 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
36 | .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES, | 37 | .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES, |
37 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, | 38 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, |
38 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, | 39 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, |
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 9f842222e798..0704cd6d2314 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
@@ -212,7 +212,8 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
212 | KIRKWOOD_PLAYCTL_SIZE_MASK); | 212 | KIRKWOOD_PLAYCTL_SIZE_MASK); |
213 | priv->ctl_play |= ctl_play; | 213 | priv->ctl_play |= ctl_play; |
214 | } else { | 214 | } else { |
215 | priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK; | 215 | priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK | |
216 | KIRKWOOD_RECCTL_SIZE_MASK); | ||
216 | priv->ctl_rec |= ctl_rec; | 217 | priv->ctl_rec |= ctl_rec; |
217 | } | 218 | } |
218 | 219 | ||
@@ -221,14 +222,24 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
221 | return 0; | 222 | return 0; |
222 | } | 223 | } |
223 | 224 | ||
225 | static unsigned kirkwood_i2s_play_mute(unsigned ctl) | ||
226 | { | ||
227 | if (!(ctl & KIRKWOOD_PLAYCTL_I2S_EN)) | ||
228 | ctl |= KIRKWOOD_PLAYCTL_I2S_MUTE; | ||
229 | if (!(ctl & KIRKWOOD_PLAYCTL_SPDIF_EN)) | ||
230 | ctl |= KIRKWOOD_PLAYCTL_SPDIF_MUTE; | ||
231 | return ctl; | ||
232 | } | ||
233 | |||
224 | static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | 234 | static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, |
225 | int cmd, struct snd_soc_dai *dai) | 235 | int cmd, struct snd_soc_dai *dai) |
226 | { | 236 | { |
237 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
227 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); | 238 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); |
228 | uint32_t ctl, value; | 239 | uint32_t ctl, value; |
229 | 240 | ||
230 | ctl = readl(priv->io + KIRKWOOD_PLAYCTL); | 241 | ctl = readl(priv->io + KIRKWOOD_PLAYCTL); |
231 | if (ctl & KIRKWOOD_PLAYCTL_PAUSE) { | 242 | if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) { |
232 | unsigned timeout = 5000; | 243 | unsigned timeout = 5000; |
233 | /* | 244 | /* |
234 | * The Armada510 spec says that if we enter pause mode, the | 245 | * The Armada510 spec says that if we enter pause mode, the |
@@ -256,14 +267,16 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
256 | ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ | 267 | ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ |
257 | else | 268 | else |
258 | ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ | 269 | ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ |
259 | 270 | ctl = kirkwood_i2s_play_mute(ctl); | |
260 | value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK; | 271 | value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
261 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 272 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
262 | 273 | ||
263 | /* enable interrupts */ | 274 | /* enable interrupts */ |
264 | value = readl(priv->io + KIRKWOOD_INT_MASK); | 275 | if (!runtime->no_period_wakeup) { |
265 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; | 276 | value = readl(priv->io + KIRKWOOD_INT_MASK); |
266 | writel(value, priv->io + KIRKWOOD_INT_MASK); | 277 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; |
278 | writel(value, priv->io + KIRKWOOD_INT_MASK); | ||
279 | } | ||
267 | 280 | ||
268 | /* enable playback */ | 281 | /* enable playback */ |
269 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 282 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
@@ -295,6 +308,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
295 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 308 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
296 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | | 309 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | |
297 | KIRKWOOD_PLAYCTL_SPDIF_MUTE); | 310 | KIRKWOOD_PLAYCTL_SPDIF_MUTE); |
311 | ctl = kirkwood_i2s_play_mute(ctl); | ||
298 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 312 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
299 | break; | 313 | break; |
300 | 314 | ||
@@ -322,8 +336,7 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | |||
322 | else | 336 | else |
323 | ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ | 337 | ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ |
324 | 338 | ||
325 | value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN | | 339 | value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK; |
326 | KIRKWOOD_RECCTL_SPDIF_EN); | ||
327 | writel(value, priv->io + KIRKWOOD_RECCTL); | 340 | writel(value, priv->io + KIRKWOOD_RECCTL); |
328 | 341 | ||
329 | /* enable interrupts */ | 342 | /* enable interrupts */ |
@@ -347,7 +360,7 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | |||
347 | 360 | ||
348 | /* disable all records */ | 361 | /* disable all records */ |
349 | value = readl(priv->io + KIRKWOOD_RECCTL); | 362 | value = readl(priv->io + KIRKWOOD_RECCTL); |
350 | value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); | 363 | value &= ~KIRKWOOD_RECCTL_ENABLE_MASK; |
351 | writel(value, priv->io + KIRKWOOD_RECCTL); | 364 | writel(value, priv->io + KIRKWOOD_RECCTL); |
352 | break; | 365 | break; |
353 | 366 | ||
@@ -411,7 +424,7 @@ static int kirkwood_i2s_init(struct kirkwood_dma_data *priv) | |||
411 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 424 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
412 | 425 | ||
413 | value = readl(priv->io + KIRKWOOD_RECCTL); | 426 | value = readl(priv->io + KIRKWOOD_RECCTL); |
414 | value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); | 427 | value &= ~KIRKWOOD_RECCTL_ENABLE_MASK; |
415 | writel(value, priv->io + KIRKWOOD_RECCTL); | 428 | writel(value, priv->io + KIRKWOOD_RECCTL); |
416 | 429 | ||
417 | return 0; | 430 | return 0; |
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c deleted file mode 100644 index 65f2a5b9ec3b..000000000000 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | /* | ||
2 | * kirkwood-openrd.c | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
5 | * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <linux/platform_data/asoc-kirkwood.h> | ||
20 | #include "../codecs/cs42l51.h" | ||
21 | |||
22 | static int openrd_client_hw_params(struct snd_pcm_substream *substream, | ||
23 | struct snd_pcm_hw_params *params) | ||
24 | { | ||
25 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
26 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
27 | unsigned int freq; | ||
28 | |||
29 | switch (params_rate(params)) { | ||
30 | default: | ||
31 | case 44100: | ||
32 | freq = 11289600; | ||
33 | break; | ||
34 | case 48000: | ||
35 | freq = 12288000; | ||
36 | break; | ||
37 | case 96000: | ||
38 | freq = 24576000; | ||
39 | break; | ||
40 | } | ||
41 | |||
42 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); | ||
43 | |||
44 | } | ||
45 | |||
46 | static struct snd_soc_ops openrd_client_ops = { | ||
47 | .hw_params = openrd_client_hw_params, | ||
48 | }; | ||
49 | |||
50 | |||
51 | static struct snd_soc_dai_link openrd_client_dai[] = { | ||
52 | { | ||
53 | .name = "CS42L51", | ||
54 | .stream_name = "CS42L51 HiFi", | ||
55 | .cpu_dai_name = "i2s", | ||
56 | .platform_name = "mvebu-audio", | ||
57 | .codec_dai_name = "cs42l51-hifi", | ||
58 | .codec_name = "cs42l51-codec.0-004a", | ||
59 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, | ||
60 | .ops = &openrd_client_ops, | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | |||
65 | static struct snd_soc_card openrd_client = { | ||
66 | .name = "OpenRD Client", | ||
67 | .owner = THIS_MODULE, | ||
68 | .dai_link = openrd_client_dai, | ||
69 | .num_links = ARRAY_SIZE(openrd_client_dai), | ||
70 | }; | ||
71 | |||
72 | static int openrd_probe(struct platform_device *pdev) | ||
73 | { | ||
74 | struct snd_soc_card *card = &openrd_client; | ||
75 | int ret; | ||
76 | |||
77 | card->dev = &pdev->dev; | ||
78 | |||
79 | ret = snd_soc_register_card(card); | ||
80 | if (ret) | ||
81 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
82 | ret); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static int openrd_remove(struct platform_device *pdev) | ||
87 | { | ||
88 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
89 | |||
90 | snd_soc_unregister_card(card); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static struct platform_driver openrd_driver = { | ||
95 | .driver = { | ||
96 | .name = "openrd-client-audio", | ||
97 | .owner = THIS_MODULE, | ||
98 | }, | ||
99 | .probe = openrd_probe, | ||
100 | .remove = openrd_remove, | ||
101 | }; | ||
102 | |||
103 | module_platform_driver(openrd_driver); | ||
104 | |||
105 | /* Module information */ | ||
106 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | ||
107 | MODULE_DESCRIPTION("ALSA SoC OpenRD Client"); | ||
108 | MODULE_LICENSE("GPL"); | ||
109 | MODULE_ALIAS("platform:openrd-client-audio"); | ||
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c deleted file mode 100644 index 844b8415a011..000000000000 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ /dev/null | |||
@@ -1,116 +0,0 @@ | |||
1 | /* | ||
2 | * kirkwood-t5325.c | ||
3 | * | ||
4 | * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <sound/soc.h> | ||
18 | #include <linux/platform_data/asoc-kirkwood.h> | ||
19 | #include "../codecs/alc5623.h" | ||
20 | |||
21 | static int t5325_hw_params(struct snd_pcm_substream *substream, | ||
22 | struct snd_pcm_hw_params *params) | ||
23 | { | ||
24 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
25 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
26 | unsigned int freq; | ||
27 | |||
28 | freq = params_rate(params) * 256; | ||
29 | |||
30 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); | ||
31 | |||
32 | } | ||
33 | |||
34 | static struct snd_soc_ops t5325_ops = { | ||
35 | .hw_params = t5325_hw_params, | ||
36 | }; | ||
37 | |||
38 | static const struct snd_soc_dapm_widget t5325_dapm_widgets[] = { | ||
39 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
40 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
41 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
42 | }; | ||
43 | |||
44 | static const struct snd_soc_dapm_route t5325_route[] = { | ||
45 | { "Headphone Jack", NULL, "HPL" }, | ||
46 | { "Headphone Jack", NULL, "HPR" }, | ||
47 | |||
48 | {"Speaker", NULL, "SPKOUT"}, | ||
49 | {"Speaker", NULL, "SPKOUTN"}, | ||
50 | |||
51 | { "MIC1", NULL, "Mic Jack" }, | ||
52 | { "MIC2", NULL, "Mic Jack" }, | ||
53 | }; | ||
54 | |||
55 | static struct snd_soc_dai_link t5325_dai[] = { | ||
56 | { | ||
57 | .name = "ALC5621", | ||
58 | .stream_name = "ALC5621 HiFi", | ||
59 | .cpu_dai_name = "i2s", | ||
60 | .platform_name = "mvebu-audio", | ||
61 | .codec_dai_name = "alc5621-hifi", | ||
62 | .codec_name = "alc562x-codec.0-001a", | ||
63 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, | ||
64 | .ops = &t5325_ops, | ||
65 | }, | ||
66 | }; | ||
67 | |||
68 | static struct snd_soc_card t5325 = { | ||
69 | .name = "t5325", | ||
70 | .owner = THIS_MODULE, | ||
71 | .dai_link = t5325_dai, | ||
72 | .num_links = ARRAY_SIZE(t5325_dai), | ||
73 | |||
74 | .dapm_widgets = t5325_dapm_widgets, | ||
75 | .num_dapm_widgets = ARRAY_SIZE(t5325_dapm_widgets), | ||
76 | .dapm_routes = t5325_route, | ||
77 | .num_dapm_routes = ARRAY_SIZE(t5325_route), | ||
78 | }; | ||
79 | |||
80 | static int t5325_probe(struct platform_device *pdev) | ||
81 | { | ||
82 | struct snd_soc_card *card = &t5325; | ||
83 | int ret; | ||
84 | |||
85 | card->dev = &pdev->dev; | ||
86 | |||
87 | ret = snd_soc_register_card(card); | ||
88 | if (ret) | ||
89 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
90 | ret); | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static int t5325_remove(struct platform_device *pdev) | ||
95 | { | ||
96 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
97 | |||
98 | snd_soc_unregister_card(card); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static struct platform_driver t5325_driver = { | ||
103 | .driver = { | ||
104 | .name = "t5325-audio", | ||
105 | .owner = THIS_MODULE, | ||
106 | }, | ||
107 | .probe = t5325_probe, | ||
108 | .remove = t5325_remove, | ||
109 | }; | ||
110 | |||
111 | module_platform_driver(t5325_driver); | ||
112 | |||
113 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | ||
114 | MODULE_DESCRIPTION("ALSA SoC t5325 audio client"); | ||
115 | MODULE_LICENSE("GPL"); | ||
116 | MODULE_ALIAS("platform:t5325-audio"); | ||
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index bf23afbba1d7..90e32a781424 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h | |||
@@ -38,6 +38,9 @@ | |||
38 | #define KIRKWOOD_RECCTL_SIZE_24 (1<<0) | 38 | #define KIRKWOOD_RECCTL_SIZE_24 (1<<0) |
39 | #define KIRKWOOD_RECCTL_SIZE_32 (0<<0) | 39 | #define KIRKWOOD_RECCTL_SIZE_32 (0<<0) |
40 | 40 | ||
41 | #define KIRKWOOD_RECCTL_ENABLE_MASK (KIRKWOOD_RECCTL_SPDIF_EN | \ | ||
42 | KIRKWOOD_RECCTL_I2S_EN) | ||
43 | |||
41 | #define KIRKWOOD_REC_BUF_ADDR 0x1004 | 44 | #define KIRKWOOD_REC_BUF_ADDR 0x1004 |
42 | #define KIRKWOOD_REC_BUF_SIZE 0x1008 | 45 | #define KIRKWOOD_REC_BUF_SIZE 0x1008 |
43 | #define KIRKWOOD_REC_BYTE_COUNT 0x100C | 46 | #define KIRKWOOD_REC_BYTE_COUNT 0x100C |
@@ -121,9 +124,9 @@ | |||
121 | 124 | ||
122 | /* Theses values come from the marvell alsa driver */ | 125 | /* Theses values come from the marvell alsa driver */ |
123 | /* need to find where they come from */ | 126 | /* need to find where they come from */ |
124 | #define KIRKWOOD_SND_MIN_PERIODS 8 | 127 | #define KIRKWOOD_SND_MIN_PERIODS 2 |
125 | #define KIRKWOOD_SND_MAX_PERIODS 16 | 128 | #define KIRKWOOD_SND_MAX_PERIODS 16 |
126 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x800 | 129 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 256 |
127 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000 | 130 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000 |
128 | #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ | 131 | #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ |
129 | * KIRKWOOD_SND_MAX_PERIODS) | 132 | * KIRKWOOD_SND_MAX_PERIODS) |
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 0cc41f94de4e..8c9cc64a9dfb 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c | |||
@@ -301,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty) | |||
301 | static void cx81801_close(struct tty_struct *tty) | 301 | static void cx81801_close(struct tty_struct *tty) |
302 | { | 302 | { |
303 | struct snd_soc_codec *codec = tty->disc_data; | 303 | struct snd_soc_codec *codec = tty->disc_data; |
304 | struct snd_soc_dapm_context *dapm = &codec->card->dapm; | 304 | struct snd_soc_dapm_context *dapm = &codec->component.card->dapm; |
305 | 305 | ||
306 | del_timer_sync(&cx81801_timer); | 306 | del_timer_sync(&cx81801_timer); |
307 | 307 | ||
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 6acb225ec6fd..2434b6d61675 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -11,6 +11,7 @@ config SND_PXA2XX_SOC | |||
11 | config SND_MMP_SOC | 11 | config SND_MMP_SOC |
12 | bool "Soc Audio for Marvell MMP chips" | 12 | bool "Soc Audio for Marvell MMP chips" |
13 | depends on ARCH_MMP | 13 | depends on ARCH_MMP |
14 | select MMP_SRAM | ||
14 | select SND_SOC_GENERIC_DMAENGINE_PCM | 15 | select SND_SOC_GENERIC_DMAENGINE_PCM |
15 | select SND_ARM | 16 | select SND_ARM |
16 | help | 17 | help |
@@ -40,7 +41,7 @@ config SND_MMP_SOC_SSPA | |||
40 | 41 | ||
41 | config SND_PXA2XX_SOC_CORGI | 42 | config SND_PXA2XX_SOC_CORGI |
42 | tristate "SoC Audio support for Sharp Zaurus SL-C7x0" | 43 | tristate "SoC Audio support for Sharp Zaurus SL-C7x0" |
43 | depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx | 44 | depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx && I2C |
44 | select SND_PXA2XX_SOC_I2S | 45 | select SND_PXA2XX_SOC_I2S |
45 | select SND_SOC_WM8731 | 46 | select SND_SOC_WM8731 |
46 | help | 47 | help |
@@ -49,7 +50,7 @@ config SND_PXA2XX_SOC_CORGI | |||
49 | 50 | ||
50 | config SND_PXA2XX_SOC_SPITZ | 51 | config SND_PXA2XX_SOC_SPITZ |
51 | tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" | 52 | tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" |
52 | depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 | 53 | depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 && I2C |
53 | select SND_PXA2XX_SOC_I2S | 54 | select SND_PXA2XX_SOC_I2S |
54 | select SND_SOC_WM8750 | 55 | select SND_SOC_WM8750 |
55 | help | 56 | help |
@@ -58,7 +59,7 @@ config SND_PXA2XX_SOC_SPITZ | |||
58 | 59 | ||
59 | config SND_PXA2XX_SOC_Z2 | 60 | config SND_PXA2XX_SOC_Z2 |
60 | tristate "SoC Audio support for Zipit Z2" | 61 | tristate "SoC Audio support for Zipit Z2" |
61 | depends on SND_PXA2XX_SOC && MACH_ZIPIT2 | 62 | depends on SND_PXA2XX_SOC && MACH_ZIPIT2 && I2C |
62 | select SND_PXA2XX_SOC_I2S | 63 | select SND_PXA2XX_SOC_I2S |
63 | select SND_SOC_WM8750 | 64 | select SND_SOC_WM8750 |
64 | help | 65 | help |
@@ -66,7 +67,7 @@ config SND_PXA2XX_SOC_Z2 | |||
66 | 67 | ||
67 | config SND_PXA2XX_SOC_POODLE | 68 | config SND_PXA2XX_SOC_POODLE |
68 | tristate "SoC Audio support for Poodle" | 69 | tristate "SoC Audio support for Poodle" |
69 | depends on SND_PXA2XX_SOC && MACH_POODLE | 70 | depends on SND_PXA2XX_SOC && MACH_POODLE && I2C |
70 | select SND_PXA2XX_SOC_I2S | 71 | select SND_PXA2XX_SOC_I2S |
71 | select SND_SOC_WM8731 | 72 | select SND_SOC_WM8731 |
72 | help | 73 | help |
@@ -181,7 +182,7 @@ config SND_PXA2XX_SOC_HX4700 | |||
181 | 182 | ||
182 | config SND_PXA2XX_SOC_MAGICIAN | 183 | config SND_PXA2XX_SOC_MAGICIAN |
183 | tristate "SoC Audio support for HTC Magician" | 184 | tristate "SoC Audio support for HTC Magician" |
184 | depends on SND_PXA2XX_SOC && MACH_MAGICIAN | 185 | depends on SND_PXA2XX_SOC && MACH_MAGICIAN && I2C |
185 | select SND_PXA2XX_SOC_I2S | 186 | select SND_PXA2XX_SOC_I2S |
186 | select SND_PXA_SOC_SSP | 187 | select SND_PXA_SOC_SSP |
187 | select SND_SOC_UDA1380 | 188 | select SND_SOC_UDA1380 |
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c index 7eba7979b9af..1c8d01166e5b 100644 --- a/sound/soc/s6000/s6000-i2s.c +++ b/sound/soc/s6000/s6000-i2s.c | |||
@@ -570,7 +570,7 @@ err_release_none: | |||
570 | return ret; | 570 | return ret; |
571 | } | 571 | } |
572 | 572 | ||
573 | static void s6000_i2s_remove(struct platform_device *pdev) | 573 | static int s6000_i2s_remove(struct platform_device *pdev) |
574 | { | 574 | { |
575 | struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev); | 575 | struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev); |
576 | struct resource *region; | 576 | struct resource *region; |
@@ -597,6 +597,8 @@ static void s6000_i2s_remove(struct platform_device *pdev) | |||
597 | iounmap(mmio); | 597 | iounmap(mmio); |
598 | region = platform_get_resource(pdev, IORESOURCE_IO, 0); | 598 | region = platform_get_resource(pdev, IORESOURCE_IO, 0); |
599 | release_mem_region(region->start, resource_size(region)); | 599 | release_mem_region(region->start, resource_size(region)); |
600 | |||
601 | return 0; | ||
600 | } | 602 | } |
601 | 603 | ||
602 | static struct platform_driver s6000_i2s_driver = { | 604 | static struct platform_driver s6000_i2s_driver = { |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 2ac76fa3e742..d2533dbc8399 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -68,6 +68,8 @@ struct i2s_dai { | |||
68 | #define DAI_OPENED (1 << 0) /* Dai is opened */ | 68 | #define DAI_OPENED (1 << 0) /* Dai is opened */ |
69 | #define DAI_MANAGER (1 << 1) /* Dai is the manager */ | 69 | #define DAI_MANAGER (1 << 1) /* Dai is the manager */ |
70 | unsigned mode; | 70 | unsigned mode; |
71 | /* CDCLK pin direction: 0 - input, 1 - output */ | ||
72 | unsigned int cdclk_out:1; | ||
71 | /* Driver for this DAI */ | 73 | /* Driver for this DAI */ |
72 | struct snd_soc_dai_driver i2s_dai_drv; | 74 | struct snd_soc_dai_driver i2s_dai_drv; |
73 | /* DMA parameters */ | 75 | /* DMA parameters */ |
@@ -737,6 +739,9 @@ static int i2s_startup(struct snd_pcm_substream *substream, | |||
737 | 739 | ||
738 | spin_unlock_irqrestore(&lock, flags); | 740 | spin_unlock_irqrestore(&lock, flags); |
739 | 741 | ||
742 | if (!is_opened(other) && i2s->cdclk_out) | ||
743 | i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK, | ||
744 | 0, SND_SOC_CLOCK_OUT); | ||
740 | return 0; | 745 | return 0; |
741 | } | 746 | } |
742 | 747 | ||
@@ -752,9 +757,13 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, | |||
752 | i2s->mode &= ~DAI_OPENED; | 757 | i2s->mode &= ~DAI_OPENED; |
753 | i2s->mode &= ~DAI_MANAGER; | 758 | i2s->mode &= ~DAI_MANAGER; |
754 | 759 | ||
755 | if (is_opened(other)) | 760 | if (is_opened(other)) { |
756 | other->mode |= DAI_MANAGER; | 761 | other->mode |= DAI_MANAGER; |
757 | 762 | } else { | |
763 | u32 mod = readl(i2s->addr + I2SMOD); | ||
764 | i2s->cdclk_out = !(mod & MOD_CDCLKCON); | ||
765 | other->cdclk_out = i2s->cdclk_out; | ||
766 | } | ||
758 | /* Reset any constraint on RFS and BFS */ | 767 | /* Reset any constraint on RFS and BFS */ |
759 | i2s->rfs = 0; | 768 | i2s->rfs = 0; |
760 | i2s->bfs = 0; | 769 | i2s->bfs = 0; |
@@ -920,11 +929,9 @@ static int i2s_suspend(struct snd_soc_dai *dai) | |||
920 | { | 929 | { |
921 | struct i2s_dai *i2s = to_info(dai); | 930 | struct i2s_dai *i2s = to_info(dai); |
922 | 931 | ||
923 | if (dai->active) { | 932 | i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); |
924 | i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); | 933 | i2s->suspend_i2scon = readl(i2s->addr + I2SCON); |
925 | i2s->suspend_i2scon = readl(i2s->addr + I2SCON); | 934 | i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); |
926 | i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); | ||
927 | } | ||
928 | 935 | ||
929 | return 0; | 936 | return 0; |
930 | } | 937 | } |
@@ -933,11 +940,9 @@ static int i2s_resume(struct snd_soc_dai *dai) | |||
933 | { | 940 | { |
934 | struct i2s_dai *i2s = to_info(dai); | 941 | struct i2s_dai *i2s = to_info(dai); |
935 | 942 | ||
936 | if (dai->active) { | 943 | writel(i2s->suspend_i2scon, i2s->addr + I2SCON); |
937 | writel(i2s->suspend_i2scon, i2s->addr + I2SCON); | 944 | writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); |
938 | writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); | 945 | writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); |
939 | writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); | ||
940 | } | ||
941 | 946 | ||
942 | return 0; | 947 | return 0; |
943 | } | 948 | } |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index b43fdf0d08af..80245b6eebd6 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU | |||
37 | config SND_SOC_RCAR | 37 | config SND_SOC_RCAR |
38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" | 38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" |
39 | select SND_SIMPLE_CARD | 39 | select SND_SIMPLE_CARD |
40 | select REGMAP | 40 | select REGMAP_MMIO |
41 | help | 41 | help |
42 | This option enables R-Car SUR/SCU/SSIU/SSI sound support | 42 | This option enables R-Car SUR/SCU/SSIU/SSI sound support |
43 | 43 | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 710a079a7377..a57eb96e57eb 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -232,11 +232,7 @@ struct fsi_stream { | |||
232 | * these are for DMAEngine | 232 | * these are for DMAEngine |
233 | */ | 233 | */ |
234 | struct dma_chan *chan; | 234 | struct dma_chan *chan; |
235 | struct work_struct work; | ||
236 | dma_addr_t dma; | ||
237 | int dma_id; | 235 | int dma_id; |
238 | int loop_cnt; | ||
239 | int additional_pos; | ||
240 | }; | 236 | }; |
241 | 237 | ||
242 | struct fsi_clk { | 238 | struct fsi_clk { |
@@ -1042,6 +1038,26 @@ static int fsi_clk_set_rate_cpg(struct device *dev, | |||
1042 | return ret; | 1038 | return ret; |
1043 | } | 1039 | } |
1044 | 1040 | ||
1041 | static void fsi_pointer_update(struct fsi_stream *io, int size) | ||
1042 | { | ||
1043 | io->buff_sample_pos += size; | ||
1044 | |||
1045 | if (io->buff_sample_pos >= | ||
1046 | io->period_samples * (io->period_pos + 1)) { | ||
1047 | struct snd_pcm_substream *substream = io->substream; | ||
1048 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1049 | |||
1050 | io->period_pos++; | ||
1051 | |||
1052 | if (io->period_pos >= runtime->periods) { | ||
1053 | io->buff_sample_pos = 0; | ||
1054 | io->period_pos = 0; | ||
1055 | } | ||
1056 | |||
1057 | snd_pcm_period_elapsed(substream); | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1045 | /* | 1061 | /* |
1046 | * pio data transfer handler | 1062 | * pio data transfer handler |
1047 | */ | 1063 | */ |
@@ -1108,31 +1124,11 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, | |||
1108 | void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), | 1124 | void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), |
1109 | int samples) | 1125 | int samples) |
1110 | { | 1126 | { |
1111 | struct snd_pcm_runtime *runtime; | ||
1112 | struct snd_pcm_substream *substream; | ||
1113 | u8 *buf; | 1127 | u8 *buf; |
1114 | int over_period; | ||
1115 | 1128 | ||
1116 | if (!fsi_stream_is_working(fsi, io)) | 1129 | if (!fsi_stream_is_working(fsi, io)) |
1117 | return -EINVAL; | 1130 | return -EINVAL; |
1118 | 1131 | ||
1119 | over_period = 0; | ||
1120 | substream = io->substream; | ||
1121 | runtime = substream->runtime; | ||
1122 | |||
1123 | /* FSI FIFO has limit. | ||
1124 | * So, this driver can not send periods data at a time | ||
1125 | */ | ||
1126 | if (io->buff_sample_pos >= | ||
1127 | io->period_samples * (io->period_pos + 1)) { | ||
1128 | |||
1129 | over_period = 1; | ||
1130 | io->period_pos = (io->period_pos + 1) % runtime->periods; | ||
1131 | |||
1132 | if (0 == io->period_pos) | ||
1133 | io->buff_sample_pos = 0; | ||
1134 | } | ||
1135 | |||
1136 | buf = fsi_pio_get_area(fsi, io); | 1132 | buf = fsi_pio_get_area(fsi, io); |
1137 | 1133 | ||
1138 | switch (io->sample_width) { | 1134 | switch (io->sample_width) { |
@@ -1146,11 +1142,7 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, | |||
1146 | return -EINVAL; | 1142 | return -EINVAL; |
1147 | } | 1143 | } |
1148 | 1144 | ||
1149 | /* update buff_sample_pos */ | 1145 | fsi_pointer_update(io, samples); |
1150 | io->buff_sample_pos += samples; | ||
1151 | |||
1152 | if (over_period) | ||
1153 | snd_pcm_period_elapsed(substream); | ||
1154 | 1146 | ||
1155 | return 0; | 1147 | return 0; |
1156 | } | 1148 | } |
@@ -1279,11 +1271,6 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
1279 | */ | 1271 | */ |
1280 | static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) | 1272 | static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) |
1281 | { | 1273 | { |
1282 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
1283 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | ||
1284 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | ||
1285 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
1286 | |||
1287 | /* | 1274 | /* |
1288 | * 24bit data : 24bit bus / package in back | 1275 | * 24bit data : 24bit bus / package in back |
1289 | * 16bit data : 16bit bus / stream mode | 1276 | * 16bit data : 16bit bus / stream mode |
@@ -1291,107 +1278,48 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1291 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | 1278 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | |
1292 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); | 1279 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); |
1293 | 1280 | ||
1294 | io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */ | ||
1295 | io->additional_pos = 0; | ||
1296 | io->dma = dma_map_single(dai->dev, runtime->dma_area, | ||
1297 | snd_pcm_lib_buffer_bytes(io->substream), dir); | ||
1298 | return 0; | 1281 | return 0; |
1299 | } | 1282 | } |
1300 | 1283 | ||
1301 | static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io) | ||
1302 | { | ||
1303 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | ||
1304 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | ||
1305 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
1306 | |||
1307 | dma_unmap_single(dai->dev, io->dma, | ||
1308 | snd_pcm_lib_buffer_bytes(io->substream), dir); | ||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional) | ||
1313 | { | ||
1314 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
1315 | int period = io->period_pos + additional; | ||
1316 | |||
1317 | if (period >= runtime->periods) | ||
1318 | period = 0; | ||
1319 | |||
1320 | return io->dma + samples_to_bytes(runtime, period * io->period_samples); | ||
1321 | } | ||
1322 | |||
1323 | static void fsi_dma_complete(void *data) | 1284 | static void fsi_dma_complete(void *data) |
1324 | { | 1285 | { |
1325 | struct fsi_stream *io = (struct fsi_stream *)data; | 1286 | struct fsi_stream *io = (struct fsi_stream *)data; |
1326 | struct fsi_priv *fsi = fsi_stream_to_priv(io); | 1287 | struct fsi_priv *fsi = fsi_stream_to_priv(io); |
1327 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
1328 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | ||
1329 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | ||
1330 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
1331 | 1288 | ||
1332 | dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0), | 1289 | fsi_pointer_update(io, io->period_samples); |
1333 | samples_to_bytes(runtime, io->period_samples), dir); | ||
1334 | |||
1335 | io->buff_sample_pos += io->period_samples; | ||
1336 | io->period_pos++; | ||
1337 | |||
1338 | if (io->period_pos >= runtime->periods) { | ||
1339 | io->period_pos = 0; | ||
1340 | io->buff_sample_pos = 0; | ||
1341 | } | ||
1342 | 1290 | ||
1343 | fsi_count_fifo_err(fsi); | 1291 | fsi_count_fifo_err(fsi); |
1344 | fsi_stream_transfer(io); | ||
1345 | |||
1346 | snd_pcm_period_elapsed(io->substream); | ||
1347 | } | 1292 | } |
1348 | 1293 | ||
1349 | static void fsi_dma_do_work(struct work_struct *work) | 1294 | static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) |
1350 | { | 1295 | { |
1351 | struct fsi_stream *io = container_of(work, struct fsi_stream, work); | 1296 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); |
1352 | struct fsi_priv *fsi = fsi_stream_to_priv(io); | 1297 | struct snd_pcm_substream *substream = io->substream; |
1353 | struct snd_soc_dai *dai; | ||
1354 | struct dma_async_tx_descriptor *desc; | 1298 | struct dma_async_tx_descriptor *desc; |
1355 | struct snd_pcm_runtime *runtime; | ||
1356 | enum dma_data_direction dir; | ||
1357 | int is_play = fsi_stream_is_play(fsi, io); | 1299 | int is_play = fsi_stream_is_play(fsi, io); |
1358 | int len, i; | 1300 | enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
1359 | dma_addr_t buf; | 1301 | int ret = -EIO; |
1360 | 1302 | ||
1361 | if (!fsi_stream_is_working(fsi, io)) | 1303 | desc = dmaengine_prep_dma_cyclic(io->chan, |
1362 | return; | 1304 | substream->runtime->dma_addr, |
1363 | 1305 | snd_pcm_lib_buffer_bytes(substream), | |
1364 | dai = fsi_get_dai(io->substream); | 1306 | snd_pcm_lib_period_bytes(substream), |
1365 | runtime = io->substream->runtime; | 1307 | dir, |
1366 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1308 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
1367 | len = samples_to_bytes(runtime, io->period_samples); | 1309 | if (!desc) { |
1368 | 1310 | dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n"); | |
1369 | for (i = 0; i < io->loop_cnt; i++) { | 1311 | goto fsi_dma_transfer_err; |
1370 | buf = fsi_dma_get_area(io, io->additional_pos); | 1312 | } |
1371 | |||
1372 | dma_sync_single_for_device(dai->dev, buf, len, dir); | ||
1373 | |||
1374 | desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, | ||
1375 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
1376 | if (!desc) { | ||
1377 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); | ||
1378 | return; | ||
1379 | } | ||
1380 | |||
1381 | desc->callback = fsi_dma_complete; | ||
1382 | desc->callback_param = io; | ||
1383 | |||
1384 | if (dmaengine_submit(desc) < 0) { | ||
1385 | dev_err(dai->dev, "tx_submit() fail\n"); | ||
1386 | return; | ||
1387 | } | ||
1388 | 1313 | ||
1389 | dma_async_issue_pending(io->chan); | 1314 | desc->callback = fsi_dma_complete; |
1315 | desc->callback_param = io; | ||
1390 | 1316 | ||
1391 | io->additional_pos = 1; | 1317 | if (dmaengine_submit(desc) < 0) { |
1318 | dev_err(dai->dev, "tx_submit() fail\n"); | ||
1319 | goto fsi_dma_transfer_err; | ||
1392 | } | 1320 | } |
1393 | 1321 | ||
1394 | io->loop_cnt = 1; | 1322 | dma_async_issue_pending(io->chan); |
1395 | 1323 | ||
1396 | /* | 1324 | /* |
1397 | * FIXME | 1325 | * FIXME |
@@ -1408,13 +1336,11 @@ static void fsi_dma_do_work(struct work_struct *work) | |||
1408 | fsi_reg_write(fsi, DIFF_ST, 0); | 1336 | fsi_reg_write(fsi, DIFF_ST, 0); |
1409 | } | 1337 | } |
1410 | } | 1338 | } |
1411 | } | ||
1412 | 1339 | ||
1413 | static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) | 1340 | ret = 0; |
1414 | { | ||
1415 | schedule_work(&io->work); | ||
1416 | 1341 | ||
1417 | return 0; | 1342 | fsi_dma_transfer_err: |
1343 | return ret; | ||
1418 | } | 1344 | } |
1419 | 1345 | ||
1420 | static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, | 1346 | static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, |
@@ -1475,15 +1401,11 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev | |||
1475 | return fsi_stream_probe(fsi, dev); | 1401 | return fsi_stream_probe(fsi, dev); |
1476 | } | 1402 | } |
1477 | 1403 | ||
1478 | INIT_WORK(&io->work, fsi_dma_do_work); | ||
1479 | |||
1480 | return 0; | 1404 | return 0; |
1481 | } | 1405 | } |
1482 | 1406 | ||
1483 | static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) | 1407 | static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) |
1484 | { | 1408 | { |
1485 | cancel_work_sync(&io->work); | ||
1486 | |||
1487 | fsi_stream_stop(fsi, io); | 1409 | fsi_stream_stop(fsi, io); |
1488 | 1410 | ||
1489 | if (io->chan) | 1411 | if (io->chan) |
@@ -1495,7 +1417,6 @@ static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1495 | 1417 | ||
1496 | static struct fsi_stream_handler fsi_dma_push_handler = { | 1418 | static struct fsi_stream_handler fsi_dma_push_handler = { |
1497 | .init = fsi_dma_init, | 1419 | .init = fsi_dma_init, |
1498 | .quit = fsi_dma_quit, | ||
1499 | .probe = fsi_dma_probe, | 1420 | .probe = fsi_dma_probe, |
1500 | .transfer = fsi_dma_transfer, | 1421 | .transfer = fsi_dma_transfer, |
1501 | .remove = fsi_dma_remove, | 1422 | .remove = fsi_dma_remove, |
@@ -1657,9 +1578,9 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
1657 | if (!ret) | 1578 | if (!ret) |
1658 | ret = fsi_hw_startup(fsi, io, dai->dev); | 1579 | ret = fsi_hw_startup(fsi, io, dai->dev); |
1659 | if (!ret) | 1580 | if (!ret) |
1660 | ret = fsi_stream_transfer(io); | 1581 | ret = fsi_stream_start(fsi, io); |
1661 | if (!ret) | 1582 | if (!ret) |
1662 | fsi_stream_start(fsi, io); | 1583 | ret = fsi_stream_transfer(io); |
1663 | break; | 1584 | break; |
1664 | case SNDRV_PCM_TRIGGER_STOP: | 1585 | case SNDRV_PCM_TRIGGER_STOP: |
1665 | if (!ret) | 1586 | if (!ret) |
@@ -1850,16 +1771,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm) | |||
1850 | 1771 | ||
1851 | static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) | 1772 | static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) |
1852 | { | 1773 | { |
1853 | struct snd_pcm *pcm = rtd->pcm; | ||
1854 | |||
1855 | /* | ||
1856 | * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel | ||
1857 | * in MMAP mode (i.e. aplay -M) | ||
1858 | */ | ||
1859 | return snd_pcm_lib_preallocate_pages_for_all( | 1774 | return snd_pcm_lib_preallocate_pages_for_all( |
1860 | pcm, | 1775 | rtd->pcm, |
1861 | SNDRV_DMA_TYPE_CONTINUOUS, | 1776 | SNDRV_DMA_TYPE_DEV, |
1862 | snd_dma_continuous_data(GFP_KERNEL), | 1777 | rtd->card->snd_card->dev, |
1863 | PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); | 1778 | PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); |
1864 | } | 1779 | } |
1865 | 1780 | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 91880156e1ae..19f78963e8b9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod) | |||
138 | return mod->ops->name; | 138 | return mod->ops->name; |
139 | } | 139 | } |
140 | 140 | ||
141 | char *rsnd_mod_dma_name(struct rsnd_mod *mod) | ||
142 | { | ||
143 | if (!mod || !mod->ops) | ||
144 | return "unknown"; | ||
145 | |||
146 | if (!mod->ops->dma_name) | ||
147 | return mod->ops->name; | ||
148 | |||
149 | return mod->ops->dma_name(mod); | ||
150 | } | ||
151 | |||
141 | void rsnd_mod_init(struct rsnd_priv *priv, | 152 | void rsnd_mod_init(struct rsnd_priv *priv, |
142 | struct rsnd_mod *mod, | 153 | struct rsnd_mod *mod, |
143 | struct rsnd_mod_ops *ops, | 154 | struct rsnd_mod_ops *ops, |
@@ -153,26 +164,8 @@ void rsnd_mod_init(struct rsnd_priv *priv, | |||
153 | /* | 164 | /* |
154 | * rsnd_dma functions | 165 | * rsnd_dma functions |
155 | */ | 166 | */ |
156 | static void __rsnd_dma_start(struct rsnd_dma *dma); | ||
157 | static void rsnd_dma_continue(struct rsnd_dma *dma) | ||
158 | { | ||
159 | /* push next A or B plane */ | ||
160 | dma->submit_loop = 1; | ||
161 | schedule_work(&dma->work); | ||
162 | } | ||
163 | |||
164 | void rsnd_dma_start(struct rsnd_dma *dma) | ||
165 | { | ||
166 | /* push both A and B plane*/ | ||
167 | dma->offset = 0; | ||
168 | dma->submit_loop = 2; | ||
169 | __rsnd_dma_start(dma); | ||
170 | } | ||
171 | |||
172 | void rsnd_dma_stop(struct rsnd_dma *dma) | 167 | void rsnd_dma_stop(struct rsnd_dma *dma) |
173 | { | 168 | { |
174 | dma->submit_loop = 0; | ||
175 | cancel_work_sync(&dma->work); | ||
176 | dmaengine_terminate_all(dma->chan); | 169 | dmaengine_terminate_all(dma->chan); |
177 | } | 170 | } |
178 | 171 | ||
@@ -180,11 +173,7 @@ static void rsnd_dma_complete(void *data) | |||
180 | { | 173 | { |
181 | struct rsnd_dma *dma = (struct rsnd_dma *)data; | 174 | struct rsnd_dma *dma = (struct rsnd_dma *)data; |
182 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 175 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
183 | struct rsnd_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma)); | ||
184 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 176 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
185 | unsigned long flags; | ||
186 | |||
187 | rsnd_lock(priv, flags); | ||
188 | 177 | ||
189 | /* | 178 | /* |
190 | * Renesas sound Gen1 needs 1 DMAC, | 179 | * Renesas sound Gen1 needs 1 DMAC, |
@@ -197,57 +186,41 @@ static void rsnd_dma_complete(void *data) | |||
197 | * rsnd_dai_pointer_update() will be called twice, | 186 | * rsnd_dai_pointer_update() will be called twice, |
198 | * ant it will breaks io->byte_pos | 187 | * ant it will breaks io->byte_pos |
199 | */ | 188 | */ |
200 | if (dma->submit_loop) | ||
201 | rsnd_dma_continue(dma); | ||
202 | |||
203 | rsnd_unlock(priv, flags); | ||
204 | 189 | ||
205 | rsnd_dai_pointer_update(io, io->byte_per_period); | 190 | rsnd_dai_pointer_update(io, io->byte_per_period); |
206 | } | 191 | } |
207 | 192 | ||
208 | static void __rsnd_dma_start(struct rsnd_dma *dma) | 193 | void rsnd_dma_start(struct rsnd_dma *dma) |
209 | { | 194 | { |
210 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 195 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
211 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 196 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
212 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 197 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
213 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 198 | struct snd_pcm_substream *substream = io->substream; |
214 | struct device *dev = rsnd_priv_to_dev(priv); | 199 | struct device *dev = rsnd_priv_to_dev(priv); |
215 | struct dma_async_tx_descriptor *desc; | 200 | struct dma_async_tx_descriptor *desc; |
216 | dma_addr_t buf; | ||
217 | size_t len = io->byte_per_period; | ||
218 | int i; | ||
219 | 201 | ||
220 | for (i = 0; i < dma->submit_loop; i++) { | 202 | desc = dmaengine_prep_dma_cyclic(dma->chan, |
221 | 203 | (dma->addr) ? dma->addr : | |
222 | buf = runtime->dma_addr + | 204 | substream->runtime->dma_addr, |
223 | rsnd_dai_pointer_offset(io, dma->offset + len); | 205 | snd_pcm_lib_buffer_bytes(substream), |
224 | dma->offset = len; | 206 | snd_pcm_lib_period_bytes(substream), |
225 | 207 | dma->dir, | |
226 | desc = dmaengine_prep_slave_single( | 208 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
227 | dma->chan, buf, len, dma->dir, | ||
228 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
229 | if (!desc) { | ||
230 | dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); | ||
231 | return; | ||
232 | } | ||
233 | 209 | ||
234 | desc->callback = rsnd_dma_complete; | 210 | if (!desc) { |
235 | desc->callback_param = dma; | 211 | dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); |
212 | return; | ||
213 | } | ||
236 | 214 | ||
237 | if (dmaengine_submit(desc) < 0) { | 215 | desc->callback = rsnd_dma_complete; |
238 | dev_err(dev, "dmaengine_submit() fail\n"); | 216 | desc->callback_param = dma; |
239 | return; | ||
240 | } | ||
241 | 217 | ||
242 | dma_async_issue_pending(dma->chan); | 218 | if (dmaengine_submit(desc) < 0) { |
219 | dev_err(dev, "dmaengine_submit() fail\n"); | ||
220 | return; | ||
243 | } | 221 | } |
244 | } | ||
245 | |||
246 | static void rsnd_dma_do_work(struct work_struct *work) | ||
247 | { | ||
248 | struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); | ||
249 | 222 | ||
250 | __rsnd_dma_start(dma); | 223 | dma_async_issue_pending(dma->chan); |
251 | } | 224 | } |
252 | 225 | ||
253 | int rsnd_dma_available(struct rsnd_dma *dma) | 226 | int rsnd_dma_available(struct rsnd_dma *dma) |
@@ -261,14 +234,27 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) | |||
261 | { | 234 | { |
262 | if (mod) | 235 | if (mod) |
263 | return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", | 236 | return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", |
264 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | 237 | rsnd_mod_dma_name(mod), rsnd_mod_id(mod)); |
265 | else | 238 | else |
266 | return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); | 239 | return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); |
267 | 240 | ||
268 | } | 241 | } |
269 | 242 | ||
270 | static void rsnd_dma_of_name(struct rsnd_dma *dma, | 243 | static void rsnd_dma_of_name(struct rsnd_mod *mod_from, |
271 | int is_play, char *dma_name) | 244 | struct rsnd_mod *mod_to, |
245 | char *dma_name) | ||
246 | { | ||
247 | int index = 0; | ||
248 | |||
249 | index = _rsnd_dma_of_name(dma_name + index, mod_from); | ||
250 | *(dma_name + index++) = '_'; | ||
251 | index = _rsnd_dma_of_name(dma_name + index, mod_to); | ||
252 | } | ||
253 | |||
254 | static void rsnd_dma_of_path(struct rsnd_dma *dma, | ||
255 | int is_play, | ||
256 | struct rsnd_mod **mod_from, | ||
257 | struct rsnd_mod **mod_to) | ||
272 | { | 258 | { |
273 | struct rsnd_mod *this = rsnd_dma_to_mod(dma); | 259 | struct rsnd_mod *this = rsnd_dma_to_mod(dma); |
274 | struct rsnd_dai_stream *io = rsnd_mod_to_io(this); | 260 | struct rsnd_dai_stream *io = rsnd_mod_to_io(this); |
@@ -276,7 +262,6 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, | |||
276 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 262 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
277 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); | 263 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); |
278 | struct rsnd_mod *mod[MOD_MAX]; | 264 | struct rsnd_mod *mod[MOD_MAX]; |
279 | struct rsnd_mod *src_mod, *dst_mod; | ||
280 | int i, index; | 265 | int i, index; |
281 | 266 | ||
282 | 267 | ||
@@ -297,31 +282,34 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, | |||
297 | for (i = 1; i < MOD_MAX; i++) { | 282 | for (i = 1; i < MOD_MAX; i++) { |
298 | if (!src) { | 283 | if (!src) { |
299 | mod[i] = ssi; | 284 | mod[i] = ssi; |
300 | break; | ||
301 | } else if (!dvc) { | 285 | } else if (!dvc) { |
302 | mod[i] = src; | 286 | mod[i] = src; |
303 | src = NULL; | 287 | src = NULL; |
304 | } else { | 288 | } else { |
305 | mod[i] = dvc; | 289 | if ((!is_play) && (this == src)) |
290 | this = dvc; | ||
291 | |||
292 | mod[i] = (is_play) ? src : dvc; | ||
293 | i++; | ||
294 | mod[i] = (is_play) ? dvc : src; | ||
295 | src = NULL; | ||
306 | dvc = NULL; | 296 | dvc = NULL; |
307 | } | 297 | } |
308 | 298 | ||
309 | if (mod[i] == this) | 299 | if (mod[i] == this) |
310 | index = i; | 300 | index = i; |
301 | |||
302 | if (mod[i] == ssi) | ||
303 | break; | ||
311 | } | 304 | } |
312 | 305 | ||
313 | if (is_play) { | 306 | if (is_play) { |
314 | src_mod = mod[index - 1]; | 307 | *mod_from = mod[index - 1]; |
315 | dst_mod = mod[index]; | 308 | *mod_to = mod[index]; |
316 | } else { | 309 | } else { |
317 | src_mod = mod[index]; | 310 | *mod_from = mod[index]; |
318 | dst_mod = mod[index + 1]; | 311 | *mod_to = mod[index - 1]; |
319 | } | 312 | } |
320 | |||
321 | index = 0; | ||
322 | index = _rsnd_dma_of_name(dma_name + index, src_mod); | ||
323 | *(dma_name + index++) = '_'; | ||
324 | index = _rsnd_dma_of_name(dma_name + index, dst_mod); | ||
325 | } | 313 | } |
326 | 314 | ||
327 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | 315 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, |
@@ -329,6 +317,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
329 | { | 317 | { |
330 | struct device *dev = rsnd_priv_to_dev(priv); | 318 | struct device *dev = rsnd_priv_to_dev(priv); |
331 | struct dma_slave_config cfg; | 319 | struct dma_slave_config cfg; |
320 | struct rsnd_mod *mod_from; | ||
321 | struct rsnd_mod *mod_to; | ||
332 | char dma_name[DMA_NAME_SIZE]; | 322 | char dma_name[DMA_NAME_SIZE]; |
333 | dma_cap_mask_t mask; | 323 | dma_cap_mask_t mask; |
334 | int ret; | 324 | int ret; |
@@ -341,13 +331,18 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
341 | dma_cap_zero(mask); | 331 | dma_cap_zero(mask); |
342 | dma_cap_set(DMA_SLAVE, mask); | 332 | dma_cap_set(DMA_SLAVE, mask); |
343 | 333 | ||
344 | if (dev->of_node) | 334 | rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); |
345 | rsnd_dma_of_name(dma, is_play, dma_name); | 335 | rsnd_dma_of_name(mod_from, mod_to, dma_name); |
346 | else | ||
347 | snprintf(dma_name, DMA_NAME_SIZE, | ||
348 | is_play ? "tx" : "rx"); | ||
349 | 336 | ||
350 | dev_dbg(dev, "dma name : %s\n", dma_name); | 337 | cfg.slave_id = id; |
338 | cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; | ||
339 | cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1); | ||
340 | cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0); | ||
341 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
342 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
343 | |||
344 | dev_dbg(dev, "dma : %s %pad -> %pad\n", | ||
345 | dma_name, &cfg.src_addr, &cfg.dst_addr); | ||
351 | 346 | ||
352 | dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, | 347 | dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, |
353 | (void *)id, dev, | 348 | (void *)id, dev, |
@@ -357,14 +352,12 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
357 | return -EIO; | 352 | return -EIO; |
358 | } | 353 | } |
359 | 354 | ||
360 | rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id); | ||
361 | |||
362 | ret = dmaengine_slave_config(dma->chan, &cfg); | 355 | ret = dmaengine_slave_config(dma->chan, &cfg); |
363 | if (ret < 0) | 356 | if (ret < 0) |
364 | goto rsnd_dma_init_err; | 357 | goto rsnd_dma_init_err; |
365 | 358 | ||
366 | dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 359 | dma->addr = is_play ? cfg.src_addr : cfg.dst_addr; |
367 | INIT_WORK(&dma->work, rsnd_dma_do_work); | 360 | dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; |
368 | 361 | ||
369 | return 0; | 362 | return 0; |
370 | 363 | ||
@@ -631,40 +624,41 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
631 | return -EINVAL; | 624 | return -EINVAL; |
632 | } | 625 | } |
633 | 626 | ||
634 | /* set clock inversion */ | ||
635 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
636 | case SND_SOC_DAIFMT_NB_IF: | ||
637 | rdai->bit_clk_inv = 0; | ||
638 | rdai->frm_clk_inv = 1; | ||
639 | break; | ||
640 | case SND_SOC_DAIFMT_IB_NF: | ||
641 | rdai->bit_clk_inv = 1; | ||
642 | rdai->frm_clk_inv = 0; | ||
643 | break; | ||
644 | case SND_SOC_DAIFMT_IB_IF: | ||
645 | rdai->bit_clk_inv = 1; | ||
646 | rdai->frm_clk_inv = 1; | ||
647 | break; | ||
648 | case SND_SOC_DAIFMT_NB_NF: | ||
649 | default: | ||
650 | rdai->bit_clk_inv = 0; | ||
651 | rdai->frm_clk_inv = 0; | ||
652 | break; | ||
653 | } | ||
654 | |||
655 | /* set format */ | 627 | /* set format */ |
656 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 628 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
657 | case SND_SOC_DAIFMT_I2S: | 629 | case SND_SOC_DAIFMT_I2S: |
658 | rdai->sys_delay = 0; | 630 | rdai->sys_delay = 0; |
659 | rdai->data_alignment = 0; | 631 | rdai->data_alignment = 0; |
632 | rdai->frm_clk_inv = 0; | ||
660 | break; | 633 | break; |
661 | case SND_SOC_DAIFMT_LEFT_J: | 634 | case SND_SOC_DAIFMT_LEFT_J: |
662 | rdai->sys_delay = 1; | 635 | rdai->sys_delay = 1; |
663 | rdai->data_alignment = 0; | 636 | rdai->data_alignment = 0; |
637 | rdai->frm_clk_inv = 1; | ||
664 | break; | 638 | break; |
665 | case SND_SOC_DAIFMT_RIGHT_J: | 639 | case SND_SOC_DAIFMT_RIGHT_J: |
666 | rdai->sys_delay = 1; | 640 | rdai->sys_delay = 1; |
667 | rdai->data_alignment = 1; | 641 | rdai->data_alignment = 1; |
642 | rdai->frm_clk_inv = 1; | ||
643 | break; | ||
644 | } | ||
645 | |||
646 | /* set clock inversion */ | ||
647 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
648 | case SND_SOC_DAIFMT_NB_IF: | ||
649 | rdai->bit_clk_inv = rdai->bit_clk_inv; | ||
650 | rdai->frm_clk_inv = !rdai->frm_clk_inv; | ||
651 | break; | ||
652 | case SND_SOC_DAIFMT_IB_NF: | ||
653 | rdai->bit_clk_inv = !rdai->bit_clk_inv; | ||
654 | rdai->frm_clk_inv = rdai->frm_clk_inv; | ||
655 | break; | ||
656 | case SND_SOC_DAIFMT_IB_IF: | ||
657 | rdai->bit_clk_inv = !rdai->bit_clk_inv; | ||
658 | rdai->frm_clk_inv = !rdai->frm_clk_inv; | ||
659 | break; | ||
660 | case SND_SOC_DAIFMT_NB_NF: | ||
661 | default: | ||
668 | break; | 662 | break; |
669 | } | 663 | } |
670 | 664 | ||
@@ -734,12 +728,13 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, | |||
734 | struct device_node *dai_node, *dai_np; | 728 | struct device_node *dai_node, *dai_np; |
735 | struct device_node *ssi_node, *ssi_np; | 729 | struct device_node *ssi_node, *ssi_np; |
736 | struct device_node *src_node, *src_np; | 730 | struct device_node *src_node, *src_np; |
731 | struct device_node *dvc_node, *dvc_np; | ||
737 | struct device_node *playback, *capture; | 732 | struct device_node *playback, *capture; |
738 | struct rsnd_dai_platform_info *dai_info; | 733 | struct rsnd_dai_platform_info *dai_info; |
739 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | 734 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); |
740 | struct device *dev = &pdev->dev; | 735 | struct device *dev = &pdev->dev; |
741 | int nr, i; | 736 | int nr, i; |
742 | int dai_i, ssi_i, src_i; | 737 | int dai_i, ssi_i, src_i, dvc_i; |
743 | 738 | ||
744 | if (!of_data) | 739 | if (!of_data) |
745 | return; | 740 | return; |
@@ -765,6 +760,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, | |||
765 | 760 | ||
766 | ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); | 761 | ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); |
767 | src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); | 762 | src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); |
763 | dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); | ||
768 | 764 | ||
769 | #define mod_parse(name) \ | 765 | #define mod_parse(name) \ |
770 | if (name##_node) { \ | 766 | if (name##_node) { \ |
@@ -800,6 +796,7 @@ if (name##_node) { \ | |||
800 | 796 | ||
801 | mod_parse(ssi); | 797 | mod_parse(ssi); |
802 | mod_parse(src); | 798 | mod_parse(src); |
799 | mod_parse(dvc); | ||
803 | 800 | ||
804 | if (playback) | 801 | if (playback) |
805 | of_node_put(playback); | 802 | of_node_put(playback); |
@@ -948,19 +945,17 @@ static struct snd_pcm_ops rsnd_pcm_ops = { | |||
948 | 945 | ||
949 | static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) | 946 | static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) |
950 | { | 947 | { |
951 | struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | 948 | struct snd_soc_dai *dai = rtd->cpu_dai; |
952 | struct rsnd_dai *rdai; | 949 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
953 | int i, ret; | 950 | int ret; |
954 | 951 | ||
955 | for_each_rsnd_dai(rdai, priv, i) { | 952 | ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd); |
956 | ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd); | 953 | if (ret) |
957 | if (ret) | 954 | return ret; |
958 | return ret; | ||
959 | 955 | ||
960 | ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd); | 956 | ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd); |
961 | if (ret) | 957 | if (ret) |
962 | return ret; | 958 | return ret; |
963 | } | ||
964 | 959 | ||
965 | return snd_pcm_lib_preallocate_pages_for_all( | 960 | return snd_pcm_lib_preallocate_pages_for_all( |
966 | rtd->pcm, | 961 | rtd->pcm, |
@@ -1047,11 +1042,11 @@ static int rsnd_probe(struct platform_device *pdev) | |||
1047 | for_each_rsnd_dai(rdai, priv, i) { | 1042 | for_each_rsnd_dai(rdai, priv, i) { |
1048 | ret = rsnd_dai_call(probe, &rdai->playback, rdai); | 1043 | ret = rsnd_dai_call(probe, &rdai->playback, rdai); |
1049 | if (ret) | 1044 | if (ret) |
1050 | return ret; | 1045 | goto exit_snd_probe; |
1051 | 1046 | ||
1052 | ret = rsnd_dai_call(probe, &rdai->capture, rdai); | 1047 | ret = rsnd_dai_call(probe, &rdai->capture, rdai); |
1053 | if (ret) | 1048 | if (ret) |
1054 | return ret; | 1049 | goto exit_snd_probe; |
1055 | } | 1050 | } |
1056 | 1051 | ||
1057 | /* | 1052 | /* |
@@ -1079,6 +1074,11 @@ static int rsnd_probe(struct platform_device *pdev) | |||
1079 | 1074 | ||
1080 | exit_snd_soc: | 1075 | exit_snd_soc: |
1081 | snd_soc_unregister_platform(dev); | 1076 | snd_soc_unregister_platform(dev); |
1077 | exit_snd_probe: | ||
1078 | for_each_rsnd_dai(rdai, priv, i) { | ||
1079 | rsnd_dai_call(remove, &rdai->playback, rdai); | ||
1080 | rsnd_dai_call(remove, &rdai->capture, rdai); | ||
1081 | } | ||
1082 | 1082 | ||
1083 | return ret; | 1083 | return ret; |
1084 | } | 1084 | } |
@@ -1087,21 +1087,16 @@ static int rsnd_remove(struct platform_device *pdev) | |||
1087 | { | 1087 | { |
1088 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | 1088 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); |
1089 | struct rsnd_dai *rdai; | 1089 | struct rsnd_dai *rdai; |
1090 | int ret, i; | 1090 | int ret = 0, i; |
1091 | 1091 | ||
1092 | pm_runtime_disable(&pdev->dev); | 1092 | pm_runtime_disable(&pdev->dev); |
1093 | 1093 | ||
1094 | for_each_rsnd_dai(rdai, priv, i) { | 1094 | for_each_rsnd_dai(rdai, priv, i) { |
1095 | ret = rsnd_dai_call(remove, &rdai->playback, rdai); | 1095 | ret |= rsnd_dai_call(remove, &rdai->playback, rdai); |
1096 | if (ret) | 1096 | ret |= rsnd_dai_call(remove, &rdai->capture, rdai); |
1097 | return ret; | ||
1098 | |||
1099 | ret = rsnd_dai_call(remove, &rdai->capture, rdai); | ||
1100 | if (ret) | ||
1101 | return ret; | ||
1102 | } | 1097 | } |
1103 | 1098 | ||
1104 | return 0; | 1099 | return ret; |
1105 | } | 1100 | } |
1106 | 1101 | ||
1107 | static struct platform_driver rsnd_driver = { | 1102 | static struct platform_driver rsnd_driver = { |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index ed0007006899..3f443930c2b1 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -20,7 +20,8 @@ struct rsnd_dvc { | |||
20 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ | 20 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ |
21 | struct rsnd_mod mod; | 21 | struct rsnd_mod mod; |
22 | struct clk *clk; | 22 | struct clk *clk; |
23 | long volume[RSND_DVC_VOLUME_NUM]; | 23 | u8 volume[RSND_DVC_VOLUME_NUM]; |
24 | u8 mute[RSND_DVC_VOLUME_NUM]; | ||
24 | }; | 25 | }; |
25 | 26 | ||
26 | #define rsnd_mod_to_dvc(_mod) \ | 27 | #define rsnd_mod_to_dvc(_mod) \ |
@@ -37,13 +38,18 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) | |||
37 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 38 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
38 | u32 max = (0x00800000 - 1); | 39 | u32 max = (0x00800000 - 1); |
39 | u32 vol[RSND_DVC_VOLUME_NUM]; | 40 | u32 vol[RSND_DVC_VOLUME_NUM]; |
41 | u32 mute = 0; | ||
40 | int i; | 42 | int i; |
41 | 43 | ||
42 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) | 44 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { |
43 | vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; | 45 | vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; |
46 | mute |= (!!dvc->mute[i]) << i; | ||
47 | } | ||
44 | 48 | ||
45 | rsnd_mod_write(mod, DVC_VOL0R, vol[0]); | 49 | rsnd_mod_write(mod, DVC_VOL0R, vol[0]); |
46 | rsnd_mod_write(mod, DVC_VOL1R, vol[1]); | 50 | rsnd_mod_write(mod, DVC_VOL1R, vol[1]); |
51 | |||
52 | rsnd_mod_write(mod, DVC_ZCMCR, mute); | ||
47 | } | 53 | } |
48 | 54 | ||
49 | static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, | 55 | static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, |
@@ -96,8 +102,8 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, | |||
96 | 102 | ||
97 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); | 103 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); |
98 | 104 | ||
99 | /* enable Volume */ | 105 | /* enable Volume / Mute */ |
100 | rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x100); | 106 | rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101); |
101 | 107 | ||
102 | /* ch0/ch1 Volume */ | 108 | /* ch0/ch1 Volume */ |
103 | rsnd_dvc_volume_update(dvc_mod); | 109 | rsnd_dvc_volume_update(dvc_mod); |
@@ -140,10 +146,20 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, | |||
140 | static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, | 146 | static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, |
141 | struct snd_ctl_elem_info *uinfo) | 147 | struct snd_ctl_elem_info *uinfo) |
142 | { | 148 | { |
143 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 149 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); |
150 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
151 | u8 *val = (u8 *)kctrl->private_value; | ||
152 | |||
144 | uinfo->count = RSND_DVC_VOLUME_NUM; | 153 | uinfo->count = RSND_DVC_VOLUME_NUM; |
145 | uinfo->value.integer.min = 0; | 154 | uinfo->value.integer.min = 0; |
146 | uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; | 155 | |
156 | if (val == dvc->volume) { | ||
157 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
158 | uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; | ||
159 | } else { | ||
160 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
161 | uinfo->value.integer.max = 1; | ||
162 | } | ||
147 | 163 | ||
148 | return 0; | 164 | return 0; |
149 | } | 165 | } |
@@ -151,12 +167,11 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, | |||
151 | static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, | 167 | static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, |
152 | struct snd_ctl_elem_value *ucontrol) | 168 | struct snd_ctl_elem_value *ucontrol) |
153 | { | 169 | { |
154 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | 170 | u8 *val = (u8 *)kctrl->private_value; |
155 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
156 | int i; | 171 | int i; |
157 | 172 | ||
158 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) | 173 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) |
159 | ucontrol->value.integer.value[i] = dvc->volume[i]; | 174 | ucontrol->value.integer.value[i] = val[i]; |
160 | 175 | ||
161 | return 0; | 176 | return 0; |
162 | } | 177 | } |
@@ -165,51 +180,38 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, | |||
165 | struct snd_ctl_elem_value *ucontrol) | 180 | struct snd_ctl_elem_value *ucontrol) |
166 | { | 181 | { |
167 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | 182 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); |
168 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 183 | u8 *val = (u8 *)kctrl->private_value; |
169 | int i, change = 0; | 184 | int i, change = 0; |
170 | 185 | ||
171 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { | 186 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { |
172 | if (ucontrol->value.integer.value[i] < 0 || | 187 | change |= (ucontrol->value.integer.value[i] != val[i]); |
173 | ucontrol->value.integer.value[i] > RSND_DVC_VOLUME_MAX) | 188 | val[i] = ucontrol->value.integer.value[i]; |
174 | return -EINVAL; | ||
175 | |||
176 | change |= (ucontrol->value.integer.value[i] != dvc->volume[i]); | ||
177 | } | 189 | } |
178 | 190 | ||
179 | if (change) { | 191 | if (change) |
180 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) | ||
181 | dvc->volume[i] = ucontrol->value.integer.value[i]; | ||
182 | |||
183 | rsnd_dvc_volume_update(mod); | 192 | rsnd_dvc_volume_update(mod); |
184 | } | ||
185 | 193 | ||
186 | return change; | 194 | return change; |
187 | } | 195 | } |
188 | 196 | ||
189 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | 197 | static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod, |
190 | struct rsnd_dai *rdai, | 198 | struct rsnd_dai *rdai, |
191 | struct snd_soc_pcm_runtime *rtd) | 199 | struct snd_soc_pcm_runtime *rtd, |
200 | const unsigned char *name, | ||
201 | u8 *private) | ||
192 | { | 202 | { |
193 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
194 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
195 | struct device *dev = rsnd_priv_to_dev(priv); | ||
196 | struct snd_card *card = rtd->card->snd_card; | 203 | struct snd_card *card = rtd->card->snd_card; |
197 | struct snd_kcontrol *kctrl; | 204 | struct snd_kcontrol *kctrl; |
198 | static struct snd_kcontrol_new knew = { | 205 | struct snd_kcontrol_new knew = { |
199 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
200 | .name = "Playback Volume", | 207 | .name = name, |
201 | .info = rsnd_dvc_volume_info, | 208 | .info = rsnd_dvc_volume_info, |
202 | .get = rsnd_dvc_volume_get, | 209 | .get = rsnd_dvc_volume_get, |
203 | .put = rsnd_dvc_volume_put, | 210 | .put = rsnd_dvc_volume_put, |
211 | .private_value = (unsigned long)private, | ||
204 | }; | 212 | }; |
205 | int ret; | 213 | int ret; |
206 | 214 | ||
207 | if (!rsnd_dai_is_play(rdai, io)) { | ||
208 | dev_err(dev, "DVC%d is connected to Capture DAI\n", | ||
209 | rsnd_mod_id(mod)); | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | |||
213 | kctrl = snd_ctl_new1(&knew, mod); | 215 | kctrl = snd_ctl_new1(&knew, mod); |
214 | if (!kctrl) | 216 | if (!kctrl) |
215 | return -ENOMEM; | 217 | return -ENOMEM; |
@@ -221,6 +223,33 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
221 | return 0; | 223 | return 0; |
222 | } | 224 | } |
223 | 225 | ||
226 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | ||
227 | struct rsnd_dai *rdai, | ||
228 | struct snd_soc_pcm_runtime *rtd) | ||
229 | { | ||
230 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
231 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
232 | int ret; | ||
233 | |||
234 | /* Volume */ | ||
235 | ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, | ||
236 | rsnd_dai_is_play(rdai, io) ? | ||
237 | "DVC Out Playback Volume" : "DVC In Capture Volume", | ||
238 | dvc->volume); | ||
239 | if (ret < 0) | ||
240 | return ret; | ||
241 | |||
242 | /* Mute */ | ||
243 | ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, | ||
244 | rsnd_dai_is_play(rdai, io) ? | ||
245 | "DVC Out Mute Switch" : "DVC In Mute Switch", | ||
246 | dvc->mute); | ||
247 | if (ret < 0) | ||
248 | return ret; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
224 | static struct rsnd_mod_ops rsnd_dvc_ops = { | 253 | static struct rsnd_mod_ops rsnd_dvc_ops = { |
225 | .name = DVC_NAME, | 254 | .name = DVC_NAME, |
226 | .probe = rsnd_dvc_probe_gen2, | 255 | .probe = rsnd_dvc_probe_gen2, |
@@ -239,6 +268,42 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) | |||
239 | return &((struct rsnd_dvc *)(priv->dvc) + id)->mod; | 268 | return &((struct rsnd_dvc *)(priv->dvc) + id)->mod; |
240 | } | 269 | } |
241 | 270 | ||
271 | static void rsnd_of_parse_dvc(struct platform_device *pdev, | ||
272 | const struct rsnd_of_data *of_data, | ||
273 | struct rsnd_priv *priv) | ||
274 | { | ||
275 | struct device_node *node; | ||
276 | struct rsnd_dvc_platform_info *dvc_info; | ||
277 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
278 | struct device *dev = &pdev->dev; | ||
279 | int nr; | ||
280 | |||
281 | if (!of_data) | ||
282 | return; | ||
283 | |||
284 | node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); | ||
285 | if (!node) | ||
286 | return; | ||
287 | |||
288 | nr = of_get_child_count(node); | ||
289 | if (!nr) | ||
290 | goto rsnd_of_parse_dvc_end; | ||
291 | |||
292 | dvc_info = devm_kzalloc(dev, | ||
293 | sizeof(struct rsnd_dvc_platform_info) * nr, | ||
294 | GFP_KERNEL); | ||
295 | if (!dvc_info) { | ||
296 | dev_err(dev, "dvc info allocation error\n"); | ||
297 | goto rsnd_of_parse_dvc_end; | ||
298 | } | ||
299 | |||
300 | info->dvc_info = dvc_info; | ||
301 | info->dvc_info_nr = nr; | ||
302 | |||
303 | rsnd_of_parse_dvc_end: | ||
304 | of_node_put(node); | ||
305 | } | ||
306 | |||
242 | int rsnd_dvc_probe(struct platform_device *pdev, | 307 | int rsnd_dvc_probe(struct platform_device *pdev, |
243 | const struct rsnd_of_data *of_data, | 308 | const struct rsnd_of_data *of_data, |
244 | struct rsnd_priv *priv) | 309 | struct rsnd_priv *priv) |
@@ -250,6 +315,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, | |||
250 | char name[RSND_DVC_NAME_SIZE]; | 315 | char name[RSND_DVC_NAME_SIZE]; |
251 | int i, nr; | 316 | int i, nr; |
252 | 317 | ||
318 | rsnd_of_parse_dvc(pdev, of_data, priv); | ||
319 | |||
253 | nr = info->dvc_info_nr; | 320 | nr = info->dvc_info_nr; |
254 | if (!nr) | 321 | if (!nr) |
255 | return 0; | 322 | return 0; |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 1dd2b7d38c2c..3fdf3be7b99a 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -15,63 +15,35 @@ struct rsnd_gen { | |||
15 | 15 | ||
16 | struct rsnd_gen_ops *ops; | 16 | struct rsnd_gen_ops *ops; |
17 | 17 | ||
18 | struct regmap *regmap; | 18 | struct regmap *regmap[RSND_BASE_MAX]; |
19 | struct regmap_field *regs[RSND_REG_MAX]; | 19 | struct regmap_field *regs[RSND_REG_MAX]; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) | 22 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) |
23 | 23 | ||
24 | #define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \ | 24 | struct rsnd_regmap_field_conf { |
25 | [id] = { \ | 25 | int idx; |
26 | .reg = (unsigned int)gen->base[reg_id] + offset, \ | 26 | unsigned int reg_offset; |
27 | .lsb = 0, \ | 27 | unsigned int id_offset; |
28 | .msb = 31, \ | 28 | }; |
29 | .id_size = _id_size, \ | ||
30 | .id_offset = _id_offset, \ | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * basic function | ||
35 | */ | ||
36 | static int rsnd_regmap_write32(void *context, const void *_data, size_t count) | ||
37 | { | ||
38 | struct rsnd_priv *priv = context; | ||
39 | struct device *dev = rsnd_priv_to_dev(priv); | ||
40 | u32 *data = (u32 *)_data; | ||
41 | u32 val = data[1]; | ||
42 | void __iomem *reg = (void *)data[0]; | ||
43 | |||
44 | iowrite32(val, reg); | ||
45 | |||
46 | dev_dbg(dev, "w %p : %08x\n", reg, val); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static int rsnd_regmap_read32(void *context, | ||
52 | const void *_data, size_t reg_size, | ||
53 | void *_val, size_t val_size) | ||
54 | { | ||
55 | struct rsnd_priv *priv = context; | ||
56 | struct device *dev = rsnd_priv_to_dev(priv); | ||
57 | u32 *data = (u32 *)_data; | ||
58 | u32 *val = (u32 *)_val; | ||
59 | void __iomem *reg = (void *)data[0]; | ||
60 | |||
61 | *val = ioread32(reg); | ||
62 | |||
63 | dev_dbg(dev, "r %p : %08x\n", reg, *val); | ||
64 | 29 | ||
65 | return 0; | 30 | #define RSND_REG_SET(id, offset, _id_offset) \ |
31 | { \ | ||
32 | .idx = id, \ | ||
33 | .reg_offset = offset, \ | ||
34 | .id_offset = _id_offset, \ | ||
66 | } | 35 | } |
36 | /* single address mapping */ | ||
37 | #define RSND_GEN_S_REG(id, offset) \ | ||
38 | RSND_REG_SET(RSND_REG_##id, offset, 0) | ||
67 | 39 | ||
68 | static struct regmap_bus rsnd_regmap_bus = { | 40 | /* multi address mapping */ |
69 | .write = rsnd_regmap_write32, | 41 | #define RSND_GEN_M_REG(id, offset, _id_offset) \ |
70 | .read = rsnd_regmap_read32, | 42 | RSND_REG_SET(RSND_REG_##id, offset, _id_offset) |
71 | .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
72 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
73 | }; | ||
74 | 43 | ||
44 | /* | ||
45 | * basic function | ||
46 | */ | ||
75 | static int rsnd_is_accessible_reg(struct rsnd_priv *priv, | 47 | static int rsnd_is_accessible_reg(struct rsnd_priv *priv, |
76 | struct rsnd_gen *gen, enum rsnd_reg reg) | 48 | struct rsnd_gen *gen, enum rsnd_reg reg) |
77 | { | 49 | { |
@@ -88,6 +60,7 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv, | |||
88 | u32 rsnd_read(struct rsnd_priv *priv, | 60 | u32 rsnd_read(struct rsnd_priv *priv, |
89 | struct rsnd_mod *mod, enum rsnd_reg reg) | 61 | struct rsnd_mod *mod, enum rsnd_reg reg) |
90 | { | 62 | { |
63 | struct device *dev = rsnd_priv_to_dev(priv); | ||
91 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 64 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
92 | u32 val; | 65 | u32 val; |
93 | 66 | ||
@@ -96,6 +69,8 @@ u32 rsnd_read(struct rsnd_priv *priv, | |||
96 | 69 | ||
97 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); | 70 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); |
98 | 71 | ||
72 | dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val); | ||
73 | |||
99 | return val; | 74 | return val; |
100 | } | 75 | } |
101 | 76 | ||
@@ -103,17 +78,21 @@ void rsnd_write(struct rsnd_priv *priv, | |||
103 | struct rsnd_mod *mod, | 78 | struct rsnd_mod *mod, |
104 | enum rsnd_reg reg, u32 data) | 79 | enum rsnd_reg reg, u32 data) |
105 | { | 80 | { |
81 | struct device *dev = rsnd_priv_to_dev(priv); | ||
106 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 82 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
107 | 83 | ||
108 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 84 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
109 | return; | 85 | return; |
110 | 86 | ||
111 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); | 87 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); |
88 | |||
89 | dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data); | ||
112 | } | 90 | } |
113 | 91 | ||
114 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | 92 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, |
115 | enum rsnd_reg reg, u32 mask, u32 data) | 93 | enum rsnd_reg reg, u32 mask, u32 data) |
116 | { | 94 | { |
95 | struct device *dev = rsnd_priv_to_dev(priv); | ||
117 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 96 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
118 | 97 | ||
119 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 98 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
@@ -121,35 +100,63 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
121 | 100 | ||
122 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), | 101 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), |
123 | mask, data); | 102 | mask, data); |
103 | |||
104 | dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n", | ||
105 | rsnd_mod_name(mod), reg, data, mask); | ||
124 | } | 106 | } |
125 | 107 | ||
126 | static int rsnd_gen_regmap_init(struct rsnd_priv *priv, | 108 | #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ |
127 | struct rsnd_gen *gen, | 109 | _rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf)) |
128 | struct reg_field *regf) | 110 | static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, |
111 | int id_size, | ||
112 | int reg_id, | ||
113 | struct rsnd_regmap_field_conf *conf, | ||
114 | int conf_size) | ||
129 | { | 115 | { |
130 | int i; | 116 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); |
117 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
131 | struct device *dev = rsnd_priv_to_dev(priv); | 118 | struct device *dev = rsnd_priv_to_dev(priv); |
119 | struct resource *res; | ||
132 | struct regmap_config regc; | 120 | struct regmap_config regc; |
121 | struct regmap_field *regs; | ||
122 | struct regmap *regmap; | ||
123 | struct reg_field regf; | ||
124 | void __iomem *base; | ||
125 | int i; | ||
133 | 126 | ||
134 | memset(®c, 0, sizeof(regc)); | 127 | memset(®c, 0, sizeof(regc)); |
135 | regc.reg_bits = 32; | 128 | regc.reg_bits = 32; |
136 | regc.val_bits = 32; | 129 | regc.val_bits = 32; |
130 | regc.reg_stride = 4; | ||
137 | 131 | ||
138 | gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); | 132 | res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id); |
139 | if (IS_ERR(gen->regmap)) { | 133 | if (!res) |
140 | dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); | 134 | return -ENODEV; |
141 | return PTR_ERR(gen->regmap); | ||
142 | } | ||
143 | 135 | ||
144 | for (i = 0; i < RSND_REG_MAX; i++) { | 136 | base = devm_ioremap_resource(dev, res); |
145 | gen->regs[i] = NULL; | 137 | if (IS_ERR(base)) |
146 | if (!regf[i].reg) | 138 | return PTR_ERR(base); |
147 | continue; | ||
148 | 139 | ||
149 | gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); | 140 | regmap = devm_regmap_init_mmio(dev, base, ®c); |
150 | if (IS_ERR(gen->regs[i])) | 141 | if (IS_ERR(regmap)) |
151 | return PTR_ERR(gen->regs[i]); | 142 | return PTR_ERR(regmap); |
152 | 143 | ||
144 | gen->base[reg_id] = base; | ||
145 | gen->regmap[reg_id] = regmap; | ||
146 | |||
147 | for (i = 0; i < conf_size; i++) { | ||
148 | |||
149 | regf.reg = conf[i].reg_offset; | ||
150 | regf.id_offset = conf[i].id_offset; | ||
151 | regf.lsb = 0; | ||
152 | regf.msb = 31; | ||
153 | regf.id_size = id_size; | ||
154 | |||
155 | regs = devm_regmap_field_alloc(dev, regmap, regf); | ||
156 | if (IS_ERR(regs)) | ||
157 | return PTR_ERR(regs); | ||
158 | |||
159 | gen->regs[conf[i].idx] = regs; | ||
153 | } | 160 | } |
154 | 161 | ||
155 | return 0; | 162 | return 0; |
@@ -165,15 +172,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
165 | * | 172 | * |
166 | * ex) R-Car H2 case | 173 | * ex) R-Car H2 case |
167 | * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out | 174 | * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out |
168 | * SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000 | 175 | * SSI : 0xec541000 / 0xec241008 / 0xec24100c |
176 | * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 | ||
169 | * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 | 177 | * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 |
170 | * CMD : 0xec500000 / 0xec008000 0xec308000 | 178 | * CMD : 0xec500000 / / 0xec008000 0xec308000 |
171 | */ | 179 | */ |
172 | #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) | 180 | #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) |
173 | #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) | 181 | #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) |
174 | 182 | ||
175 | #define RDMA_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) | 183 | #define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) |
176 | #define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) | 184 | #define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) |
185 | |||
186 | #define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) | ||
187 | #define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) | ||
177 | 188 | ||
178 | #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) | 189 | #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) |
179 | #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) | 190 | #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) |
@@ -184,14 +195,13 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
184 | #define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) | 195 | #define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) |
185 | #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) | 196 | #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) |
186 | 197 | ||
187 | void rsnd_gen_dma_addr(struct rsnd_priv *priv, | 198 | static dma_addr_t |
188 | struct rsnd_dma *dma, | 199 | rsnd_gen2_dma_addr(struct rsnd_priv *priv, |
189 | struct dma_slave_config *cfg, | 200 | struct rsnd_mod *mod, |
190 | int is_play, int slave_id) | 201 | int is_play, int is_from) |
191 | { | 202 | { |
192 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); | 203 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); |
193 | struct device *dev = rsnd_priv_to_dev(priv); | 204 | struct device *dev = rsnd_priv_to_dev(priv); |
194 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | ||
195 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 205 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
196 | dma_addr_t ssi_reg = platform_get_resource(pdev, | 206 | dma_addr_t ssi_reg = platform_get_resource(pdev, |
197 | IORESOURCE_MEM, RSND_GEN2_SSI)->start; | 207 | IORESOURCE_MEM, RSND_GEN2_SSI)->start; |
@@ -202,170 +212,152 @@ void rsnd_gen_dma_addr(struct rsnd_priv *priv, | |||
202 | int use_dvc = !!rsnd_io_to_mod_dvc(io); | 212 | int use_dvc = !!rsnd_io_to_mod_dvc(io); |
203 | int id = rsnd_mod_id(mod); | 213 | int id = rsnd_mod_id(mod); |
204 | struct dma_addr { | 214 | struct dma_addr { |
205 | dma_addr_t src_addr; | 215 | dma_addr_t out_addr; |
206 | dma_addr_t dst_addr; | 216 | dma_addr_t in_addr; |
207 | } dma_addrs[2][2][3] = { | 217 | } dma_addrs[3][2][3] = { |
208 | { /* SRC */ | 218 | /* SRC */ |
209 | /* Capture */ | 219 | {{{ 0, 0 }, |
210 | {{ 0, 0 }, | 220 | /* Capture */ |
211 | { RDMA_SRC_O_N(src, id), 0 }, | 221 | { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, |
212 | { RDMA_CMD_O_N(src, id), 0 }}, | 222 | { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, |
213 | /* Playback */ | 223 | /* Playback */ |
214 | {{ 0, 0, }, | 224 | {{ 0, 0, }, |
215 | { 0, RDMA_SRC_I_N(src, id) }, | 225 | { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, |
216 | { 0, RDMA_SRC_I_N(src, id) }} | 226 | { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } |
217 | }, { /* SSI */ | 227 | }, |
218 | /* Capture */ | 228 | /* SSI */ |
219 | {{ RDMA_SSI_O_N(ssi, id), 0 }, | 229 | /* Capture */ |
220 | { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, | 230 | {{{ RDMA_SSI_O_N(ssi, id), 0 }, |
221 | { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }}, | 231 | { RDMA_SSIU_O_P(ssi, id), 0 }, |
222 | /* Playback */ | 232 | { RDMA_SSIU_O_P(ssi, id), 0 } }, |
223 | {{ 0, RDMA_SSI_I_N(ssi, id) }, | 233 | /* Playback */ |
224 | { RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) }, | 234 | {{ 0, RDMA_SSI_I_N(ssi, id) }, |
225 | { RDMA_CMD_O_P(src, id), RDMA_SSI_I_P(ssi, id) }} | 235 | { 0, RDMA_SSIU_I_P(ssi, id) }, |
226 | } | 236 | { 0, RDMA_SSIU_I_P(ssi, id) } } |
237 | }, | ||
238 | /* SSIU */ | ||
239 | /* Capture */ | ||
240 | {{{ RDMA_SSIU_O_N(ssi, id), 0 }, | ||
241 | { RDMA_SSIU_O_P(ssi, id), 0 }, | ||
242 | { RDMA_SSIU_O_P(ssi, id), 0 } }, | ||
243 | /* Playback */ | ||
244 | {{ 0, RDMA_SSIU_I_N(ssi, id) }, | ||
245 | { 0, RDMA_SSIU_I_P(ssi, id) }, | ||
246 | { 0, RDMA_SSIU_I_P(ssi, id) } } }, | ||
227 | }; | 247 | }; |
228 | 248 | ||
229 | cfg->slave_id = slave_id; | 249 | /* it shouldn't happen */ |
230 | cfg->src_addr = 0; | 250 | if (use_dvc & !use_src) |
231 | cfg->dst_addr = 0; | 251 | dev_err(dev, "DVC is selected without SRC\n"); |
232 | cfg->direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; | 252 | |
253 | /* use SSIU or SSI ? */ | ||
254 | if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) | ||
255 | is_ssi++; | ||
256 | |||
257 | return (is_from) ? | ||
258 | dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr : | ||
259 | dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; | ||
260 | } | ||
233 | 261 | ||
262 | dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, | ||
263 | struct rsnd_mod *mod, | ||
264 | int is_play, int is_from) | ||
265 | { | ||
234 | /* | 266 | /* |
235 | * gen1 uses default DMA addr | 267 | * gen1 uses default DMA addr |
236 | */ | 268 | */ |
237 | if (rsnd_is_gen1(priv)) | 269 | if (rsnd_is_gen1(priv)) |
238 | return; | 270 | return 0; |
239 | |||
240 | /* it shouldn't happen */ | ||
241 | if (use_dvc & !use_src) { | ||
242 | dev_err(dev, "DVC is selected without SRC\n"); | ||
243 | return; | ||
244 | } | ||
245 | 271 | ||
246 | cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; | 272 | if (!mod) |
247 | cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; | 273 | return 0; |
248 | 274 | ||
249 | dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n", | 275 | return rsnd_gen2_dma_addr(priv, mod, is_play, is_from); |
250 | id, cfg->src_addr, cfg->dst_addr); | ||
251 | } | 276 | } |
252 | 277 | ||
253 | /* | 278 | /* |
254 | * Gen2 | 279 | * Gen2 |
255 | */ | 280 | */ |
256 | |||
257 | /* single address mapping */ | ||
258 | #define RSND_GEN2_S_REG(gen, reg, id, offset) \ | ||
259 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10) | ||
260 | |||
261 | /* multi address mapping */ | ||
262 | #define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset) \ | ||
263 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10) | ||
264 | |||
265 | static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | ||
266 | { | ||
267 | struct reg_field regf[RSND_REG_MAX] = { | ||
268 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), | ||
269 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), | ||
270 | /* FIXME: it needs SSI_MODE2/3 in the future */ | ||
271 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_MODE, 0x0, 0x80), | ||
272 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_ADINR,0x4, 0x80), | ||
273 | RSND_GEN2_M_REG(gen, SSIU, SSI_CTRL, 0x10, 0x80), | ||
274 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), | ||
275 | |||
276 | RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20), | ||
277 | RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20), | ||
278 | RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20), | ||
279 | RSND_GEN2_M_REG(gen, SCU, CMD_ROUTE_SLCT, 0x18c, 0x20), | ||
280 | RSND_GEN2_M_REG(gen, SCU, CMD_CTRL, 0x190, 0x20), | ||
281 | RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40), | ||
282 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40), | ||
283 | RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40), | ||
284 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSCR, 0x21c, 0x40), | ||
285 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSVR, 0x220, 0x40), | ||
286 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40), | ||
287 | RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40), | ||
288 | RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40), | ||
289 | RSND_GEN2_M_REG(gen, SCU, DVC_SWRSR, 0xe00, 0x100), | ||
290 | RSND_GEN2_M_REG(gen, SCU, DVC_DVUIR, 0xe04, 0x100), | ||
291 | RSND_GEN2_M_REG(gen, SCU, DVC_ADINR, 0xe08, 0x100), | ||
292 | RSND_GEN2_M_REG(gen, SCU, DVC_DVUCR, 0xe10, 0x100), | ||
293 | RSND_GEN2_M_REG(gen, SCU, DVC_ZCMCR, 0xe14, 0x100), | ||
294 | RSND_GEN2_M_REG(gen, SCU, DVC_VOL0R, 0xe28, 0x100), | ||
295 | RSND_GEN2_M_REG(gen, SCU, DVC_VOL1R, 0xe2c, 0x100), | ||
296 | RSND_GEN2_M_REG(gen, SCU, DVC_DVUER, 0xe48, 0x100), | ||
297 | |||
298 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), | ||
299 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), | ||
300 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), | ||
301 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | ||
302 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | ||
303 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), | ||
304 | RSND_GEN2_S_REG(gen, ADG, DIV_EN, 0x30), | ||
305 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL0, 0x34), | ||
306 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL1, 0x38), | ||
307 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL2, 0x3c), | ||
308 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL3, 0x40), | ||
309 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL4, 0x44), | ||
310 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL0, 0x48), | ||
311 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL1, 0x4c), | ||
312 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50), | ||
313 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54), | ||
314 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58), | ||
315 | RSND_GEN2_S_REG(gen, ADG, CMDOUT_TIMSEL, 0x5c), | ||
316 | |||
317 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), | ||
318 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), | ||
319 | RSND_GEN2_M_REG(gen, SSI, SSITDR, 0x08, 0x40), | ||
320 | RSND_GEN2_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), | ||
321 | RSND_GEN2_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), | ||
322 | }; | ||
323 | |||
324 | return rsnd_gen_regmap_init(priv, gen, regf); | ||
325 | } | ||
326 | |||
327 | static int rsnd_gen2_probe(struct platform_device *pdev, | 281 | static int rsnd_gen2_probe(struct platform_device *pdev, |
328 | struct rsnd_priv *priv) | 282 | struct rsnd_priv *priv) |
329 | { | 283 | { |
330 | struct device *dev = rsnd_priv_to_dev(priv); | 284 | struct device *dev = rsnd_priv_to_dev(priv); |
331 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 285 | struct rsnd_regmap_field_conf conf_ssiu[] = { |
332 | struct resource *scu_res; | 286 | RSND_GEN_S_REG(SSI_MODE0, 0x800), |
333 | struct resource *adg_res; | 287 | RSND_GEN_S_REG(SSI_MODE1, 0x804), |
334 | struct resource *ssiu_res; | 288 | /* FIXME: it needs SSI_MODE2/3 in the future */ |
335 | struct resource *ssi_res; | 289 | RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), |
336 | int ret; | 290 | RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), |
337 | 291 | RSND_GEN_M_REG(BUSIF_DALIGN, 0x8, 0x80), | |
338 | /* | 292 | RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), |
339 | * map address | 293 | RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), |
340 | */ | 294 | }; |
341 | scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU); | 295 | struct rsnd_regmap_field_conf conf_scu[] = { |
342 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG); | 296 | RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), |
343 | ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU); | 297 | RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), |
344 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI); | 298 | RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), |
345 | 299 | RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), | |
346 | gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res); | 300 | RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), |
347 | gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res); | 301 | RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), |
348 | gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res); | 302 | RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), |
349 | gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res); | 303 | RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), |
350 | if (IS_ERR(gen->base[RSND_GEN2_SCU]) || | 304 | RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), |
351 | IS_ERR(gen->base[RSND_GEN2_ADG]) || | 305 | RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), |
352 | IS_ERR(gen->base[RSND_GEN2_SSIU]) || | 306 | RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), |
353 | IS_ERR(gen->base[RSND_GEN2_SSI])) | 307 | RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), |
354 | return -ENODEV; | 308 | RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), |
355 | 309 | RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), | |
356 | ret = rsnd_gen2_regmap_init(priv, gen); | 310 | RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), |
357 | if (ret < 0) | 311 | RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), |
358 | return ret; | 312 | RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), |
359 | 313 | RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), | |
360 | dev_dbg(dev, "Gen2 device probed\n"); | 314 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), |
361 | dev_dbg(dev, "SCU : %pap => %p\n", &scu_res->start, | 315 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), |
362 | gen->base[RSND_GEN2_SCU]); | 316 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), |
363 | dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, | 317 | }; |
364 | gen->base[RSND_GEN2_ADG]); | 318 | struct rsnd_regmap_field_conf conf_adg[] = { |
365 | dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start, | 319 | RSND_GEN_S_REG(BRRA, 0x00), |
366 | gen->base[RSND_GEN2_SSIU]); | 320 | RSND_GEN_S_REG(BRRB, 0x04), |
367 | dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, | 321 | RSND_GEN_S_REG(SSICKR, 0x08), |
368 | gen->base[RSND_GEN2_SSI]); | 322 | RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), |
323 | RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), | ||
324 | RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), | ||
325 | RSND_GEN_S_REG(DIV_EN, 0x30), | ||
326 | RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34), | ||
327 | RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38), | ||
328 | RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c), | ||
329 | RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40), | ||
330 | RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44), | ||
331 | RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48), | ||
332 | RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c), | ||
333 | RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50), | ||
334 | RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54), | ||
335 | RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), | ||
336 | RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), | ||
337 | }; | ||
338 | struct rsnd_regmap_field_conf conf_ssi[] = { | ||
339 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), | ||
340 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), | ||
341 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), | ||
342 | RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), | ||
343 | RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), | ||
344 | }; | ||
345 | int ret_ssiu; | ||
346 | int ret_scu; | ||
347 | int ret_adg; | ||
348 | int ret_ssi; | ||
349 | |||
350 | ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, conf_ssiu); | ||
351 | ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, conf_scu); | ||
352 | ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, conf_adg); | ||
353 | ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, conf_ssi); | ||
354 | if (ret_ssiu < 0 || | ||
355 | ret_scu < 0 || | ||
356 | ret_adg < 0 || | ||
357 | ret_ssi < 0) | ||
358 | return ret_ssiu | ret_scu | ret_adg | ret_ssi; | ||
359 | |||
360 | dev_dbg(dev, "Gen2 is probed\n"); | ||
369 | 361 | ||
370 | return 0; | 362 | return 0; |
371 | } | 363 | } |
@@ -374,92 +366,60 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
374 | * Gen1 | 366 | * Gen1 |
375 | */ | 367 | */ |
376 | 368 | ||
377 | /* single address mapping */ | ||
378 | #define RSND_GEN1_S_REG(gen, reg, id, offset) \ | ||
379 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) | ||
380 | |||
381 | /* multi address mapping */ | ||
382 | #define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset) \ | ||
383 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9) | ||
384 | |||
385 | static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | ||
386 | { | ||
387 | struct reg_field regf[RSND_REG_MAX] = { | ||
388 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), | ||
389 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), | ||
390 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), | ||
391 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), | ||
392 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), | ||
393 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), | ||
394 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), | ||
395 | RSND_GEN1_M_REG(gen, SRU, SRC_BUSIF_MODE, 0x20, 0x4), | ||
396 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), | ||
397 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), | ||
398 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), | ||
399 | RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40), | ||
400 | RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40), | ||
401 | RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40), | ||
402 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40), | ||
403 | RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40), | ||
404 | |||
405 | RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), | ||
406 | RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), | ||
407 | RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), | ||
408 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | ||
409 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | ||
410 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), | ||
411 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), | ||
412 | RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20), | ||
413 | |||
414 | RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), | ||
415 | RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), | ||
416 | RSND_GEN1_M_REG(gen, SSI, SSITDR, 0x08, 0x40), | ||
417 | RSND_GEN1_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), | ||
418 | RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), | ||
419 | }; | ||
420 | |||
421 | return rsnd_gen_regmap_init(priv, gen, regf); | ||
422 | } | ||
423 | |||
424 | static int rsnd_gen1_probe(struct platform_device *pdev, | 369 | static int rsnd_gen1_probe(struct platform_device *pdev, |
425 | struct rsnd_priv *priv) | 370 | struct rsnd_priv *priv) |
426 | { | 371 | { |
427 | struct device *dev = rsnd_priv_to_dev(priv); | 372 | struct device *dev = rsnd_priv_to_dev(priv); |
428 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 373 | struct rsnd_regmap_field_conf conf_sru[] = { |
429 | struct resource *sru_res; | 374 | RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00), |
430 | struct resource *adg_res; | 375 | RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08), |
431 | struct resource *ssi_res; | 376 | RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c), |
432 | int ret; | 377 | RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10), |
433 | 378 | RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0), | |
434 | /* | 379 | RSND_GEN_S_REG(SSI_MODE0, 0xD0), |
435 | * map address | 380 | RSND_GEN_S_REG(SSI_MODE1, 0xD4), |
436 | */ | 381 | RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4), |
437 | sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); | 382 | RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8), |
438 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); | 383 | RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), |
439 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); | 384 | RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), |
440 | 385 | RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), | |
441 | gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); | 386 | RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), |
442 | gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); | 387 | RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), |
443 | gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); | 388 | RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), |
444 | if (IS_ERR(gen->base[RSND_GEN1_SRU]) || | 389 | RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40), |
445 | IS_ERR(gen->base[RSND_GEN1_ADG]) || | 390 | }; |
446 | IS_ERR(gen->base[RSND_GEN1_SSI])) | 391 | struct rsnd_regmap_field_conf conf_adg[] = { |
447 | return -ENODEV; | 392 | RSND_GEN_S_REG(BRRA, 0x00), |
393 | RSND_GEN_S_REG(BRRB, 0x04), | ||
394 | RSND_GEN_S_REG(SSICKR, 0x08), | ||
395 | RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), | ||
396 | RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), | ||
397 | RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18), | ||
398 | RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c), | ||
399 | RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20), | ||
400 | }; | ||
401 | struct rsnd_regmap_field_conf conf_ssi[] = { | ||
402 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), | ||
403 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), | ||
404 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), | ||
405 | RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), | ||
406 | RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), | ||
407 | }; | ||
408 | int ret_sru; | ||
409 | int ret_adg; | ||
410 | int ret_ssi; | ||
448 | 411 | ||
449 | ret = rsnd_gen1_regmap_init(priv, gen); | 412 | ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, conf_sru); |
450 | if (ret < 0) | 413 | ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, conf_adg); |
451 | return ret; | 414 | ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, conf_ssi); |
415 | if (ret_sru < 0 || | ||
416 | ret_adg < 0 || | ||
417 | ret_ssi < 0) | ||
418 | return ret_sru | ret_adg | ret_ssi; | ||
452 | 419 | ||
453 | dev_dbg(dev, "Gen1 device probed\n"); | 420 | dev_dbg(dev, "Gen1 is probed\n"); |
454 | dev_dbg(dev, "SRU : %pap => %p\n", &sru_res->start, | ||
455 | gen->base[RSND_GEN1_SRU]); | ||
456 | dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, | ||
457 | gen->base[RSND_GEN1_ADG]); | ||
458 | dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, | ||
459 | gen->base[RSND_GEN1_SSI]); | ||
460 | 421 | ||
461 | return 0; | 422 | return 0; |
462 | |||
463 | } | 423 | } |
464 | 424 | ||
465 | /* | 425 | /* |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 39d98af5ee05..d119adf97c9c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -90,6 +90,7 @@ enum rsnd_reg { | |||
90 | RSND_REG_SHARE19, | 90 | RSND_REG_SHARE19, |
91 | RSND_REG_SHARE20, | 91 | RSND_REG_SHARE20, |
92 | RSND_REG_SHARE21, | 92 | RSND_REG_SHARE21, |
93 | RSND_REG_SHARE22, | ||
93 | 94 | ||
94 | RSND_REG_MAX, | 95 | RSND_REG_MAX, |
95 | }; | 96 | }; |
@@ -127,6 +128,7 @@ enum rsnd_reg { | |||
127 | #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 | 128 | #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 |
128 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 | 129 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 |
129 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 | 130 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 |
131 | #define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 | ||
130 | 132 | ||
131 | struct rsnd_of_data; | 133 | struct rsnd_of_data; |
132 | struct rsnd_priv; | 134 | struct rsnd_priv; |
@@ -156,12 +158,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod); | |||
156 | */ | 158 | */ |
157 | struct rsnd_dma { | 159 | struct rsnd_dma { |
158 | struct sh_dmae_slave slave; | 160 | struct sh_dmae_slave slave; |
159 | struct work_struct work; | ||
160 | struct dma_chan *chan; | 161 | struct dma_chan *chan; |
161 | enum dma_data_direction dir; | 162 | enum dma_transfer_direction dir; |
162 | 163 | dma_addr_t addr; | |
163 | int submit_loop; | ||
164 | int offset; /* it cares A/B plane */ | ||
165 | }; | 164 | }; |
166 | 165 | ||
167 | void rsnd_dma_start(struct rsnd_dma *dma); | 166 | void rsnd_dma_start(struct rsnd_dma *dma); |
@@ -185,6 +184,7 @@ enum rsnd_mod_type { | |||
185 | 184 | ||
186 | struct rsnd_mod_ops { | 185 | struct rsnd_mod_ops { |
187 | char *name; | 186 | char *name; |
187 | char* (*dma_name)(struct rsnd_mod *mod); | ||
188 | int (*probe)(struct rsnd_mod *mod, | 188 | int (*probe)(struct rsnd_mod *mod, |
189 | struct rsnd_dai *rdai); | 189 | struct rsnd_dai *rdai); |
190 | int (*remove)(struct rsnd_mod *mod, | 190 | int (*remove)(struct rsnd_mod *mod, |
@@ -224,6 +224,7 @@ void rsnd_mod_init(struct rsnd_priv *priv, | |||
224 | enum rsnd_mod_type type, | 224 | enum rsnd_mod_type type, |
225 | int id); | 225 | int id); |
226 | char *rsnd_mod_name(struct rsnd_mod *mod); | 226 | char *rsnd_mod_name(struct rsnd_mod *mod); |
227 | char *rsnd_mod_dma_name(struct rsnd_mod *mod); | ||
227 | 228 | ||
228 | /* | 229 | /* |
229 | * R-Car sound DAI | 230 | * R-Car sound DAI |
@@ -281,10 +282,9 @@ int rsnd_gen_probe(struct platform_device *pdev, | |||
281 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | 282 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
282 | struct rsnd_mod *mod, | 283 | struct rsnd_mod *mod, |
283 | enum rsnd_reg reg); | 284 | enum rsnd_reg reg); |
284 | void rsnd_gen_dma_addr(struct rsnd_priv *priv, | 285 | dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, |
285 | struct rsnd_dma *dma, | 286 | struct rsnd_mod *mod, |
286 | struct dma_slave_config *cfg, | 287 | int is_play, int is_from); |
287 | int is_play, int slave_id); | ||
288 | 288 | ||
289 | #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) | 289 | #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) |
290 | #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) | 290 | #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) |
@@ -391,8 +391,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); | |||
391 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | 391 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
392 | struct rsnd_dai_stream *io, | 392 | struct rsnd_dai_stream *io, |
393 | struct snd_pcm_runtime *runtime); | 393 | struct snd_pcm_runtime *runtime); |
394 | int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | 394 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, |
395 | struct rsnd_dai *rdai); | 395 | struct rsnd_dai *rdai, |
396 | int use_busif); | ||
397 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | ||
398 | struct rsnd_dai *rdai, | ||
399 | int use_busif); | ||
396 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | 400 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, |
397 | struct rsnd_dai *rdai); | 401 | struct rsnd_dai *rdai); |
398 | 402 | ||
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 200eda019bc7..9183e0145503 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -106,18 +106,19 @@ struct rsnd_src { | |||
106 | /* | 106 | /* |
107 | * Gen1/Gen2 common functions | 107 | * Gen1/Gen2 common functions |
108 | */ | 108 | */ |
109 | int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | 109 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, |
110 | struct rsnd_dai *rdai) | 110 | struct rsnd_dai *rdai, |
111 | int use_busif) | ||
111 | { | 112 | { |
112 | struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); | 113 | struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); |
113 | struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); | 114 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
114 | int ssi_id = rsnd_mod_id(ssi_mod); | 115 | int ssi_id = rsnd_mod_id(ssi_mod); |
115 | 116 | ||
116 | /* | 117 | /* |
117 | * SSI_MODE0 | 118 | * SSI_MODE0 |
118 | */ | 119 | */ |
119 | rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), | 120 | rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), |
120 | src_mod ? 0 : (1 << ssi_id)); | 121 | !use_busif << ssi_id); |
121 | 122 | ||
122 | /* | 123 | /* |
123 | * SSI_MODE1 | 124 | * SSI_MODE1 |
@@ -143,6 +144,46 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | |||
143 | 0x2 << shift : 0x1 << shift); | 144 | 0x2 << shift : 0x1 << shift); |
144 | } | 145 | } |
145 | 146 | ||
147 | /* | ||
148 | * DMA settings for SSIU | ||
149 | */ | ||
150 | if (use_busif) { | ||
151 | u32 val = 0x76543210; | ||
152 | u32 mask = ~0; | ||
153 | |||
154 | rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, | ||
155 | rsnd_get_adinr(ssi_mod)); | ||
156 | rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); | ||
157 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); | ||
158 | |||
159 | mask <<= runtime->channels * 4; | ||
160 | val = val & mask; | ||
161 | |||
162 | switch (runtime->sample_bits) { | ||
163 | case 16: | ||
164 | val |= 0x67452301 & ~mask; | ||
165 | break; | ||
166 | case 32: | ||
167 | val |= 0x76543210 & ~mask; | ||
168 | break; | ||
169 | } | ||
170 | rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val); | ||
171 | |||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | ||
178 | struct rsnd_dai *rdai, | ||
179 | int use_busif) | ||
180 | { | ||
181 | /* | ||
182 | * DMA settings for SSIU | ||
183 | */ | ||
184 | if (use_busif) | ||
185 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0); | ||
186 | |||
146 | return 0; | 187 | return 0; |
147 | } | 188 | } |
148 | 189 | ||
@@ -461,18 +502,45 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { | |||
461 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | 502 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, |
462 | struct rsnd_dai *rdai) | 503 | struct rsnd_dai *rdai) |
463 | { | 504 | { |
505 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
506 | struct device *dev = rsnd_priv_to_dev(priv); | ||
507 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
508 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
509 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
510 | uint ratio; | ||
464 | int ret; | 511 | int ret; |
465 | 512 | ||
513 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ | ||
514 | if (!rsnd_src_convert_rate(src)) | ||
515 | ratio = 0; | ||
516 | else if (rsnd_src_convert_rate(src) > runtime->rate) | ||
517 | ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate; | ||
518 | else | ||
519 | ratio = 100 * runtime->rate / rsnd_src_convert_rate(src); | ||
520 | |||
521 | if (ratio > 600) { | ||
522 | dev_err(dev, "FSO/FSI ratio error\n"); | ||
523 | return -EINVAL; | ||
524 | } | ||
525 | |||
466 | ret = rsnd_src_set_convert_rate(mod, rdai); | 526 | ret = rsnd_src_set_convert_rate(mod, rdai); |
467 | if (ret < 0) | 527 | if (ret < 0) |
468 | return ret; | 528 | return ret; |
469 | 529 | ||
470 | rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr(mod)); | ||
471 | rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); | ||
472 | |||
473 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); | 530 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); |
474 | 531 | ||
475 | rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); | 532 | switch (rsnd_mod_id(mod)) { |
533 | case 5: | ||
534 | case 6: | ||
535 | case 7: | ||
536 | case 8: | ||
537 | rsnd_mod_write(mod, SRC_BSDSR, 0x02400000); | ||
538 | break; | ||
539 | default: | ||
540 | rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); | ||
541 | break; | ||
542 | } | ||
543 | |||
476 | rsnd_mod_write(mod, SRC_BSISR, 0x00100060); | 544 | rsnd_mod_write(mod, SRC_BSISR, 0x00100060); |
477 | 545 | ||
478 | return 0; | 546 | return 0; |
@@ -554,7 +622,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, | |||
554 | 622 | ||
555 | rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); | 623 | rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); |
556 | 624 | ||
557 | rsnd_mod_write(mod, SSI_CTRL, 0x1); | ||
558 | rsnd_mod_write(mod, SRC_CTRL, val); | 625 | rsnd_mod_write(mod, SRC_CTRL, val); |
559 | 626 | ||
560 | return rsnd_src_start(mod, rdai); | 627 | return rsnd_src_start(mod, rdai); |
@@ -565,7 +632,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | |||
565 | { | 632 | { |
566 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 633 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
567 | 634 | ||
568 | rsnd_mod_write(mod, SSI_CTRL, 0); | ||
569 | rsnd_mod_write(mod, SRC_CTRL, 0); | 635 | rsnd_mod_write(mod, SRC_CTRL, 0); |
570 | 636 | ||
571 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); | 637 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2df723df5d19..34e84009162b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -90,6 +90,20 @@ struct rsnd_ssi { | |||
90 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 90 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) |
91 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | 91 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) |
92 | 92 | ||
93 | static int rsnd_ssi_use_busif(struct rsnd_mod *mod) | ||
94 | { | ||
95 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
96 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
97 | int use_busif = 0; | ||
98 | |||
99 | if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) | ||
100 | use_busif = 1; | ||
101 | if (rsnd_io_to_mod_src(io)) | ||
102 | use_busif = 1; | ||
103 | |||
104 | return use_busif; | ||
105 | } | ||
106 | |||
93 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | 107 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, |
94 | u32 bit) | 108 | u32 bit) |
95 | { | 109 | { |
@@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
289 | ssi->cr_own = cr; | 303 | ssi->cr_own = cr; |
290 | ssi->err = -1; /* ignore 1st error */ | 304 | ssi->err = -1; /* ignore 1st error */ |
291 | 305 | ||
292 | rsnd_src_ssi_mode_init(mod, rdai); | ||
293 | |||
294 | return 0; | 306 | return 0; |
295 | } | 307 | } |
296 | 308 | ||
@@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | |||
389 | /* enable PIO IRQ */ | 401 | /* enable PIO IRQ */ |
390 | ssi->cr_etc = UIEN | OIEN | DIEN; | 402 | ssi->cr_etc = UIEN | OIEN | DIEN; |
391 | 403 | ||
404 | rsnd_src_ssiu_start(mod, rdai, 0); | ||
405 | |||
392 | rsnd_src_enable_ssi_irq(mod, rdai); | 406 | rsnd_src_enable_ssi_irq(mod, rdai); |
393 | 407 | ||
394 | rsnd_ssi_hw_start(ssi, rdai, io); | 408 | rsnd_ssi_hw_start(ssi, rdai, io); |
@@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
405 | 419 | ||
406 | rsnd_ssi_hw_stop(ssi, rdai); | 420 | rsnd_ssi_hw_stop(ssi, rdai); |
407 | 421 | ||
422 | rsnd_src_ssiu_stop(mod, rdai, 0); | ||
423 | |||
408 | return 0; | 424 | return 0; |
409 | } | 425 | } |
410 | 426 | ||
@@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | |||
457 | /* enable DMA transfer */ | 473 | /* enable DMA transfer */ |
458 | ssi->cr_etc = DMEN; | 474 | ssi->cr_etc = DMEN; |
459 | 475 | ||
476 | rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); | ||
477 | |||
460 | rsnd_dma_start(dma); | 478 | rsnd_dma_start(dma); |
461 | 479 | ||
462 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 480 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); |
@@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
482 | 500 | ||
483 | rsnd_dma_stop(dma); | 501 | rsnd_dma_stop(dma); |
484 | 502 | ||
503 | rsnd_src_ssiu_stop(mod, rdai, 1); | ||
504 | |||
485 | return 0; | 505 | return 0; |
486 | } | 506 | } |
487 | 507 | ||
508 | static char *rsnd_ssi_dma_name(struct rsnd_mod *mod) | ||
509 | { | ||
510 | return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME; | ||
511 | } | ||
512 | |||
488 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | 513 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { |
489 | .name = SSI_NAME, | 514 | .name = SSI_NAME, |
515 | .dma_name = rsnd_ssi_dma_name, | ||
490 | .probe = rsnd_ssi_dma_probe, | 516 | .probe = rsnd_ssi_dma_probe, |
491 | .remove = rsnd_ssi_dma_remove, | 517 | .remove = rsnd_ssi_dma_remove, |
492 | .init = rsnd_ssi_init, | 518 | .init = rsnd_ssi_init, |
@@ -595,6 +621,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, | |||
595 | */ | 621 | */ |
596 | ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? | 622 | ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? |
597 | 0 : 1; | 623 | 0 : 1; |
624 | |||
625 | if (of_get_property(np, "no-busif", NULL)) | ||
626 | ssi_info->flags |= RSND_SSI_NO_BUSIF; | ||
598 | } | 627 | } |
599 | 628 | ||
600 | rsnd_of_parse_ssi_end: | 629 | rsnd_of_parse_ssi_end: |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 00e70b6c7da2..a9f82b5aba9d 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -78,7 +78,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) | |||
78 | mutex_init(&codec->cache_rw_mutex); | 78 | mutex_init(&codec->cache_rw_mutex); |
79 | 79 | ||
80 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", | 80 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", |
81 | codec->name); | 81 | codec->component.name); |
82 | 82 | ||
83 | if (codec_drv->reg_cache_default) | 83 | if (codec_drv->reg_cache_default) |
84 | codec->reg_cache = kmemdup(codec_drv->reg_cache_default, | 84 | codec->reg_cache = kmemdup(codec_drv->reg_cache_default, |
@@ -98,8 +98,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) | |||
98 | int snd_soc_cache_exit(struct snd_soc_codec *codec) | 98 | int snd_soc_cache_exit(struct snd_soc_codec *codec) |
99 | { | 99 | { |
100 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", | 100 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", |
101 | codec->name); | 101 | codec->component.name); |
102 | |||
103 | kfree(codec->reg_cache); | 102 | kfree(codec->reg_cache); |
104 | codec->reg_cache = NULL; | 103 | codec->reg_cache = NULL; |
105 | return 0; | 104 | return 0; |
@@ -192,7 +191,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec) | |||
192 | return 0; | 191 | return 0; |
193 | 192 | ||
194 | dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", | 193 | dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", |
195 | codec->name); | 194 | codec->component.name); |
196 | trace_snd_soc_cache_sync(codec, name, "start"); | 195 | trace_snd_soc_cache_sync(codec, name, "start"); |
197 | ret = snd_soc_flat_cache_sync(codec); | 196 | ret = snd_soc_flat_cache_sync(codec); |
198 | if (!ret) | 197 | if (!ret) |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 10f7f1da2aca..27c06acce205 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -37,7 +37,8 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
37 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { | 37 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { |
38 | ret = platform->driver->compr_ops->open(cstream); | 38 | ret = platform->driver->compr_ops->open(cstream); |
39 | if (ret < 0) { | 39 | if (ret < 0) { |
40 | pr_err("compress asoc: can't open platform %s\n", platform->name); | 40 | pr_err("compress asoc: can't open platform %s\n", |
41 | platform->component.name); | ||
41 | goto out; | 42 | goto out; |
42 | } | 43 | } |
43 | } | 44 | } |
@@ -84,7 +85,8 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
84 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { | 85 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { |
85 | ret = platform->driver->compr_ops->open(cstream); | 86 | ret = platform->driver->compr_ops->open(cstream); |
86 | if (ret < 0) { | 87 | if (ret < 0) { |
87 | pr_err("compress asoc: can't open platform %s\n", platform->name); | 88 | pr_err("compress asoc: can't open platform %s\n", |
89 | platform->component.name); | ||
88 | goto out; | 90 | goto out; |
89 | } | 91 | } |
90 | } | 92 | } |
@@ -627,6 +629,11 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) | |||
627 | char new_name[64]; | 629 | char new_name[64]; |
628 | int ret = 0, direction = 0; | 630 | int ret = 0, direction = 0; |
629 | 631 | ||
632 | if (rtd->num_codecs > 1) { | ||
633 | dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n"); | ||
634 | return -EINVAL; | ||
635 | } | ||
636 | |||
630 | /* check client and interface hw capabilities */ | 637 | /* check client and interface hw capabilities */ |
631 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 638 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
632 | rtd->dai_link->stream_name, codec_dai->name, num); | 639 | rtd->dai_link->stream_name, codec_dai->name, num); |
@@ -680,7 +687,7 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) | |||
680 | ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); | 687 | ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); |
681 | if (ret < 0) { | 688 | if (ret < 0) { |
682 | pr_err("compress asoc: can't create compress for codec %s\n", | 689 | pr_err("compress asoc: can't create compress for codec %s\n", |
683 | codec->name); | 690 | codec->component.name); |
684 | goto compr_err; | 691 | goto compr_err; |
685 | } | 692 | } |
686 | 693 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b87d7d882e6d..2d6c8b86b7d3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -270,12 +270,33 @@ static const struct file_operations codec_reg_fops = { | |||
270 | .llseek = default_llseek, | 270 | .llseek = default_llseek, |
271 | }; | 271 | }; |
272 | 272 | ||
273 | static struct dentry *soc_debugfs_create_dir(struct dentry *parent, | ||
274 | const char *fmt, ...) | ||
275 | { | ||
276 | struct dentry *de; | ||
277 | va_list ap; | ||
278 | char *s; | ||
279 | |||
280 | va_start(ap, fmt); | ||
281 | s = kvasprintf(GFP_KERNEL, fmt, ap); | ||
282 | va_end(ap); | ||
283 | |||
284 | if (!s) | ||
285 | return NULL; | ||
286 | |||
287 | de = debugfs_create_dir(s, parent); | ||
288 | kfree(s); | ||
289 | |||
290 | return de; | ||
291 | } | ||
292 | |||
273 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | 293 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) |
274 | { | 294 | { |
275 | struct dentry *debugfs_card_root = codec->card->debugfs_card_root; | 295 | struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; |
276 | 296 | ||
277 | codec->debugfs_codec_root = debugfs_create_dir(codec->name, | 297 | codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, |
278 | debugfs_card_root); | 298 | "codec:%s", |
299 | codec->component.name); | ||
279 | if (!codec->debugfs_codec_root) { | 300 | if (!codec->debugfs_codec_root) { |
280 | dev_warn(codec->dev, | 301 | dev_warn(codec->dev, |
281 | "ASoC: Failed to create codec debugfs directory\n"); | 302 | "ASoC: Failed to create codec debugfs directory\n"); |
@@ -304,17 +325,18 @@ static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | |||
304 | 325 | ||
305 | static void soc_init_platform_debugfs(struct snd_soc_platform *platform) | 326 | static void soc_init_platform_debugfs(struct snd_soc_platform *platform) |
306 | { | 327 | { |
307 | struct dentry *debugfs_card_root = platform->card->debugfs_card_root; | 328 | struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; |
308 | 329 | ||
309 | platform->debugfs_platform_root = debugfs_create_dir(platform->name, | 330 | platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, |
310 | debugfs_card_root); | 331 | "platform:%s", |
332 | platform->component.name); | ||
311 | if (!platform->debugfs_platform_root) { | 333 | if (!platform->debugfs_platform_root) { |
312 | dev_warn(platform->dev, | 334 | dev_warn(platform->dev, |
313 | "ASoC: Failed to create platform debugfs directory\n"); | 335 | "ASoC: Failed to create platform debugfs directory\n"); |
314 | return; | 336 | return; |
315 | } | 337 | } |
316 | 338 | ||
317 | snd_soc_dapm_debugfs_init(&platform->dapm, | 339 | snd_soc_dapm_debugfs_init(&platform->component.dapm, |
318 | platform->debugfs_platform_root); | 340 | platform->debugfs_platform_root); |
319 | } | 341 | } |
320 | 342 | ||
@@ -335,7 +357,7 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, | |||
335 | 357 | ||
336 | list_for_each_entry(codec, &codec_list, list) { | 358 | list_for_each_entry(codec, &codec_list, list) { |
337 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", | 359 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
338 | codec->name); | 360 | codec->component.name); |
339 | if (len >= 0) | 361 | if (len >= 0) |
340 | ret += len; | 362 | ret += len; |
341 | if (ret > PAGE_SIZE) { | 363 | if (ret > PAGE_SIZE) { |
@@ -406,7 +428,7 @@ static ssize_t platform_list_read_file(struct file *file, | |||
406 | 428 | ||
407 | list_for_each_entry(platform, &platform_list, list) { | 429 | list_for_each_entry(platform, &platform_list, list) { |
408 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", | 430 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
409 | platform->name); | 431 | platform->component.name); |
410 | if (len >= 0) | 432 | if (len >= 0) |
411 | ret += len; | 433 | ret += len; |
412 | if (ret > PAGE_SIZE) { | 434 | if (ret > PAGE_SIZE) { |
@@ -524,11 +546,12 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) | |||
524 | int err; | 546 | int err; |
525 | 547 | ||
526 | codec->ac97->dev.bus = &ac97_bus_type; | 548 | codec->ac97->dev.bus = &ac97_bus_type; |
527 | codec->ac97->dev.parent = codec->card->dev; | 549 | codec->ac97->dev.parent = codec->component.card->dev; |
528 | codec->ac97->dev.release = soc_ac97_device_release; | 550 | codec->ac97->dev.release = soc_ac97_device_release; |
529 | 551 | ||
530 | dev_set_name(&codec->ac97->dev, "%d-%d:%s", | 552 | dev_set_name(&codec->ac97->dev, "%d-%d:%s", |
531 | codec->card->snd_card->number, 0, codec->name); | 553 | codec->component.card->snd_card->number, 0, |
554 | codec->component.name); | ||
532 | err = device_register(&codec->ac97->dev); | 555 | err = device_register(&codec->ac97->dev); |
533 | if (err < 0) { | 556 | if (err < 0) { |
534 | dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); | 557 | dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); |
@@ -554,7 +577,7 @@ int snd_soc_suspend(struct device *dev) | |||
554 | { | 577 | { |
555 | struct snd_soc_card *card = dev_get_drvdata(dev); | 578 | struct snd_soc_card *card = dev_get_drvdata(dev); |
556 | struct snd_soc_codec *codec; | 579 | struct snd_soc_codec *codec; |
557 | int i; | 580 | int i, j; |
558 | 581 | ||
559 | /* If the initialization of this soc device failed, there is no codec | 582 | /* If the initialization of this soc device failed, there is no codec |
560 | * associated with it. Just bail out in this case. | 583 | * associated with it. Just bail out in this case. |
@@ -574,14 +597,17 @@ int snd_soc_suspend(struct device *dev) | |||
574 | 597 | ||
575 | /* mute any active DACs */ | 598 | /* mute any active DACs */ |
576 | for (i = 0; i < card->num_rtd; i++) { | 599 | for (i = 0; i < card->num_rtd; i++) { |
577 | struct snd_soc_dai *dai = card->rtd[i].codec_dai; | ||
578 | struct snd_soc_dai_driver *drv = dai->driver; | ||
579 | 600 | ||
580 | if (card->rtd[i].dai_link->ignore_suspend) | 601 | if (card->rtd[i].dai_link->ignore_suspend) |
581 | continue; | 602 | continue; |
582 | 603 | ||
583 | if (drv->ops->digital_mute && dai->playback_active) | 604 | for (j = 0; j < card->rtd[i].num_codecs; j++) { |
584 | drv->ops->digital_mute(dai, 1); | 605 | struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; |
606 | struct snd_soc_dai_driver *drv = dai->driver; | ||
607 | |||
608 | if (drv->ops->digital_mute && dai->playback_active) | ||
609 | drv->ops->digital_mute(dai, 1); | ||
610 | } | ||
585 | } | 611 | } |
586 | 612 | ||
587 | /* suspend all pcms */ | 613 | /* suspend all pcms */ |
@@ -612,8 +638,12 @@ int snd_soc_suspend(struct device *dev) | |||
612 | 638 | ||
613 | /* close any waiting streams and save state */ | 639 | /* close any waiting streams and save state */ |
614 | for (i = 0; i < card->num_rtd; i++) { | 640 | for (i = 0; i < card->num_rtd; i++) { |
641 | struct snd_soc_dai **codec_dais = card->rtd[i].codec_dais; | ||
615 | flush_delayed_work(&card->rtd[i].delayed_work); | 642 | flush_delayed_work(&card->rtd[i].delayed_work); |
616 | card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level; | 643 | for (j = 0; j < card->rtd[i].num_codecs; j++) { |
644 | codec_dais[j]->codec->dapm.suspend_bias_level = | ||
645 | codec_dais[j]->codec->dapm.bias_level; | ||
646 | } | ||
617 | } | 647 | } |
618 | 648 | ||
619 | for (i = 0; i < card->num_rtd; i++) { | 649 | for (i = 0; i < card->num_rtd; i++) { |
@@ -697,7 +727,7 @@ static void soc_resume_deferred(struct work_struct *work) | |||
697 | struct snd_soc_card *card = | 727 | struct snd_soc_card *card = |
698 | container_of(work, struct snd_soc_card, deferred_resume_work); | 728 | container_of(work, struct snd_soc_card, deferred_resume_work); |
699 | struct snd_soc_codec *codec; | 729 | struct snd_soc_codec *codec; |
700 | int i; | 730 | int i, j; |
701 | 731 | ||
702 | /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, | 732 | /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, |
703 | * so userspace apps are blocked from touching us | 733 | * so userspace apps are blocked from touching us |
@@ -758,14 +788,17 @@ static void soc_resume_deferred(struct work_struct *work) | |||
758 | 788 | ||
759 | /* unmute any active DACs */ | 789 | /* unmute any active DACs */ |
760 | for (i = 0; i < card->num_rtd; i++) { | 790 | for (i = 0; i < card->num_rtd; i++) { |
761 | struct snd_soc_dai *dai = card->rtd[i].codec_dai; | ||
762 | struct snd_soc_dai_driver *drv = dai->driver; | ||
763 | 791 | ||
764 | if (card->rtd[i].dai_link->ignore_suspend) | 792 | if (card->rtd[i].dai_link->ignore_suspend) |
765 | continue; | 793 | continue; |
766 | 794 | ||
767 | if (drv->ops->digital_mute && dai->playback_active) | 795 | for (j = 0; j < card->rtd[i].num_codecs; j++) { |
768 | drv->ops->digital_mute(dai, 0); | 796 | struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; |
797 | struct snd_soc_dai_driver *drv = dai->driver; | ||
798 | |||
799 | if (drv->ops->digital_mute && dai->playback_active) | ||
800 | drv->ops->digital_mute(dai, 0); | ||
801 | } | ||
769 | } | 802 | } |
770 | 803 | ||
771 | for (i = 0; i < card->num_rtd; i++) { | 804 | for (i = 0; i < card->num_rtd; i++) { |
@@ -810,12 +843,19 @@ int snd_soc_resume(struct device *dev) | |||
810 | 843 | ||
811 | /* activate pins from sleep state */ | 844 | /* activate pins from sleep state */ |
812 | for (i = 0; i < card->num_rtd; i++) { | 845 | for (i = 0; i < card->num_rtd; i++) { |
813 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 846 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
814 | struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; | 847 | struct snd_soc_dai **codec_dais = rtd->codec_dais; |
848 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
849 | int j; | ||
850 | |||
815 | if (cpu_dai->active) | 851 | if (cpu_dai->active) |
816 | pinctrl_pm_select_default_state(cpu_dai->dev); | 852 | pinctrl_pm_select_default_state(cpu_dai->dev); |
817 | if (codec_dai->active) | 853 | |
818 | pinctrl_pm_select_default_state(codec_dai->dev); | 854 | for (j = 0; j < rtd->num_codecs; j++) { |
855 | struct snd_soc_dai *codec_dai = codec_dais[j]; | ||
856 | if (codec_dai->active) | ||
857 | pinctrl_pm_select_default_state(codec_dai->dev); | ||
858 | } | ||
819 | } | 859 | } |
820 | 860 | ||
821 | /* AC97 devices might have other drivers hanging off them so | 861 | /* AC97 devices might have other drivers hanging off them so |
@@ -847,8 +887,9 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); | |||
847 | static const struct snd_soc_dai_ops null_dai_ops = { | 887 | static const struct snd_soc_dai_ops null_dai_ops = { |
848 | }; | 888 | }; |
849 | 889 | ||
850 | static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_node, | 890 | static struct snd_soc_codec *soc_find_codec( |
851 | const char *codec_name) | 891 | const struct device_node *codec_of_node, |
892 | const char *codec_name) | ||
852 | { | 893 | { |
853 | struct snd_soc_codec *codec; | 894 | struct snd_soc_codec *codec; |
854 | 895 | ||
@@ -857,7 +898,7 @@ static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_n | |||
857 | if (codec->dev->of_node != codec_of_node) | 898 | if (codec->dev->of_node != codec_of_node) |
858 | continue; | 899 | continue; |
859 | } else { | 900 | } else { |
860 | if (strcmp(codec->name, codec_name)) | 901 | if (strcmp(codec->component.name, codec_name)) |
861 | continue; | 902 | continue; |
862 | } | 903 | } |
863 | 904 | ||
@@ -886,9 +927,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
886 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 927 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
887 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 928 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
888 | struct snd_soc_component *component; | 929 | struct snd_soc_component *component; |
930 | struct snd_soc_dai_link_component *codecs = dai_link->codecs; | ||
931 | struct snd_soc_dai **codec_dais = rtd->codec_dais; | ||
889 | struct snd_soc_platform *platform; | 932 | struct snd_soc_platform *platform; |
890 | struct snd_soc_dai *cpu_dai; | 933 | struct snd_soc_dai *cpu_dai; |
891 | const char *platform_name; | 934 | const char *platform_name; |
935 | int i; | ||
892 | 936 | ||
893 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); | 937 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); |
894 | 938 | ||
@@ -915,24 +959,30 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
915 | return -EPROBE_DEFER; | 959 | return -EPROBE_DEFER; |
916 | } | 960 | } |
917 | 961 | ||
918 | /* Find CODEC from registered list */ | 962 | rtd->num_codecs = dai_link->num_codecs; |
919 | rtd->codec = soc_find_codec(dai_link->codec_of_node, | ||
920 | dai_link->codec_name); | ||
921 | if (!rtd->codec) { | ||
922 | dev_err(card->dev, "ASoC: CODEC %s not registered\n", | ||
923 | dai_link->codec_name); | ||
924 | return -EPROBE_DEFER; | ||
925 | } | ||
926 | 963 | ||
927 | /* Find CODEC DAI from registered list */ | 964 | /* Find CODEC from registered CODECs */ |
928 | rtd->codec_dai = soc_find_codec_dai(rtd->codec, | 965 | for (i = 0; i < rtd->num_codecs; i++) { |
929 | dai_link->codec_dai_name); | 966 | struct snd_soc_codec *codec; |
930 | if (!rtd->codec_dai) { | 967 | codec = soc_find_codec(codecs[i].of_node, codecs[i].name); |
931 | dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", | 968 | if (!codec) { |
932 | dai_link->codec_dai_name); | 969 | dev_err(card->dev, "ASoC: CODEC %s not registered\n", |
933 | return -EPROBE_DEFER; | 970 | codecs[i].name); |
971 | return -EPROBE_DEFER; | ||
972 | } | ||
973 | |||
974 | codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); | ||
975 | if (!codec_dais[i]) { | ||
976 | dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", | ||
977 | codecs[i].dai_name); | ||
978 | return -EPROBE_DEFER; | ||
979 | } | ||
934 | } | 980 | } |
935 | 981 | ||
982 | /* Single codec links expect codec and codec_dai in runtime data */ | ||
983 | rtd->codec_dai = codec_dais[0]; | ||
984 | rtd->codec = rtd->codec_dai->codec; | ||
985 | |||
936 | /* if there's no platform we match on the empty platform */ | 986 | /* if there's no platform we match on the empty platform */ |
937 | platform_name = dai_link->platform_name; | 987 | platform_name = dai_link->platform_name; |
938 | if (!platform_name && !dai_link->platform_of_node) | 988 | if (!platform_name && !dai_link->platform_of_node) |
@@ -945,7 +995,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
945 | dai_link->platform_of_node) | 995 | dai_link->platform_of_node) |
946 | continue; | 996 | continue; |
947 | } else { | 997 | } else { |
948 | if (strcmp(platform->name, platform_name)) | 998 | if (strcmp(platform->component.name, platform_name)) |
949 | continue; | 999 | continue; |
950 | } | 1000 | } |
951 | 1001 | ||
@@ -974,11 +1024,10 @@ static int soc_remove_platform(struct snd_soc_platform *platform) | |||
974 | } | 1024 | } |
975 | 1025 | ||
976 | /* Make sure all DAPM widgets are freed */ | 1026 | /* Make sure all DAPM widgets are freed */ |
977 | snd_soc_dapm_free(&platform->dapm); | 1027 | snd_soc_dapm_free(&platform->component.dapm); |
978 | 1028 | ||
979 | soc_cleanup_platform_debugfs(platform); | 1029 | soc_cleanup_platform_debugfs(platform); |
980 | platform->probed = 0; | 1030 | platform->probed = 0; |
981 | list_del(&platform->card_list); | ||
982 | module_put(platform->dev->driver->owner); | 1031 | module_put(platform->dev->driver->owner); |
983 | 1032 | ||
984 | return 0; | 1033 | return 0; |
@@ -1023,8 +1072,8 @@ static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) | |||
1023 | static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) | 1072 | static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) |
1024 | { | 1073 | { |
1025 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1074 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1026 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; | 1075 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1027 | int err; | 1076 | int i, err; |
1028 | 1077 | ||
1029 | /* unregister the rtd device */ | 1078 | /* unregister the rtd device */ |
1030 | if (rtd->dev_registered) { | 1079 | if (rtd->dev_registered) { |
@@ -1035,7 +1084,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) | |||
1035 | } | 1084 | } |
1036 | 1085 | ||
1037 | /* remove the CODEC DAI */ | 1086 | /* remove the CODEC DAI */ |
1038 | soc_remove_codec_dai(codec_dai, order); | 1087 | for (i = 0; i < rtd->num_codecs; i++) |
1088 | soc_remove_codec_dai(rtd->codec_dais[i], order); | ||
1039 | 1089 | ||
1040 | /* remove the cpu_dai */ | 1090 | /* remove the cpu_dai */ |
1041 | if (cpu_dai && cpu_dai->probed && | 1091 | if (cpu_dai && cpu_dai->probed && |
@@ -1048,11 +1098,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) | |||
1048 | cpu_dai->name, err); | 1098 | cpu_dai->name, err); |
1049 | } | 1099 | } |
1050 | cpu_dai->probed = 0; | 1100 | cpu_dai->probed = 0; |
1051 | 1101 | if (!cpu_dai->codec) | |
1052 | if (!cpu_dai->codec) { | ||
1053 | snd_soc_dapm_free(&cpu_dai->dapm); | ||
1054 | module_put(cpu_dai->dev->driver->owner); | 1102 | module_put(cpu_dai->dev->driver->owner); |
1055 | } | ||
1056 | } | 1103 | } |
1057 | } | 1104 | } |
1058 | 1105 | ||
@@ -1061,9 +1108,9 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, | |||
1061 | { | 1108 | { |
1062 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1109 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1063 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1110 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1064 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1065 | struct snd_soc_platform *platform = rtd->platform; | 1111 | struct snd_soc_platform *platform = rtd->platform; |
1066 | struct snd_soc_codec *codec; | 1112 | struct snd_soc_codec *codec; |
1113 | int i; | ||
1067 | 1114 | ||
1068 | /* remove the platform */ | 1115 | /* remove the platform */ |
1069 | if (platform && platform->probed && | 1116 | if (platform && platform->probed && |
@@ -1072,8 +1119,8 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, | |||
1072 | } | 1119 | } |
1073 | 1120 | ||
1074 | /* remove the CODEC-side CODEC */ | 1121 | /* remove the CODEC-side CODEC */ |
1075 | if (codec_dai) { | 1122 | for (i = 0; i < rtd->num_codecs; i++) { |
1076 | codec = codec_dai->codec; | 1123 | codec = rtd->codec_dais[i]->codec; |
1077 | if (codec && codec->probed && | 1124 | if (codec && codec->probed && |
1078 | codec->driver->remove_order == order) | 1125 | codec->driver->remove_order == order) |
1079 | soc_remove_codec(codec); | 1126 | soc_remove_codec(codec); |
@@ -1108,7 +1155,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) | |||
1108 | } | 1155 | } |
1109 | 1156 | ||
1110 | static void soc_set_name_prefix(struct snd_soc_card *card, | 1157 | static void soc_set_name_prefix(struct snd_soc_card *card, |
1111 | struct snd_soc_codec *codec) | 1158 | struct snd_soc_component *component) |
1112 | { | 1159 | { |
1113 | int i; | 1160 | int i; |
1114 | 1161 | ||
@@ -1117,11 +1164,11 @@ static void soc_set_name_prefix(struct snd_soc_card *card, | |||
1117 | 1164 | ||
1118 | for (i = 0; i < card->num_configs; i++) { | 1165 | for (i = 0; i < card->num_configs; i++) { |
1119 | struct snd_soc_codec_conf *map = &card->codec_conf[i]; | 1166 | struct snd_soc_codec_conf *map = &card->codec_conf[i]; |
1120 | if (map->of_node && codec->dev->of_node != map->of_node) | 1167 | if (map->of_node && component->dev->of_node != map->of_node) |
1121 | continue; | 1168 | continue; |
1122 | if (map->dev_name && strcmp(codec->name, map->dev_name)) | 1169 | if (map->dev_name && strcmp(component->name, map->dev_name)) |
1123 | continue; | 1170 | continue; |
1124 | codec->name_prefix = map->name_prefix; | 1171 | component->name_prefix = map->name_prefix; |
1125 | break; | 1172 | break; |
1126 | } | 1173 | } |
1127 | } | 1174 | } |
@@ -1133,9 +1180,9 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1133 | const struct snd_soc_codec_driver *driver = codec->driver; | 1180 | const struct snd_soc_codec_driver *driver = codec->driver; |
1134 | struct snd_soc_dai *dai; | 1181 | struct snd_soc_dai *dai; |
1135 | 1182 | ||
1136 | codec->card = card; | 1183 | codec->component.card = card; |
1137 | codec->dapm.card = card; | 1184 | codec->dapm.card = card; |
1138 | soc_set_name_prefix(card, codec); | 1185 | soc_set_name_prefix(card, &codec->component); |
1139 | 1186 | ||
1140 | if (!try_module_get(codec->dev->driver->owner)) | 1187 | if (!try_module_get(codec->dev->driver->owner)) |
1141 | return -ENODEV; | 1188 | return -ENODEV; |
@@ -1177,7 +1224,7 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1177 | WARN(codec->dapm.idle_bias_off && | 1224 | WARN(codec->dapm.idle_bias_off && |
1178 | codec->dapm.bias_level != SND_SOC_BIAS_OFF, | 1225 | codec->dapm.bias_level != SND_SOC_BIAS_OFF, |
1179 | "codec %s can not start from non-off bias with idle_bias_off==1\n", | 1226 | "codec %s can not start from non-off bias with idle_bias_off==1\n", |
1180 | codec->name); | 1227 | codec->component.name); |
1181 | } | 1228 | } |
1182 | 1229 | ||
1183 | if (driver->controls) | 1230 | if (driver->controls) |
@@ -1209,8 +1256,8 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
1209 | struct snd_soc_component *component; | 1256 | struct snd_soc_component *component; |
1210 | struct snd_soc_dai *dai; | 1257 | struct snd_soc_dai *dai; |
1211 | 1258 | ||
1212 | platform->card = card; | 1259 | platform->component.card = card; |
1213 | platform->dapm.card = card; | 1260 | platform->component.dapm.card = card; |
1214 | 1261 | ||
1215 | if (!try_module_get(platform->dev->driver->owner)) | 1262 | if (!try_module_get(platform->dev->driver->owner)) |
1216 | return -ENODEV; | 1263 | return -ENODEV; |
@@ -1218,7 +1265,7 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
1218 | soc_init_platform_debugfs(platform); | 1265 | soc_init_platform_debugfs(platform); |
1219 | 1266 | ||
1220 | if (driver->dapm_widgets) | 1267 | if (driver->dapm_widgets) |
1221 | snd_soc_dapm_new_controls(&platform->dapm, | 1268 | snd_soc_dapm_new_controls(&platform->component.dapm, |
1222 | driver->dapm_widgets, driver->num_dapm_widgets); | 1269 | driver->dapm_widgets, driver->num_dapm_widgets); |
1223 | 1270 | ||
1224 | /* Create DAPM widgets for each DAI stream */ | 1271 | /* Create DAPM widgets for each DAI stream */ |
@@ -1226,10 +1273,11 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
1226 | if (component->dev != platform->dev) | 1273 | if (component->dev != platform->dev) |
1227 | continue; | 1274 | continue; |
1228 | list_for_each_entry(dai, &component->dai_list, list) | 1275 | list_for_each_entry(dai, &component->dai_list, list) |
1229 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); | 1276 | snd_soc_dapm_new_dai_widgets(&platform->component.dapm, |
1277 | dai); | ||
1230 | } | 1278 | } |
1231 | 1279 | ||
1232 | platform->dapm.idle_bias_off = 1; | 1280 | platform->component.dapm.idle_bias_off = 1; |
1233 | 1281 | ||
1234 | if (driver->probe) { | 1282 | if (driver->probe) { |
1235 | ret = driver->probe(platform); | 1283 | ret = driver->probe(platform); |
@@ -1244,13 +1292,12 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
1244 | snd_soc_add_platform_controls(platform, driver->controls, | 1292 | snd_soc_add_platform_controls(platform, driver->controls, |
1245 | driver->num_controls); | 1293 | driver->num_controls); |
1246 | if (driver->dapm_routes) | 1294 | if (driver->dapm_routes) |
1247 | snd_soc_dapm_add_routes(&platform->dapm, driver->dapm_routes, | 1295 | snd_soc_dapm_add_routes(&platform->component.dapm, |
1248 | driver->num_dapm_routes); | 1296 | driver->dapm_routes, driver->num_dapm_routes); |
1249 | 1297 | ||
1250 | /* mark platform as probed and add to card platform list */ | 1298 | /* mark platform as probed and add to card platform list */ |
1251 | platform->probed = 1; | 1299 | platform->probed = 1; |
1252 | list_add(&platform->card_list, &card->platform_dev_list); | 1300 | list_add(&platform->component.dapm.list, &card->dapm_list); |
1253 | list_add(&platform->dapm.list, &card->dapm_list); | ||
1254 | 1301 | ||
1255 | return 0; | 1302 | return 0; |
1256 | 1303 | ||
@@ -1266,83 +1313,17 @@ static void rtd_release(struct device *dev) | |||
1266 | kfree(dev); | 1313 | kfree(dev); |
1267 | } | 1314 | } |
1268 | 1315 | ||
1269 | static int soc_aux_dev_init(struct snd_soc_card *card, | 1316 | static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, |
1270 | struct snd_soc_codec *codec, | 1317 | const char *name) |
1271 | int num) | ||
1272 | { | ||
1273 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | ||
1274 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | ||
1275 | int ret; | ||
1276 | |||
1277 | rtd->card = card; | ||
1278 | |||
1279 | /* do machine specific initialization */ | ||
1280 | if (aux_dev->init) { | ||
1281 | ret = aux_dev->init(&codec->dapm); | ||
1282 | if (ret < 0) | ||
1283 | return ret; | ||
1284 | } | ||
1285 | |||
1286 | rtd->codec = codec; | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | |||
1291 | static int soc_dai_link_init(struct snd_soc_card *card, | ||
1292 | struct snd_soc_codec *codec, | ||
1293 | int num) | ||
1294 | { | ||
1295 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | ||
1296 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | ||
1297 | int ret; | ||
1298 | |||
1299 | rtd->card = card; | ||
1300 | |||
1301 | /* do machine specific initialization */ | ||
1302 | if (dai_link->init) { | ||
1303 | ret = dai_link->init(rtd); | ||
1304 | if (ret < 0) | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | rtd->codec = codec; | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | static int soc_post_component_init(struct snd_soc_card *card, | ||
1314 | struct snd_soc_codec *codec, | ||
1315 | int num, int dailess) | ||
1316 | { | 1318 | { |
1317 | struct snd_soc_dai_link *dai_link = NULL; | ||
1318 | struct snd_soc_aux_dev *aux_dev = NULL; | ||
1319 | struct snd_soc_pcm_runtime *rtd; | ||
1320 | const char *name; | ||
1321 | int ret = 0; | 1319 | int ret = 0; |
1322 | 1320 | ||
1323 | if (!dailess) { | ||
1324 | dai_link = &card->dai_link[num]; | ||
1325 | rtd = &card->rtd[num]; | ||
1326 | name = dai_link->name; | ||
1327 | ret = soc_dai_link_init(card, codec, num); | ||
1328 | } else { | ||
1329 | aux_dev = &card->aux_dev[num]; | ||
1330 | rtd = &card->rtd_aux[num]; | ||
1331 | name = aux_dev->name; | ||
1332 | ret = soc_aux_dev_init(card, codec, num); | ||
1333 | } | ||
1334 | |||
1335 | if (ret < 0) { | ||
1336 | dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret); | ||
1337 | return ret; | ||
1338 | } | ||
1339 | |||
1340 | /* register the rtd device */ | 1321 | /* register the rtd device */ |
1341 | rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 1322 | rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1342 | if (!rtd->dev) | 1323 | if (!rtd->dev) |
1343 | return -ENOMEM; | 1324 | return -ENOMEM; |
1344 | device_initialize(rtd->dev); | 1325 | device_initialize(rtd->dev); |
1345 | rtd->dev->parent = card->dev; | 1326 | rtd->dev->parent = rtd->card->dev; |
1346 | rtd->dev->release = rtd_release; | 1327 | rtd->dev->release = rtd_release; |
1347 | rtd->dev->init_name = name; | 1328 | rtd->dev->init_name = name; |
1348 | dev_set_drvdata(rtd->dev, rtd); | 1329 | dev_set_drvdata(rtd->dev, rtd); |
@@ -1355,7 +1336,7 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1355 | if (ret < 0) { | 1336 | if (ret < 0) { |
1356 | /* calling put_device() here to free the rtd->dev */ | 1337 | /* calling put_device() here to free the rtd->dev */ |
1357 | put_device(rtd->dev); | 1338 | put_device(rtd->dev); |
1358 | dev_err(card->dev, | 1339 | dev_err(rtd->card->dev, |
1359 | "ASoC: failed to register runtime device: %d\n", ret); | 1340 | "ASoC: failed to register runtime device: %d\n", ret); |
1360 | return ret; | 1341 | return ret; |
1361 | } | 1342 | } |
@@ -1364,26 +1345,15 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1364 | /* add DAPM sysfs entries for this codec */ | 1345 | /* add DAPM sysfs entries for this codec */ |
1365 | ret = snd_soc_dapm_sys_add(rtd->dev); | 1346 | ret = snd_soc_dapm_sys_add(rtd->dev); |
1366 | if (ret < 0) | 1347 | if (ret < 0) |
1367 | dev_err(codec->dev, | 1348 | dev_err(rtd->dev, |
1368 | "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); | 1349 | "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); |
1369 | 1350 | ||
1370 | /* add codec sysfs entries */ | 1351 | /* add codec sysfs entries */ |
1371 | ret = device_create_file(rtd->dev, &dev_attr_codec_reg); | 1352 | ret = device_create_file(rtd->dev, &dev_attr_codec_reg); |
1372 | if (ret < 0) | 1353 | if (ret < 0) |
1373 | dev_err(codec->dev, | 1354 | dev_err(rtd->dev, |
1374 | "ASoC: failed to add codec sysfs files: %d\n", ret); | 1355 | "ASoC: failed to add codec sysfs files: %d\n", ret); |
1375 | 1356 | ||
1376 | #ifdef CONFIG_DEBUG_FS | ||
1377 | /* add DPCM sysfs entries */ | ||
1378 | if (!dailess && !dai_link->dynamic) | ||
1379 | goto out; | ||
1380 | |||
1381 | ret = soc_dpcm_debugfs_add(rtd); | ||
1382 | if (ret < 0) | ||
1383 | dev_err(rtd->dev, "ASoC: failed to add dpcm sysfs entries: %d\n", ret); | ||
1384 | |||
1385 | out: | ||
1386 | #endif | ||
1387 | return 0; | 1357 | return 0; |
1388 | } | 1358 | } |
1389 | 1359 | ||
@@ -1392,9 +1362,8 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, | |||
1392 | { | 1362 | { |
1393 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1363 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1394 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1364 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1395 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1396 | struct snd_soc_platform *platform = rtd->platform; | 1365 | struct snd_soc_platform *platform = rtd->platform; |
1397 | int ret; | 1366 | int i, ret; |
1398 | 1367 | ||
1399 | /* probe the CPU-side component, if it is a CODEC */ | 1368 | /* probe the CPU-side component, if it is a CODEC */ |
1400 | if (cpu_dai->codec && | 1369 | if (cpu_dai->codec && |
@@ -1405,12 +1374,14 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, | |||
1405 | return ret; | 1374 | return ret; |
1406 | } | 1375 | } |
1407 | 1376 | ||
1408 | /* probe the CODEC-side component */ | 1377 | /* probe the CODEC-side components */ |
1409 | if (!codec_dai->codec->probed && | 1378 | for (i = 0; i < rtd->num_codecs; i++) { |
1410 | codec_dai->codec->driver->probe_order == order) { | 1379 | if (!rtd->codec_dais[i]->codec->probed && |
1411 | ret = soc_probe_codec(card, codec_dai->codec); | 1380 | rtd->codec_dais[i]->codec->driver->probe_order == order) { |
1412 | if (ret < 0) | 1381 | ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); |
1413 | return ret; | 1382 | if (ret < 0) |
1383 | return ret; | ||
1384 | } | ||
1414 | } | 1385 | } |
1415 | 1386 | ||
1416 | /* probe the platform */ | 1387 | /* probe the platform */ |
@@ -1450,12 +1421,16 @@ static int soc_probe_codec_dai(struct snd_soc_card *card, | |||
1450 | 1421 | ||
1451 | static int soc_link_dai_widgets(struct snd_soc_card *card, | 1422 | static int soc_link_dai_widgets(struct snd_soc_card *card, |
1452 | struct snd_soc_dai_link *dai_link, | 1423 | struct snd_soc_dai_link *dai_link, |
1453 | struct snd_soc_dai *cpu_dai, | 1424 | struct snd_soc_pcm_runtime *rtd) |
1454 | struct snd_soc_dai *codec_dai) | ||
1455 | { | 1425 | { |
1426 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
1427 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1456 | struct snd_soc_dapm_widget *play_w, *capture_w; | 1428 | struct snd_soc_dapm_widget *play_w, *capture_w; |
1457 | int ret; | 1429 | int ret; |
1458 | 1430 | ||
1431 | if (rtd->num_codecs > 1) | ||
1432 | dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); | ||
1433 | |||
1459 | /* link the DAI widgets */ | 1434 | /* link the DAI widgets */ |
1460 | play_w = codec_dai->playback_widget; | 1435 | play_w = codec_dai->playback_widget; |
1461 | capture_w = cpu_dai->capture_widget; | 1436 | capture_w = cpu_dai->capture_widget; |
@@ -1488,19 +1463,18 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1488 | { | 1463 | { |
1489 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1464 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1490 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1465 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1491 | struct snd_soc_codec *codec = rtd->codec; | ||
1492 | struct snd_soc_platform *platform = rtd->platform; | 1466 | struct snd_soc_platform *platform = rtd->platform; |
1493 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1494 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1467 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1495 | int ret; | 1468 | int i, ret; |
1496 | 1469 | ||
1497 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", | 1470 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", |
1498 | card->name, num, order); | 1471 | card->name, num, order); |
1499 | 1472 | ||
1500 | /* config components */ | 1473 | /* config components */ |
1501 | cpu_dai->platform = platform; | 1474 | cpu_dai->platform = platform; |
1502 | codec_dai->card = card; | ||
1503 | cpu_dai->card = card; | 1475 | cpu_dai->card = card; |
1476 | for (i = 0; i < rtd->num_codecs; i++) | ||
1477 | rtd->codec_dais[i]->card = card; | ||
1504 | 1478 | ||
1505 | /* set default power off timeout */ | 1479 | /* set default power off timeout */ |
1506 | rtd->pmdown_time = pmdown_time; | 1480 | rtd->pmdown_time = pmdown_time; |
@@ -1509,11 +1483,8 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1509 | if (!cpu_dai->probed && | 1483 | if (!cpu_dai->probed && |
1510 | cpu_dai->driver->probe_order == order) { | 1484 | cpu_dai->driver->probe_order == order) { |
1511 | if (!cpu_dai->codec) { | 1485 | if (!cpu_dai->codec) { |
1512 | cpu_dai->dapm.card = card; | ||
1513 | if (!try_module_get(cpu_dai->dev->driver->owner)) | 1486 | if (!try_module_get(cpu_dai->dev->driver->owner)) |
1514 | return -ENODEV; | 1487 | return -ENODEV; |
1515 | |||
1516 | list_add(&cpu_dai->dapm.list, &card->dapm_list); | ||
1517 | } | 1488 | } |
1518 | 1489 | ||
1519 | if (cpu_dai->driver->probe) { | 1490 | if (cpu_dai->driver->probe) { |
@@ -1530,18 +1501,43 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1530 | } | 1501 | } |
1531 | 1502 | ||
1532 | /* probe the CODEC DAI */ | 1503 | /* probe the CODEC DAI */ |
1533 | ret = soc_probe_codec_dai(card, codec_dai, order); | 1504 | for (i = 0; i < rtd->num_codecs; i++) { |
1534 | if (ret) | 1505 | ret = soc_probe_codec_dai(card, rtd->codec_dais[i], order); |
1535 | return ret; | 1506 | if (ret) |
1507 | return ret; | ||
1508 | } | ||
1536 | 1509 | ||
1537 | /* complete DAI probe during last probe */ | 1510 | /* complete DAI probe during last probe */ |
1538 | if (order != SND_SOC_COMP_ORDER_LAST) | 1511 | if (order != SND_SOC_COMP_ORDER_LAST) |
1539 | return 0; | 1512 | return 0; |
1540 | 1513 | ||
1541 | ret = soc_post_component_init(card, codec, num, 0); | 1514 | /* do machine specific initialization */ |
1515 | if (dai_link->init) { | ||
1516 | ret = dai_link->init(rtd); | ||
1517 | if (ret < 0) { | ||
1518 | dev_err(card->dev, "ASoC: failed to init %s: %d\n", | ||
1519 | dai_link->name, ret); | ||
1520 | return ret; | ||
1521 | } | ||
1522 | } | ||
1523 | |||
1524 | ret = soc_post_component_init(rtd, dai_link->name); | ||
1542 | if (ret) | 1525 | if (ret) |
1543 | return ret; | 1526 | return ret; |
1544 | 1527 | ||
1528 | #ifdef CONFIG_DEBUG_FS | ||
1529 | /* add DPCM sysfs entries */ | ||
1530 | if (dai_link->dynamic) { | ||
1531 | ret = soc_dpcm_debugfs_add(rtd); | ||
1532 | if (ret < 0) { | ||
1533 | dev_err(rtd->dev, | ||
1534 | "ASoC: failed to add dpcm sysfs entries: %d\n", | ||
1535 | ret); | ||
1536 | return ret; | ||
1537 | } | ||
1538 | } | ||
1539 | #endif | ||
1540 | |||
1545 | ret = device_create_file(rtd->dev, &dev_attr_pmdown_time); | 1541 | ret = device_create_file(rtd->dev, &dev_attr_pmdown_time); |
1546 | if (ret < 0) | 1542 | if (ret < 0) |
1547 | dev_warn(rtd->dev, "ASoC: failed to add pmdown_time sysfs: %d\n", | 1543 | dev_warn(rtd->dev, "ASoC: failed to add pmdown_time sysfs: %d\n", |
@@ -1570,16 +1566,18 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1570 | codec2codec_close_delayed_work); | 1566 | codec2codec_close_delayed_work); |
1571 | 1567 | ||
1572 | /* link the DAI widgets */ | 1568 | /* link the DAI widgets */ |
1573 | ret = soc_link_dai_widgets(card, dai_link, | 1569 | ret = soc_link_dai_widgets(card, dai_link, rtd); |
1574 | cpu_dai, codec_dai); | ||
1575 | if (ret) | 1570 | if (ret) |
1576 | return ret; | 1571 | return ret; |
1577 | } | 1572 | } |
1578 | } | 1573 | } |
1579 | 1574 | ||
1580 | /* add platform data for AC97 devices */ | 1575 | /* add platform data for AC97 devices */ |
1581 | if (rtd->codec_dai->driver->ac97_control) | 1576 | for (i = 0; i < rtd->num_codecs; i++) { |
1582 | snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata); | 1577 | if (rtd->codec_dais[i]->driver->ac97_control) |
1578 | snd_ac97_dev_add_pdata(rtd->codec_dais[i]->codec->ac97, | ||
1579 | rtd->cpu_dai->ac97_pdata); | ||
1580 | } | ||
1583 | 1581 | ||
1584 | return 0; | 1582 | return 0; |
1585 | } | 1583 | } |
@@ -1617,11 +1615,6 @@ static int soc_register_ac97_codec(struct snd_soc_codec *codec, | |||
1617 | return 0; | 1615 | return 0; |
1618 | } | 1616 | } |
1619 | 1617 | ||
1620 | static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | ||
1621 | { | ||
1622 | return soc_register_ac97_codec(rtd->codec, rtd->codec_dai); | ||
1623 | } | ||
1624 | |||
1625 | static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) | 1618 | static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) |
1626 | { | 1619 | { |
1627 | if (codec->ac97_registered) { | 1620 | if (codec->ac97_registered) { |
@@ -1630,74 +1623,77 @@ static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) | |||
1630 | } | 1623 | } |
1631 | } | 1624 | } |
1632 | 1625 | ||
1633 | static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | 1626 | static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) |
1634 | { | 1627 | { |
1635 | soc_unregister_ac97_codec(rtd->codec); | 1628 | int i, ret; |
1636 | } | ||
1637 | #endif | ||
1638 | 1629 | ||
1639 | static struct snd_soc_codec *soc_find_matching_codec(struct snd_soc_card *card, | 1630 | for (i = 0; i < rtd->num_codecs; i++) { |
1640 | int num) | 1631 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
1641 | { | ||
1642 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | ||
1643 | struct snd_soc_codec *codec; | ||
1644 | 1632 | ||
1645 | /* find CODEC from registered CODECs */ | 1633 | ret = soc_register_ac97_codec(codec_dai->codec, codec_dai); |
1646 | list_for_each_entry(codec, &codec_list, list) { | 1634 | if (ret) { |
1647 | if (aux_dev->codec_of_node && | 1635 | while (--i >= 0) |
1648 | (codec->dev->of_node != aux_dev->codec_of_node)) | 1636 | soc_unregister_ac97_codec(codec_dai->codec); |
1649 | continue; | 1637 | return ret; |
1650 | if (aux_dev->codec_name && strcmp(codec->name, aux_dev->codec_name)) | 1638 | } |
1651 | continue; | ||
1652 | return codec; | ||
1653 | } | 1639 | } |
1654 | 1640 | ||
1655 | return NULL; | 1641 | return 0; |
1656 | } | 1642 | } |
1657 | 1643 | ||
1658 | static int soc_check_aux_dev(struct snd_soc_card *card, int num) | 1644 | static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) |
1659 | { | 1645 | { |
1660 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | 1646 | int i; |
1661 | const char *codecname = aux_dev->codec_name; | ||
1662 | struct snd_soc_codec *codec = soc_find_matching_codec(card, num); | ||
1663 | |||
1664 | if (codec) | ||
1665 | return 0; | ||
1666 | if (aux_dev->codec_of_node) | ||
1667 | codecname = of_node_full_name(aux_dev->codec_of_node); | ||
1668 | 1647 | ||
1669 | dev_err(card->dev, "ASoC: %s not registered\n", codecname); | 1648 | for (i = 0; i < rtd->num_codecs; i++) |
1670 | return -EPROBE_DEFER; | 1649 | soc_unregister_ac97_codec(rtd->codec_dais[i]->codec); |
1671 | } | 1650 | } |
1651 | #endif | ||
1672 | 1652 | ||
1673 | static int soc_probe_aux_dev(struct snd_soc_card *card, int num) | 1653 | static int soc_bind_aux_dev(struct snd_soc_card *card, int num) |
1674 | { | 1654 | { |
1655 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | ||
1675 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | 1656 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; |
1676 | const char *codecname = aux_dev->codec_name; | 1657 | const char *codecname = aux_dev->codec_name; |
1677 | int ret = -ENODEV; | ||
1678 | struct snd_soc_codec *codec = soc_find_matching_codec(card, num); | ||
1679 | 1658 | ||
1680 | if (!codec) { | 1659 | rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); |
1660 | if (!rtd->codec) { | ||
1681 | if (aux_dev->codec_of_node) | 1661 | if (aux_dev->codec_of_node) |
1682 | codecname = of_node_full_name(aux_dev->codec_of_node); | 1662 | codecname = of_node_full_name(aux_dev->codec_of_node); |
1683 | 1663 | ||
1684 | /* codec not found */ | 1664 | dev_err(card->dev, "ASoC: %s not registered\n", codecname); |
1685 | dev_err(card->dev, "ASoC: codec %s not found", codecname); | ||
1686 | return -EPROBE_DEFER; | 1665 | return -EPROBE_DEFER; |
1687 | } | 1666 | } |
1688 | 1667 | ||
1689 | if (codec->probed) { | 1668 | return 0; |
1690 | dev_err(codec->dev, "ASoC: codec already probed"); | 1669 | } |
1670 | |||
1671 | static int soc_probe_aux_dev(struct snd_soc_card *card, int num) | ||
1672 | { | ||
1673 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | ||
1674 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | ||
1675 | int ret; | ||
1676 | |||
1677 | if (rtd->codec->probed) { | ||
1678 | dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); | ||
1691 | return -EBUSY; | 1679 | return -EBUSY; |
1692 | } | 1680 | } |
1693 | 1681 | ||
1694 | ret = soc_probe_codec(card, codec); | 1682 | ret = soc_probe_codec(card, rtd->codec); |
1695 | if (ret < 0) | 1683 | if (ret < 0) |
1696 | return ret; | 1684 | return ret; |
1697 | 1685 | ||
1698 | ret = soc_post_component_init(card, codec, num, 1); | 1686 | /* do machine specific initialization */ |
1687 | if (aux_dev->init) { | ||
1688 | ret = aux_dev->init(&rtd->codec->dapm); | ||
1689 | if (ret < 0) { | ||
1690 | dev_err(card->dev, "ASoC: failed to init %s: %d\n", | ||
1691 | aux_dev->name, ret); | ||
1692 | return ret; | ||
1693 | } | ||
1694 | } | ||
1699 | 1695 | ||
1700 | return ret; | 1696 | return soc_post_component_init(rtd, aux_dev->name); |
1701 | } | 1697 | } |
1702 | 1698 | ||
1703 | static void soc_remove_aux_dev(struct snd_soc_card *card, int num) | 1699 | static void soc_remove_aux_dev(struct snd_soc_card *card, int num) |
@@ -1749,9 +1745,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1749 | goto base_error; | 1745 | goto base_error; |
1750 | } | 1746 | } |
1751 | 1747 | ||
1752 | /* check aux_devs too */ | 1748 | /* bind aux_devs too */ |
1753 | for (i = 0; i < card->num_aux_devs; i++) { | 1749 | for (i = 0; i < card->num_aux_devs; i++) { |
1754 | ret = soc_check_aux_dev(card, i); | 1750 | ret = soc_bind_aux_dev(card, i); |
1755 | if (ret != 0) | 1751 | if (ret != 0) |
1756 | goto base_error; | 1752 | goto base_error; |
1757 | } | 1753 | } |
@@ -1849,16 +1845,23 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1849 | card->num_dapm_routes); | 1845 | card->num_dapm_routes); |
1850 | 1846 | ||
1851 | for (i = 0; i < card->num_links; i++) { | 1847 | for (i = 0; i < card->num_links; i++) { |
1848 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | ||
1852 | dai_link = &card->dai_link[i]; | 1849 | dai_link = &card->dai_link[i]; |
1853 | dai_fmt = dai_link->dai_fmt; | 1850 | dai_fmt = dai_link->dai_fmt; |
1854 | 1851 | ||
1855 | if (dai_fmt) { | 1852 | if (dai_fmt) { |
1856 | ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai, | 1853 | struct snd_soc_dai **codec_dais = rtd->codec_dais; |
1857 | dai_fmt); | 1854 | int j; |
1858 | if (ret != 0 && ret != -ENOTSUPP) | 1855 | |
1859 | dev_warn(card->rtd[i].codec_dai->dev, | 1856 | for (j = 0; j < rtd->num_codecs; j++) { |
1860 | "ASoC: Failed to set DAI format: %d\n", | 1857 | struct snd_soc_dai *codec_dai = codec_dais[j]; |
1861 | ret); | 1858 | |
1859 | ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); | ||
1860 | if (ret != 0 && ret != -ENOTSUPP) | ||
1861 | dev_warn(codec_dai->dev, | ||
1862 | "ASoC: Failed to set DAI format: %d\n", | ||
1863 | ret); | ||
1864 | } | ||
1862 | } | 1865 | } |
1863 | 1866 | ||
1864 | /* If this is a regular CPU link there will be a platform */ | 1867 | /* If this is a regular CPU link there will be a platform */ |
@@ -1927,8 +1930,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1927 | } | 1930 | } |
1928 | 1931 | ||
1929 | if (card->fully_routed) | 1932 | if (card->fully_routed) |
1930 | list_for_each_entry(codec, &card->codec_dev_list, card_list) | 1933 | snd_soc_dapm_auto_nc_pins(card); |
1931 | snd_soc_dapm_auto_nc_codec_pins(codec); | ||
1932 | 1934 | ||
1933 | snd_soc_dapm_new_widgets(card); | 1935 | snd_soc_dapm_new_widgets(card); |
1934 | 1936 | ||
@@ -2058,10 +2060,15 @@ int snd_soc_poweroff(struct device *dev) | |||
2058 | 2060 | ||
2059 | /* deactivate pins to sleep state */ | 2061 | /* deactivate pins to sleep state */ |
2060 | for (i = 0; i < card->num_rtd; i++) { | 2062 | for (i = 0; i < card->num_rtd; i++) { |
2061 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 2063 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
2062 | struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; | 2064 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2063 | pinctrl_pm_select_sleep_state(codec_dai->dev); | 2065 | int j; |
2066 | |||
2064 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 2067 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
2068 | for (j = 0; j < rtd->num_codecs; j++) { | ||
2069 | struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; | ||
2070 | pinctrl_pm_select_sleep_state(codec_dai->dev); | ||
2071 | } | ||
2065 | } | 2072 | } |
2066 | 2073 | ||
2067 | return 0; | 2074 | return 0; |
@@ -2387,6 +2394,25 @@ struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, | |||
2387 | EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); | 2394 | EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); |
2388 | 2395 | ||
2389 | /** | 2396 | /** |
2397 | * snd_soc_add_component_controls - Add an array of controls to a component. | ||
2398 | * | ||
2399 | * @component: Component to add controls to | ||
2400 | * @controls: Array of controls to add | ||
2401 | * @num_controls: Number of elements in the array | ||
2402 | * | ||
2403 | * Return: 0 for success, else error. | ||
2404 | */ | ||
2405 | int snd_soc_add_component_controls(struct snd_soc_component *component, | ||
2406 | const struct snd_kcontrol_new *controls, unsigned int num_controls) | ||
2407 | { | ||
2408 | struct snd_card *card = component->card->snd_card; | ||
2409 | |||
2410 | return snd_soc_add_controls(card, component->dev, controls, | ||
2411 | num_controls, component->name_prefix, component); | ||
2412 | } | ||
2413 | EXPORT_SYMBOL_GPL(snd_soc_add_component_controls); | ||
2414 | |||
2415 | /** | ||
2390 | * snd_soc_add_codec_controls - add an array of controls to a codec. | 2416 | * snd_soc_add_codec_controls - add an array of controls to a codec. |
2391 | * Convenience function to add a list of controls. Many codecs were | 2417 | * Convenience function to add a list of controls. Many codecs were |
2392 | * duplicating this code. | 2418 | * duplicating this code. |
@@ -2398,12 +2424,10 @@ EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); | |||
2398 | * Return 0 for success, else error. | 2424 | * Return 0 for success, else error. |
2399 | */ | 2425 | */ |
2400 | int snd_soc_add_codec_controls(struct snd_soc_codec *codec, | 2426 | int snd_soc_add_codec_controls(struct snd_soc_codec *codec, |
2401 | const struct snd_kcontrol_new *controls, int num_controls) | 2427 | const struct snd_kcontrol_new *controls, unsigned int num_controls) |
2402 | { | 2428 | { |
2403 | struct snd_card *card = codec->card->snd_card; | 2429 | return snd_soc_add_component_controls(&codec->component, controls, |
2404 | 2430 | num_controls); | |
2405 | return snd_soc_add_controls(card, codec->dev, controls, num_controls, | ||
2406 | codec->name_prefix, &codec->component); | ||
2407 | } | 2431 | } |
2408 | EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls); | 2432 | EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls); |
2409 | 2433 | ||
@@ -2418,12 +2442,10 @@ EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls); | |||
2418 | * Return 0 for success, else error. | 2442 | * Return 0 for success, else error. |
2419 | */ | 2443 | */ |
2420 | int snd_soc_add_platform_controls(struct snd_soc_platform *platform, | 2444 | int snd_soc_add_platform_controls(struct snd_soc_platform *platform, |
2421 | const struct snd_kcontrol_new *controls, int num_controls) | 2445 | const struct snd_kcontrol_new *controls, unsigned int num_controls) |
2422 | { | 2446 | { |
2423 | struct snd_card *card = platform->card->snd_card; | 2447 | return snd_soc_add_component_controls(&platform->component, controls, |
2424 | 2448 | num_controls); | |
2425 | return snd_soc_add_controls(card, platform->dev, controls, num_controls, | ||
2426 | NULL, &platform->component); | ||
2427 | } | 2449 | } |
2428 | EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls); | 2450 | EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls); |
2429 | 2451 | ||
@@ -3095,7 +3117,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | |||
3095 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | 3117 | int snd_soc_limit_volume(struct snd_soc_codec *codec, |
3096 | const char *name, int max) | 3118 | const char *name, int max) |
3097 | { | 3119 | { |
3098 | struct snd_card *card = codec->card->snd_card; | 3120 | struct snd_card *card = codec->component.card->snd_card; |
3099 | struct snd_kcontrol *kctl; | 3121 | struct snd_kcontrol *kctl; |
3100 | struct soc_mixer_control *mc; | 3122 | struct soc_mixer_control *mc; |
3101 | int found = 0; | 3123 | int found = 0; |
@@ -3641,6 +3663,9 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | |||
3641 | else | 3663 | else |
3642 | snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); | 3664 | snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); |
3643 | 3665 | ||
3666 | dai->tx_mask = tx_mask; | ||
3667 | dai->rx_mask = rx_mask; | ||
3668 | |||
3644 | if (dai->driver && dai->driver->ops->set_tdm_slot) | 3669 | if (dai->driver && dai->driver->ops->set_tdm_slot) |
3645 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, | 3670 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
3646 | slots, slot_width); | 3671 | slots, slot_width); |
@@ -3713,6 +3738,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, | |||
3713 | } | 3738 | } |
3714 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | 3739 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); |
3715 | 3740 | ||
3741 | static int snd_soc_init_multicodec(struct snd_soc_card *card, | ||
3742 | struct snd_soc_dai_link *dai_link) | ||
3743 | { | ||
3744 | /* Legacy codec/codec_dai link is a single entry in multicodec */ | ||
3745 | if (dai_link->codec_name || dai_link->codec_of_node || | ||
3746 | dai_link->codec_dai_name) { | ||
3747 | dai_link->num_codecs = 1; | ||
3748 | |||
3749 | dai_link->codecs = devm_kzalloc(card->dev, | ||
3750 | sizeof(struct snd_soc_dai_link_component), | ||
3751 | GFP_KERNEL); | ||
3752 | if (!dai_link->codecs) | ||
3753 | return -ENOMEM; | ||
3754 | |||
3755 | dai_link->codecs[0].name = dai_link->codec_name; | ||
3756 | dai_link->codecs[0].of_node = dai_link->codec_of_node; | ||
3757 | dai_link->codecs[0].dai_name = dai_link->codec_dai_name; | ||
3758 | } | ||
3759 | |||
3760 | if (!dai_link->codecs) { | ||
3761 | dev_err(card->dev, "ASoC: DAI link has no CODECs\n"); | ||
3762 | return -EINVAL; | ||
3763 | } | ||
3764 | |||
3765 | return 0; | ||
3766 | } | ||
3767 | |||
3716 | /** | 3768 | /** |
3717 | * snd_soc_register_card - Register a card with the ASoC core | 3769 | * snd_soc_register_card - Register a card with the ASoC core |
3718 | * | 3770 | * |
@@ -3721,7 +3773,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | |||
3721 | */ | 3773 | */ |
3722 | int snd_soc_register_card(struct snd_soc_card *card) | 3774 | int snd_soc_register_card(struct snd_soc_card *card) |
3723 | { | 3775 | { |
3724 | int i, ret; | 3776 | int i, j, ret; |
3725 | 3777 | ||
3726 | if (!card->name || !card->dev) | 3778 | if (!card->name || !card->dev) |
3727 | return -EINVAL; | 3779 | return -EINVAL; |
@@ -3729,22 +3781,29 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
3729 | for (i = 0; i < card->num_links; i++) { | 3781 | for (i = 0; i < card->num_links; i++) { |
3730 | struct snd_soc_dai_link *link = &card->dai_link[i]; | 3782 | struct snd_soc_dai_link *link = &card->dai_link[i]; |
3731 | 3783 | ||
3732 | /* | 3784 | ret = snd_soc_init_multicodec(card, link); |
3733 | * Codec must be specified by 1 of name or OF node, | 3785 | if (ret) { |
3734 | * not both or neither. | 3786 | dev_err(card->dev, "ASoC: failed to init multicodec\n"); |
3735 | */ | 3787 | return ret; |
3736 | if (!!link->codec_name == !!link->codec_of_node) { | ||
3737 | dev_err(card->dev, | ||
3738 | "ASoC: Neither/both codec name/of_node are set for %s\n", | ||
3739 | link->name); | ||
3740 | return -EINVAL; | ||
3741 | } | 3788 | } |
3742 | /* Codec DAI name must be specified */ | 3789 | |
3743 | if (!link->codec_dai_name) { | 3790 | for (j = 0; j < link->num_codecs; j++) { |
3744 | dev_err(card->dev, | 3791 | /* |
3745 | "ASoC: codec_dai_name not set for %s\n", | 3792 | * Codec must be specified by 1 of name or OF node, |
3746 | link->name); | 3793 | * not both or neither. |
3747 | return -EINVAL; | 3794 | */ |
3795 | if (!!link->codecs[j].name == | ||
3796 | !!link->codecs[j].of_node) { | ||
3797 | dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", | ||
3798 | link->name); | ||
3799 | return -EINVAL; | ||
3800 | } | ||
3801 | /* Codec DAI name must be specified */ | ||
3802 | if (!link->codecs[j].dai_name) { | ||
3803 | dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", | ||
3804 | link->name); | ||
3805 | return -EINVAL; | ||
3806 | } | ||
3748 | } | 3807 | } |
3749 | 3808 | ||
3750 | /* | 3809 | /* |
@@ -3797,8 +3856,19 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
3797 | card->num_rtd = 0; | 3856 | card->num_rtd = 0; |
3798 | card->rtd_aux = &card->rtd[card->num_links]; | 3857 | card->rtd_aux = &card->rtd[card->num_links]; |
3799 | 3858 | ||
3800 | for (i = 0; i < card->num_links; i++) | 3859 | for (i = 0; i < card->num_links; i++) { |
3860 | card->rtd[i].card = card; | ||
3801 | card->rtd[i].dai_link = &card->dai_link[i]; | 3861 | card->rtd[i].dai_link = &card->dai_link[i]; |
3862 | card->rtd[i].codec_dais = devm_kzalloc(card->dev, | ||
3863 | sizeof(struct snd_soc_dai *) * | ||
3864 | (card->rtd[i].dai_link->num_codecs), | ||
3865 | GFP_KERNEL); | ||
3866 | if (card->rtd[i].codec_dais == NULL) | ||
3867 | return -ENOMEM; | ||
3868 | } | ||
3869 | |||
3870 | for (i = 0; i < card->num_aux_devs; i++) | ||
3871 | card->rtd_aux[i].card = card; | ||
3802 | 3872 | ||
3803 | INIT_LIST_HEAD(&card->dapm_dirty); | 3873 | INIT_LIST_HEAD(&card->dapm_dirty); |
3804 | card->instantiated = 0; | 3874 | card->instantiated = 0; |
@@ -3811,10 +3881,16 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
3811 | 3881 | ||
3812 | /* deactivate pins to sleep state */ | 3882 | /* deactivate pins to sleep state */ |
3813 | for (i = 0; i < card->num_rtd; i++) { | 3883 | for (i = 0; i < card->num_rtd; i++) { |
3814 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 3884 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
3815 | struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; | 3885 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3816 | if (!codec_dai->active) | 3886 | int j; |
3817 | pinctrl_pm_select_sleep_state(codec_dai->dev); | 3887 | |
3888 | for (j = 0; j < rtd->num_codecs; j++) { | ||
3889 | struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; | ||
3890 | if (!codec_dai->active) | ||
3891 | pinctrl_pm_select_sleep_state(codec_dai->dev); | ||
3892 | } | ||
3893 | |||
3818 | if (!cpu_dai->active) | 3894 | if (!cpu_dai->active) |
3819 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 3895 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
3820 | } | 3896 | } |
@@ -3921,16 +3997,14 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) | |||
3921 | * snd_soc_register_dais - Register a DAI with the ASoC core | 3997 | * snd_soc_register_dais - Register a DAI with the ASoC core |
3922 | * | 3998 | * |
3923 | * @component: The component the DAIs are registered for | 3999 | * @component: The component the DAIs are registered for |
3924 | * @codec: The CODEC that the DAIs are registered for, NULL if the component is | ||
3925 | * not a CODEC. | ||
3926 | * @dai_drv: DAI driver to use for the DAIs | 4000 | * @dai_drv: DAI driver to use for the DAIs |
3927 | * @count: Number of DAIs | 4001 | * @count: Number of DAIs |
3928 | * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the | 4002 | * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the |
3929 | * parent's name. | 4003 | * parent's name. |
3930 | */ | 4004 | */ |
3931 | static int snd_soc_register_dais(struct snd_soc_component *component, | 4005 | static int snd_soc_register_dais(struct snd_soc_component *component, |
3932 | struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, | 4006 | struct snd_soc_dai_driver *dai_drv, size_t count, |
3933 | size_t count, bool legacy_dai_naming) | 4007 | bool legacy_dai_naming) |
3934 | { | 4008 | { |
3935 | struct device *dev = component->dev; | 4009 | struct device *dev = component->dev; |
3936 | struct snd_soc_dai *dai; | 4010 | struct snd_soc_dai *dai; |
@@ -3939,6 +4013,9 @@ static int snd_soc_register_dais(struct snd_soc_component *component, | |||
3939 | 4013 | ||
3940 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); | 4014 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); |
3941 | 4015 | ||
4016 | component->dai_drv = dai_drv; | ||
4017 | component->num_dai = count; | ||
4018 | |||
3942 | for (i = 0; i < count; i++) { | 4019 | for (i = 0; i < count; i++) { |
3943 | 4020 | ||
3944 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | 4021 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); |
@@ -3971,16 +4048,11 @@ static int snd_soc_register_dais(struct snd_soc_component *component, | |||
3971 | } | 4048 | } |
3972 | 4049 | ||
3973 | dai->component = component; | 4050 | dai->component = component; |
3974 | dai->codec = codec; | ||
3975 | dai->dev = dev; | 4051 | dai->dev = dev; |
3976 | dai->driver = &dai_drv[i]; | 4052 | dai->driver = &dai_drv[i]; |
3977 | dai->dapm.dev = dev; | ||
3978 | if (!dai->driver->ops) | 4053 | if (!dai->driver->ops) |
3979 | dai->driver->ops = &null_dai_ops; | 4054 | dai->driver->ops = &null_dai_ops; |
3980 | 4055 | ||
3981 | if (!dai->codec) | ||
3982 | dai->dapm.idle_bias_off = 1; | ||
3983 | |||
3984 | list_add(&dai->list, &component->dai_list); | 4056 | list_add(&dai->list, &component->dai_list); |
3985 | 4057 | ||
3986 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); | 4058 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); |
@@ -3994,60 +4066,82 @@ err: | |||
3994 | return ret; | 4066 | return ret; |
3995 | } | 4067 | } |
3996 | 4068 | ||
3997 | /** | 4069 | static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, |
3998 | * snd_soc_register_component - Register a component with the ASoC core | 4070 | enum snd_soc_dapm_type type, int subseq) |
3999 | * | ||
4000 | */ | ||
4001 | static int | ||
4002 | __snd_soc_register_component(struct device *dev, | ||
4003 | struct snd_soc_component *cmpnt, | ||
4004 | const struct snd_soc_component_driver *cmpnt_drv, | ||
4005 | struct snd_soc_codec *codec, | ||
4006 | struct snd_soc_dai_driver *dai_drv, | ||
4007 | int num_dai, bool allow_single_dai) | ||
4008 | { | 4071 | { |
4009 | int ret; | 4072 | struct snd_soc_component *component = dapm->component; |
4010 | 4073 | ||
4011 | dev_dbg(dev, "component register %s\n", dev_name(dev)); | 4074 | component->driver->seq_notifier(component, type, subseq); |
4075 | } | ||
4012 | 4076 | ||
4013 | if (!cmpnt) { | 4077 | static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, |
4014 | dev_err(dev, "ASoC: Failed to connecting component\n"); | 4078 | int event) |
4015 | return -ENOMEM; | 4079 | { |
4016 | } | 4080 | struct snd_soc_component *component = dapm->component; |
4017 | 4081 | ||
4018 | mutex_init(&cmpnt->io_mutex); | 4082 | return component->driver->stream_event(component, event); |
4083 | } | ||
4084 | |||
4085 | static int snd_soc_component_initialize(struct snd_soc_component *component, | ||
4086 | const struct snd_soc_component_driver *driver, struct device *dev) | ||
4087 | { | ||
4088 | struct snd_soc_dapm_context *dapm; | ||
4019 | 4089 | ||
4020 | cmpnt->name = fmt_single_name(dev, &cmpnt->id); | 4090 | component->name = fmt_single_name(dev, &component->id); |
4021 | if (!cmpnt->name) { | 4091 | if (!component->name) { |
4022 | dev_err(dev, "ASoC: Failed to simplifying name\n"); | 4092 | dev_err(dev, "ASoC: Failed to allocate name\n"); |
4023 | return -ENOMEM; | 4093 | return -ENOMEM; |
4024 | } | 4094 | } |
4025 | 4095 | ||
4026 | cmpnt->dev = dev; | 4096 | component->dev = dev; |
4027 | cmpnt->driver = cmpnt_drv; | 4097 | component->driver = driver; |
4028 | cmpnt->dai_drv = dai_drv; | ||
4029 | cmpnt->num_dai = num_dai; | ||
4030 | INIT_LIST_HEAD(&cmpnt->dai_list); | ||
4031 | 4098 | ||
4032 | ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, | 4099 | if (!component->dapm_ptr) |
4033 | allow_single_dai); | 4100 | component->dapm_ptr = &component->dapm; |
4034 | if (ret < 0) { | 4101 | |
4035 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); | 4102 | dapm = component->dapm_ptr; |
4036 | goto error_component_name; | 4103 | dapm->dev = dev; |
4037 | } | 4104 | dapm->component = component; |
4105 | dapm->bias_level = SND_SOC_BIAS_OFF; | ||
4106 | if (driver->seq_notifier) | ||
4107 | dapm->seq_notifier = snd_soc_component_seq_notifier; | ||
4108 | if (driver->stream_event) | ||
4109 | dapm->stream_event = snd_soc_component_stream_event; | ||
4110 | |||
4111 | INIT_LIST_HEAD(&component->dai_list); | ||
4112 | mutex_init(&component->io_mutex); | ||
4113 | |||
4114 | return 0; | ||
4115 | } | ||
4038 | 4116 | ||
4117 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) | ||
4118 | { | ||
4119 | list_add(&component->list, &component_list); | ||
4120 | } | ||
4121 | |||
4122 | static void snd_soc_component_add(struct snd_soc_component *component) | ||
4123 | { | ||
4039 | mutex_lock(&client_mutex); | 4124 | mutex_lock(&client_mutex); |
4040 | list_add(&cmpnt->list, &component_list); | 4125 | snd_soc_component_add_unlocked(component); |
4041 | mutex_unlock(&client_mutex); | 4126 | mutex_unlock(&client_mutex); |
4127 | } | ||
4042 | 4128 | ||
4043 | dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); | 4129 | static void snd_soc_component_cleanup(struct snd_soc_component *component) |
4044 | 4130 | { | |
4045 | return ret; | 4131 | snd_soc_unregister_dais(component); |
4132 | kfree(component->name); | ||
4133 | } | ||
4046 | 4134 | ||
4047 | error_component_name: | 4135 | static void snd_soc_component_del_unlocked(struct snd_soc_component *component) |
4048 | kfree(cmpnt->name); | 4136 | { |
4137 | list_del(&component->list); | ||
4138 | } | ||
4049 | 4139 | ||
4050 | return ret; | 4140 | static void snd_soc_component_del(struct snd_soc_component *component) |
4141 | { | ||
4142 | mutex_lock(&client_mutex); | ||
4143 | snd_soc_component_del_unlocked(component); | ||
4144 | mutex_unlock(&client_mutex); | ||
4051 | } | 4145 | } |
4052 | 4146 | ||
4053 | int snd_soc_register_component(struct device *dev, | 4147 | int snd_soc_register_component(struct device *dev, |
@@ -4056,32 +4150,38 @@ int snd_soc_register_component(struct device *dev, | |||
4056 | int num_dai) | 4150 | int num_dai) |
4057 | { | 4151 | { |
4058 | struct snd_soc_component *cmpnt; | 4152 | struct snd_soc_component *cmpnt; |
4153 | int ret; | ||
4059 | 4154 | ||
4060 | cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); | 4155 | cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL); |
4061 | if (!cmpnt) { | 4156 | if (!cmpnt) { |
4062 | dev_err(dev, "ASoC: Failed to allocate memory\n"); | 4157 | dev_err(dev, "ASoC: Failed to allocate memory\n"); |
4063 | return -ENOMEM; | 4158 | return -ENOMEM; |
4064 | } | 4159 | } |
4065 | 4160 | ||
4161 | ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev); | ||
4162 | if (ret) | ||
4163 | goto err_free; | ||
4164 | |||
4066 | cmpnt->ignore_pmdown_time = true; | 4165 | cmpnt->ignore_pmdown_time = true; |
4067 | cmpnt->registered_as_component = true; | 4166 | cmpnt->registered_as_component = true; |
4068 | 4167 | ||
4069 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, | 4168 | ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true); |
4070 | dai_drv, num_dai, true); | 4169 | if (ret < 0) { |
4071 | } | 4170 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); |
4072 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | 4171 | goto err_cleanup; |
4172 | } | ||
4073 | 4173 | ||
4074 | static void __snd_soc_unregister_component(struct snd_soc_component *cmpnt) | 4174 | snd_soc_component_add(cmpnt); |
4075 | { | ||
4076 | snd_soc_unregister_dais(cmpnt); | ||
4077 | 4175 | ||
4078 | mutex_lock(&client_mutex); | 4176 | return 0; |
4079 | list_del(&cmpnt->list); | ||
4080 | mutex_unlock(&client_mutex); | ||
4081 | 4177 | ||
4082 | dev_dbg(cmpnt->dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); | 4178 | err_cleanup: |
4083 | kfree(cmpnt->name); | 4179 | snd_soc_component_cleanup(cmpnt); |
4180 | err_free: | ||
4181 | kfree(cmpnt); | ||
4182 | return ret; | ||
4084 | } | 4183 | } |
4184 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | ||
4085 | 4185 | ||
4086 | /** | 4186 | /** |
4087 | * snd_soc_unregister_component - Unregister a component from the ASoC core | 4187 | * snd_soc_unregister_component - Unregister a component from the ASoC core |
@@ -4098,7 +4198,9 @@ void snd_soc_unregister_component(struct device *dev) | |||
4098 | return; | 4198 | return; |
4099 | 4199 | ||
4100 | found: | 4200 | found: |
4101 | __snd_soc_unregister_component(cmpnt); | 4201 | snd_soc_component_del(cmpnt); |
4202 | snd_soc_component_cleanup(cmpnt); | ||
4203 | kfree(cmpnt); | ||
4102 | } | 4204 | } |
4103 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); | 4205 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); |
4104 | 4206 | ||
@@ -4131,37 +4233,25 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, | |||
4131 | { | 4233 | { |
4132 | int ret; | 4234 | int ret; |
4133 | 4235 | ||
4134 | /* create platform component name */ | 4236 | ret = snd_soc_component_initialize(&platform->component, |
4135 | platform->name = fmt_single_name(dev, &platform->id); | 4237 | &platform_drv->component_driver, dev); |
4136 | if (platform->name == NULL) | 4238 | if (ret) |
4137 | return -ENOMEM; | 4239 | return ret; |
4138 | 4240 | ||
4139 | platform->dev = dev; | 4241 | platform->dev = dev; |
4140 | platform->driver = platform_drv; | 4242 | platform->driver = platform_drv; |
4141 | platform->dapm.dev = dev; | ||
4142 | platform->dapm.platform = platform; | ||
4143 | platform->dapm.component = &platform->component; | ||
4144 | platform->dapm.stream_event = platform_drv->stream_event; | ||
4145 | if (platform_drv->write) | 4243 | if (platform_drv->write) |
4146 | platform->component.write = snd_soc_platform_drv_write; | 4244 | platform->component.write = snd_soc_platform_drv_write; |
4147 | if (platform_drv->read) | 4245 | if (platform_drv->read) |
4148 | platform->component.read = snd_soc_platform_drv_read; | 4246 | platform->component.read = snd_soc_platform_drv_read; |
4149 | 4247 | ||
4150 | /* register component */ | ||
4151 | ret = __snd_soc_register_component(dev, &platform->component, | ||
4152 | &platform_drv->component_driver, | ||
4153 | NULL, NULL, 0, false); | ||
4154 | if (ret < 0) { | ||
4155 | dev_err(platform->component.dev, | ||
4156 | "ASoC: Failed to register component: %d\n", ret); | ||
4157 | return ret; | ||
4158 | } | ||
4159 | |||
4160 | mutex_lock(&client_mutex); | 4248 | mutex_lock(&client_mutex); |
4249 | snd_soc_component_add_unlocked(&platform->component); | ||
4161 | list_add(&platform->list, &platform_list); | 4250 | list_add(&platform->list, &platform_list); |
4162 | mutex_unlock(&client_mutex); | 4251 | mutex_unlock(&client_mutex); |
4163 | 4252 | ||
4164 | dev_dbg(dev, "ASoC: Registered platform '%s'\n", platform->name); | 4253 | dev_dbg(dev, "ASoC: Registered platform '%s'\n", |
4254 | platform->component.name); | ||
4165 | 4255 | ||
4166 | return 0; | 4256 | return 0; |
4167 | } | 4257 | } |
@@ -4198,15 +4288,16 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform); | |||
4198 | */ | 4288 | */ |
4199 | void snd_soc_remove_platform(struct snd_soc_platform *platform) | 4289 | void snd_soc_remove_platform(struct snd_soc_platform *platform) |
4200 | { | 4290 | { |
4201 | __snd_soc_unregister_component(&platform->component); | ||
4202 | 4291 | ||
4203 | mutex_lock(&client_mutex); | 4292 | mutex_lock(&client_mutex); |
4204 | list_del(&platform->list); | 4293 | list_del(&platform->list); |
4294 | snd_soc_component_del_unlocked(&platform->component); | ||
4205 | mutex_unlock(&client_mutex); | 4295 | mutex_unlock(&client_mutex); |
4206 | 4296 | ||
4297 | snd_soc_component_cleanup(&platform->component); | ||
4298 | |||
4207 | dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n", | 4299 | dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n", |
4208 | platform->name); | 4300 | platform->component.name); |
4209 | kfree(platform->name); | ||
4210 | } | 4301 | } |
4211 | EXPORT_SYMBOL_GPL(snd_soc_remove_platform); | 4302 | EXPORT_SYMBOL_GPL(snd_soc_remove_platform); |
4212 | 4303 | ||
@@ -4292,6 +4383,14 @@ static int snd_soc_codec_drv_read(struct snd_soc_component *component, | |||
4292 | return 0; | 4383 | return 0; |
4293 | } | 4384 | } |
4294 | 4385 | ||
4386 | static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm, | ||
4387 | enum snd_soc_bias_level level) | ||
4388 | { | ||
4389 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | ||
4390 | |||
4391 | return codec->driver->set_bias_level(codec, level); | ||
4392 | } | ||
4393 | |||
4295 | /** | 4394 | /** |
4296 | * snd_soc_register_codec - Register a codec with the ASoC core | 4395 | * snd_soc_register_codec - Register a codec with the ASoC core |
4297 | * | 4396 | * |
@@ -4303,6 +4402,7 @@ int snd_soc_register_codec(struct device *dev, | |||
4303 | int num_dai) | 4402 | int num_dai) |
4304 | { | 4403 | { |
4305 | struct snd_soc_codec *codec; | 4404 | struct snd_soc_codec *codec; |
4405 | struct snd_soc_dai *dai; | ||
4306 | struct regmap *regmap; | 4406 | struct regmap *regmap; |
4307 | int ret, i; | 4407 | int ret, i; |
4308 | 4408 | ||
@@ -4312,24 +4412,23 @@ int snd_soc_register_codec(struct device *dev, | |||
4312 | if (codec == NULL) | 4412 | if (codec == NULL) |
4313 | return -ENOMEM; | 4413 | return -ENOMEM; |
4314 | 4414 | ||
4315 | /* create CODEC component name */ | 4415 | codec->component.dapm_ptr = &codec->dapm; |
4316 | codec->name = fmt_single_name(dev, &codec->id); | 4416 | |
4317 | if (codec->name == NULL) { | 4417 | ret = snd_soc_component_initialize(&codec->component, |
4318 | ret = -ENOMEM; | 4418 | &codec_drv->component_driver, dev); |
4319 | goto fail_codec; | 4419 | if (ret) |
4320 | } | 4420 | goto err_free; |
4321 | 4421 | ||
4322 | if (codec_drv->write) | 4422 | if (codec_drv->write) |
4323 | codec->component.write = snd_soc_codec_drv_write; | 4423 | codec->component.write = snd_soc_codec_drv_write; |
4324 | if (codec_drv->read) | 4424 | if (codec_drv->read) |
4325 | codec->component.read = snd_soc_codec_drv_read; | 4425 | codec->component.read = snd_soc_codec_drv_read; |
4326 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; | 4426 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; |
4327 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | ||
4328 | codec->dapm.dev = dev; | ||
4329 | codec->dapm.codec = codec; | 4427 | codec->dapm.codec = codec; |
4330 | codec->dapm.component = &codec->component; | 4428 | if (codec_drv->seq_notifier) |
4331 | codec->dapm.seq_notifier = codec_drv->seq_notifier; | 4429 | codec->dapm.seq_notifier = codec_drv->seq_notifier; |
4332 | codec->dapm.stream_event = codec_drv->stream_event; | 4430 | if (codec_drv->set_bias_level) |
4431 | codec->dapm.set_bias_level = snd_soc_codec_set_bias_level; | ||
4333 | codec->dev = dev; | 4432 | codec->dev = dev; |
4334 | codec->driver = codec_drv; | 4433 | codec->driver = codec_drv; |
4335 | codec->component.val_bytes = codec_drv->reg_word_size; | 4434 | codec->component.val_bytes = codec_drv->reg_word_size; |
@@ -4348,7 +4447,7 @@ int snd_soc_register_codec(struct device *dev, | |||
4348 | dev_err(codec->dev, | 4447 | dev_err(codec->dev, |
4349 | "Failed to set cache I/O:%d\n", | 4448 | "Failed to set cache I/O:%d\n", |
4350 | ret); | 4449 | ret); |
4351 | return ret; | 4450 | goto err_cleanup; |
4352 | } | 4451 | } |
4353 | } | 4452 | } |
4354 | } | 4453 | } |
@@ -4358,29 +4457,27 @@ int snd_soc_register_codec(struct device *dev, | |||
4358 | fixup_codec_formats(&dai_drv[i].capture); | 4457 | fixup_codec_formats(&dai_drv[i].capture); |
4359 | } | 4458 | } |
4360 | 4459 | ||
4361 | mutex_lock(&client_mutex); | 4460 | ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false); |
4362 | list_add(&codec->list, &codec_list); | ||
4363 | mutex_unlock(&client_mutex); | ||
4364 | |||
4365 | /* register component */ | ||
4366 | ret = __snd_soc_register_component(dev, &codec->component, | ||
4367 | &codec_drv->component_driver, | ||
4368 | codec, dai_drv, num_dai, false); | ||
4369 | if (ret < 0) { | 4461 | if (ret < 0) { |
4370 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); | 4462 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); |
4371 | goto fail_codec_name; | 4463 | goto err_cleanup; |
4372 | } | 4464 | } |
4373 | 4465 | ||
4374 | dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); | 4466 | list_for_each_entry(dai, &codec->component.dai_list, list) |
4375 | return 0; | 4467 | dai->codec = codec; |
4376 | 4468 | ||
4377 | fail_codec_name: | ||
4378 | mutex_lock(&client_mutex); | 4469 | mutex_lock(&client_mutex); |
4379 | list_del(&codec->list); | 4470 | snd_soc_component_add_unlocked(&codec->component); |
4471 | list_add(&codec->list, &codec_list); | ||
4380 | mutex_unlock(&client_mutex); | 4472 | mutex_unlock(&client_mutex); |
4381 | 4473 | ||
4382 | kfree(codec->name); | 4474 | dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", |
4383 | fail_codec: | 4475 | codec->component.name); |
4476 | return 0; | ||
4477 | |||
4478 | err_cleanup: | ||
4479 | snd_soc_component_cleanup(&codec->component); | ||
4480 | err_free: | ||
4384 | kfree(codec); | 4481 | kfree(codec); |
4385 | return ret; | 4482 | return ret; |
4386 | } | 4483 | } |
@@ -4402,16 +4499,17 @@ void snd_soc_unregister_codec(struct device *dev) | |||
4402 | return; | 4499 | return; |
4403 | 4500 | ||
4404 | found: | 4501 | found: |
4405 | __snd_soc_unregister_component(&codec->component); | ||
4406 | 4502 | ||
4407 | mutex_lock(&client_mutex); | 4503 | mutex_lock(&client_mutex); |
4408 | list_del(&codec->list); | 4504 | list_del(&codec->list); |
4505 | snd_soc_component_del_unlocked(&codec->component); | ||
4409 | mutex_unlock(&client_mutex); | 4506 | mutex_unlock(&client_mutex); |
4410 | 4507 | ||
4411 | dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name); | 4508 | dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", |
4509 | codec->component.name); | ||
4412 | 4510 | ||
4511 | snd_soc_component_cleanup(&codec->component); | ||
4413 | snd_soc_cache_exit(codec); | 4512 | snd_soc_cache_exit(codec); |
4414 | kfree(codec->name); | ||
4415 | kfree(codec); | 4513 | kfree(codec); |
4416 | } | 4514 | } |
4417 | EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); | 4515 | EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); |
@@ -4420,9 +4518,16 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); | |||
4420 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, | 4518 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, |
4421 | const char *propname) | 4519 | const char *propname) |
4422 | { | 4520 | { |
4423 | struct device_node *np = card->dev->of_node; | 4521 | struct device_node *np; |
4424 | int ret; | 4522 | int ret; |
4425 | 4523 | ||
4524 | if (!card->dev) { | ||
4525 | pr_err("card->dev is not set before calling %s\n", __func__); | ||
4526 | return -EINVAL; | ||
4527 | } | ||
4528 | |||
4529 | np = card->dev->of_node; | ||
4530 | |||
4426 | ret = of_property_read_string_index(np, propname, 0, &card->name); | 4531 | ret = of_property_read_string_index(np, propname, 0, &card->name); |
4427 | /* | 4532 | /* |
4428 | * EINVAL means the property does not exist. This is fine providing | 4533 | * EINVAL means the property does not exist. This is fine providing |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a74b9bf23d9f..8348352dc2c6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -350,12 +350,27 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, | |||
350 | } | 350 | } |
351 | 351 | ||
352 | /** | 352 | /** |
353 | * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a | ||
354 | * kcontrol | ||
355 | * @kcontrol: The kcontrol | ||
356 | * | ||
357 | * Note: This function must only be used on kcontrols that are known to have | ||
358 | * been registered for a CODEC. Otherwise the behaviour is undefined. | ||
359 | */ | ||
360 | struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( | ||
361 | struct snd_kcontrol *kcontrol) | ||
362 | { | ||
363 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm; | ||
364 | } | ||
365 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm); | ||
366 | |||
367 | /** | ||
353 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol | 368 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol |
354 | * @kcontrol: The kcontrol | 369 | * @kcontrol: The kcontrol |
355 | */ | 370 | */ |
356 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) | 371 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) |
357 | { | 372 | { |
358 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec; | 373 | return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol)); |
359 | } | 374 | } |
360 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); | 375 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); |
361 | 376 | ||
@@ -375,23 +390,38 @@ static void dapm_reset(struct snd_soc_card *card) | |||
375 | } | 390 | } |
376 | } | 391 | } |
377 | 392 | ||
378 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, | 393 | static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm) |
394 | { | ||
395 | if (!dapm->component) | ||
396 | return NULL; | ||
397 | return dapm->component->name_prefix; | ||
398 | } | ||
399 | |||
400 | static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg, | ||
379 | unsigned int *value) | 401 | unsigned int *value) |
380 | { | 402 | { |
381 | if (!w->dapm->component) | 403 | if (!dapm->component) |
382 | return -EIO; | 404 | return -EIO; |
383 | return snd_soc_component_read(w->dapm->component, reg, value); | 405 | return snd_soc_component_read(dapm->component, reg, value); |
384 | } | 406 | } |
385 | 407 | ||
386 | static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, | 408 | static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm, |
387 | int reg, unsigned int mask, unsigned int value) | 409 | int reg, unsigned int mask, unsigned int value) |
388 | { | 410 | { |
389 | if (!w->dapm->component) | 411 | if (!dapm->component) |
390 | return -EIO; | 412 | return -EIO; |
391 | return snd_soc_component_update_bits_async(w->dapm->component, reg, | 413 | return snd_soc_component_update_bits_async(dapm->component, reg, |
392 | mask, value); | 414 | mask, value); |
393 | } | 415 | } |
394 | 416 | ||
417 | static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm, | ||
418 | int reg, unsigned int mask, unsigned int value) | ||
419 | { | ||
420 | if (!dapm->component) | ||
421 | return -EIO; | ||
422 | return snd_soc_component_test_bits(dapm->component, reg, mask, value); | ||
423 | } | ||
424 | |||
395 | static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) | 425 | static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) |
396 | { | 426 | { |
397 | if (dapm->component) | 427 | if (dapm->component) |
@@ -420,15 +450,10 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, | |||
420 | if (ret != 0) | 450 | if (ret != 0) |
421 | goto out; | 451 | goto out; |
422 | 452 | ||
423 | if (dapm->codec) { | 453 | if (dapm->set_bias_level) |
424 | if (dapm->codec->driver->set_bias_level) | 454 | ret = dapm->set_bias_level(dapm, level); |
425 | ret = dapm->codec->driver->set_bias_level(dapm->codec, | 455 | else if (!card || dapm != &card->dapm) |
426 | level); | ||
427 | else | ||
428 | dapm->bias_level = level; | ||
429 | } else if (!card || dapm != &card->dapm) { | ||
430 | dapm->bias_level = level; | 456 | dapm->bias_level = level; |
431 | } | ||
432 | 457 | ||
433 | if (ret != 0) | 458 | if (ret != 0) |
434 | goto out; | 459 | goto out; |
@@ -452,7 +477,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
452 | int i; | 477 | int i; |
453 | 478 | ||
454 | if (e->reg != SND_SOC_NOPM) { | 479 | if (e->reg != SND_SOC_NOPM) { |
455 | soc_widget_read(dest, e->reg, &val); | 480 | soc_dapm_read(dapm, e->reg, &val); |
456 | val = (val >> e->shift_l) & e->mask; | 481 | val = (val >> e->shift_l) & e->mask; |
457 | item = snd_soc_enum_val_to_item(e, val); | 482 | item = snd_soc_enum_val_to_item(e, val); |
458 | } else { | 483 | } else { |
@@ -496,7 +521,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
496 | unsigned int val; | 521 | unsigned int val; |
497 | 522 | ||
498 | if (reg != SND_SOC_NOPM) { | 523 | if (reg != SND_SOC_NOPM) { |
499 | soc_widget_read(w, reg, &val); | 524 | soc_dapm_read(w->dapm, reg, &val); |
500 | val = (val >> shift) & mask; | 525 | val = (val >> shift) & mask; |
501 | if (invert) | 526 | if (invert) |
502 | val = max - val; | 527 | val = max - val; |
@@ -570,11 +595,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
570 | const char *name; | 595 | const char *name; |
571 | int ret; | 596 | int ret; |
572 | 597 | ||
573 | if (dapm->codec) | 598 | prefix = soc_dapm_prefix(dapm); |
574 | prefix = dapm->codec->name_prefix; | ||
575 | else | ||
576 | prefix = NULL; | ||
577 | |||
578 | if (prefix) | 599 | if (prefix) |
579 | prefix_len = strlen(prefix) + 1; | 600 | prefix_len = strlen(prefix) + 1; |
580 | else | 601 | else |
@@ -1308,16 +1329,18 @@ static void dapm_seq_check_event(struct snd_soc_card *card, | |||
1308 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, | 1329 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, |
1309 | struct list_head *pending) | 1330 | struct list_head *pending) |
1310 | { | 1331 | { |
1332 | struct snd_soc_dapm_context *dapm; | ||
1311 | struct snd_soc_dapm_widget *w; | 1333 | struct snd_soc_dapm_widget *w; |
1312 | int reg; | 1334 | int reg; |
1313 | unsigned int value = 0; | 1335 | unsigned int value = 0; |
1314 | unsigned int mask = 0; | 1336 | unsigned int mask = 0; |
1315 | 1337 | ||
1316 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, | 1338 | w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list); |
1317 | power_list)->reg; | 1339 | reg = w->reg; |
1340 | dapm = w->dapm; | ||
1318 | 1341 | ||
1319 | list_for_each_entry(w, pending, power_list) { | 1342 | list_for_each_entry(w, pending, power_list) { |
1320 | WARN_ON(reg != w->reg); | 1343 | WARN_ON(reg != w->reg || dapm != w->dapm); |
1321 | w->power = w->new_power; | 1344 | w->power = w->new_power; |
1322 | 1345 | ||
1323 | mask |= w->mask << w->shift; | 1346 | mask |= w->mask << w->shift; |
@@ -1326,7 +1349,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, | |||
1326 | else | 1349 | else |
1327 | value |= w->off_val << w->shift; | 1350 | value |= w->off_val << w->shift; |
1328 | 1351 | ||
1329 | pop_dbg(w->dapm->dev, card->pop_time, | 1352 | pop_dbg(dapm->dev, card->pop_time, |
1330 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", | 1353 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", |
1331 | w->name, reg, value, mask); | 1354 | w->name, reg, value, mask); |
1332 | 1355 | ||
@@ -1339,14 +1362,12 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, | |||
1339 | /* Any widget will do, they should all be updating the | 1362 | /* Any widget will do, they should all be updating the |
1340 | * same register. | 1363 | * same register. |
1341 | */ | 1364 | */ |
1342 | w = list_first_entry(pending, struct snd_soc_dapm_widget, | ||
1343 | power_list); | ||
1344 | 1365 | ||
1345 | pop_dbg(w->dapm->dev, card->pop_time, | 1366 | pop_dbg(dapm->dev, card->pop_time, |
1346 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 1367 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
1347 | value, mask, reg, card->pop_time); | 1368 | value, mask, reg, card->pop_time); |
1348 | pop_wait(card->pop_time); | 1369 | pop_wait(card->pop_time); |
1349 | soc_widget_update_bits(w, reg, mask, value); | 1370 | soc_dapm_update_bits(dapm, reg, mask, value); |
1350 | } | 1371 | } |
1351 | 1372 | ||
1352 | list_for_each_entry(w, pending, power_list) { | 1373 | list_for_each_entry(w, pending, power_list) { |
@@ -1492,7 +1513,8 @@ static void dapm_widget_update(struct snd_soc_card *card) | |||
1492 | if (!w) | 1513 | if (!w) |
1493 | return; | 1514 | return; |
1494 | 1515 | ||
1495 | ret = soc_widget_update_bits(w, update->reg, update->mask, update->val); | 1516 | ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask, |
1517 | update->val); | ||
1496 | if (ret < 0) | 1518 | if (ret < 0) |
1497 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", | 1519 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", |
1498 | w->name, ret); | 1520 | w->name, ret); |
@@ -2062,17 +2084,13 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, | |||
2062 | } | 2084 | } |
2063 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | 2085 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
2064 | 2086 | ||
2065 | /* show dapm widget status in sys fs */ | 2087 | static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf) |
2066 | static ssize_t dapm_widget_show(struct device *dev, | ||
2067 | struct device_attribute *attr, char *buf) | ||
2068 | { | 2088 | { |
2069 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); | ||
2070 | struct snd_soc_codec *codec =rtd->codec; | ||
2071 | struct snd_soc_dapm_widget *w; | 2089 | struct snd_soc_dapm_widget *w; |
2072 | int count = 0; | 2090 | int count = 0; |
2073 | char *state = "not set"; | 2091 | char *state = "not set"; |
2074 | 2092 | ||
2075 | list_for_each_entry(w, &codec->card->widgets, list) { | 2093 | list_for_each_entry(w, &codec->component.card->widgets, list) { |
2076 | if (w->dapm != &codec->dapm) | 2094 | if (w->dapm != &codec->dapm) |
2077 | continue; | 2095 | continue; |
2078 | 2096 | ||
@@ -2120,6 +2138,21 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
2120 | return count; | 2138 | return count; |
2121 | } | 2139 | } |
2122 | 2140 | ||
2141 | /* show dapm widget status in sys fs */ | ||
2142 | static ssize_t dapm_widget_show(struct device *dev, | ||
2143 | struct device_attribute *attr, char *buf) | ||
2144 | { | ||
2145 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); | ||
2146 | int i, count = 0; | ||
2147 | |||
2148 | for (i = 0; i < rtd->num_codecs; i++) { | ||
2149 | struct snd_soc_codec *codec = rtd->codec_dais[i]->codec; | ||
2150 | count += dapm_widget_show_codec(codec, buf + count); | ||
2151 | } | ||
2152 | |||
2153 | return count; | ||
2154 | } | ||
2155 | |||
2123 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); | 2156 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); |
2124 | 2157 | ||
2125 | int snd_soc_dapm_sys_add(struct device *dev) | 2158 | int snd_soc_dapm_sys_add(struct device *dev) |
@@ -2371,14 +2404,16 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2371 | const char *source; | 2404 | const char *source; |
2372 | char prefixed_sink[80]; | 2405 | char prefixed_sink[80]; |
2373 | char prefixed_source[80]; | 2406 | char prefixed_source[80]; |
2407 | const char *prefix; | ||
2374 | int ret; | 2408 | int ret; |
2375 | 2409 | ||
2376 | if (dapm->codec && dapm->codec->name_prefix) { | 2410 | prefix = soc_dapm_prefix(dapm); |
2411 | if (prefix) { | ||
2377 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 2412 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
2378 | dapm->codec->name_prefix, route->sink); | 2413 | prefix, route->sink); |
2379 | sink = prefixed_sink; | 2414 | sink = prefixed_sink; |
2380 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | 2415 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", |
2381 | dapm->codec->name_prefix, route->source); | 2416 | prefix, route->source); |
2382 | source = prefixed_source; | 2417 | source = prefixed_source; |
2383 | } else { | 2418 | } else { |
2384 | sink = route->sink; | 2419 | sink = route->sink; |
@@ -2439,6 +2474,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2439 | const char *source; | 2474 | const char *source; |
2440 | char prefixed_sink[80]; | 2475 | char prefixed_sink[80]; |
2441 | char prefixed_source[80]; | 2476 | char prefixed_source[80]; |
2477 | const char *prefix; | ||
2442 | 2478 | ||
2443 | if (route->control) { | 2479 | if (route->control) { |
2444 | dev_err(dapm->dev, | 2480 | dev_err(dapm->dev, |
@@ -2446,12 +2482,13 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2446 | return -EINVAL; | 2482 | return -EINVAL; |
2447 | } | 2483 | } |
2448 | 2484 | ||
2449 | if (dapm->codec && dapm->codec->name_prefix) { | 2485 | prefix = soc_dapm_prefix(dapm); |
2486 | if (prefix) { | ||
2450 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 2487 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
2451 | dapm->codec->name_prefix, route->sink); | 2488 | prefix, route->sink); |
2452 | sink = prefixed_sink; | 2489 | sink = prefixed_sink; |
2453 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | 2490 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", |
2454 | dapm->codec->name_prefix, route->source); | 2491 | prefix, route->source); |
2455 | source = prefixed_source; | 2492 | source = prefixed_source; |
2456 | } else { | 2493 | } else { |
2457 | sink = route->sink; | 2494 | sink = route->sink; |
@@ -2670,7 +2707,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
2670 | 2707 | ||
2671 | /* Read the initial power state from the device */ | 2708 | /* Read the initial power state from the device */ |
2672 | if (w->reg >= 0) { | 2709 | if (w->reg >= 0) { |
2673 | soc_widget_read(w, w->reg, &val); | 2710 | soc_dapm_read(w->dapm, w->reg, &val); |
2674 | val = val >> w->shift; | 2711 | val = val >> w->shift; |
2675 | val &= w->mask; | 2712 | val &= w->mask; |
2676 | if (val == w->on_val) | 2713 | if (val == w->on_val) |
@@ -2701,8 +2738,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
2701 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 2738 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
2702 | struct snd_ctl_elem_value *ucontrol) | 2739 | struct snd_ctl_elem_value *ucontrol) |
2703 | { | 2740 | { |
2704 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2741 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2705 | struct snd_soc_card *card = codec->card; | 2742 | struct snd_soc_card *card = dapm->card; |
2706 | struct soc_mixer_control *mc = | 2743 | struct soc_mixer_control *mc = |
2707 | (struct soc_mixer_control *)kcontrol->private_value; | 2744 | (struct soc_mixer_control *)kcontrol->private_value; |
2708 | int reg = mc->reg; | 2745 | int reg = mc->reg; |
@@ -2711,17 +2748,20 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2711 | unsigned int mask = (1 << fls(max)) - 1; | 2748 | unsigned int mask = (1 << fls(max)) - 1; |
2712 | unsigned int invert = mc->invert; | 2749 | unsigned int invert = mc->invert; |
2713 | unsigned int val; | 2750 | unsigned int val; |
2751 | int ret = 0; | ||
2714 | 2752 | ||
2715 | if (snd_soc_volsw_is_stereo(mc)) | 2753 | if (snd_soc_volsw_is_stereo(mc)) |
2716 | dev_warn(codec->dapm.dev, | 2754 | dev_warn(dapm->dev, |
2717 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2755 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2718 | kcontrol->id.name); | 2756 | kcontrol->id.name); |
2719 | 2757 | ||
2720 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2758 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2721 | if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) | 2759 | if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { |
2722 | val = (snd_soc_read(codec, reg) >> shift) & mask; | 2760 | ret = soc_dapm_read(dapm, reg, &val); |
2723 | else | 2761 | val = (val >> shift) & mask; |
2762 | } else { | ||
2724 | val = dapm_kcontrol_get_value(kcontrol); | 2763 | val = dapm_kcontrol_get_value(kcontrol); |
2764 | } | ||
2725 | mutex_unlock(&card->dapm_mutex); | 2765 | mutex_unlock(&card->dapm_mutex); |
2726 | 2766 | ||
2727 | if (invert) | 2767 | if (invert) |
@@ -2729,7 +2769,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2729 | else | 2769 | else |
2730 | ucontrol->value.integer.value[0] = val; | 2770 | ucontrol->value.integer.value[0] = val; |
2731 | 2771 | ||
2732 | return 0; | 2772 | return ret; |
2733 | } | 2773 | } |
2734 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | 2774 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); |
2735 | 2775 | ||
@@ -2745,8 +2785,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
2745 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 2785 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
2746 | struct snd_ctl_elem_value *ucontrol) | 2786 | struct snd_ctl_elem_value *ucontrol) |
2747 | { | 2787 | { |
2748 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2788 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2749 | struct snd_soc_card *card = codec->card; | 2789 | struct snd_soc_card *card = dapm->card; |
2750 | struct soc_mixer_control *mc = | 2790 | struct soc_mixer_control *mc = |
2751 | (struct soc_mixer_control *)kcontrol->private_value; | 2791 | (struct soc_mixer_control *)kcontrol->private_value; |
2752 | int reg = mc->reg; | 2792 | int reg = mc->reg; |
@@ -2755,12 +2795,12 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2755 | unsigned int mask = (1 << fls(max)) - 1; | 2795 | unsigned int mask = (1 << fls(max)) - 1; |
2756 | unsigned int invert = mc->invert; | 2796 | unsigned int invert = mc->invert; |
2757 | unsigned int val; | 2797 | unsigned int val; |
2758 | int connect, change; | 2798 | int connect, change, reg_change = 0; |
2759 | struct snd_soc_dapm_update update; | 2799 | struct snd_soc_dapm_update update; |
2760 | int ret = 0; | 2800 | int ret = 0; |
2761 | 2801 | ||
2762 | if (snd_soc_volsw_is_stereo(mc)) | 2802 | if (snd_soc_volsw_is_stereo(mc)) |
2763 | dev_warn(codec->dapm.dev, | 2803 | dev_warn(dapm->dev, |
2764 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2804 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2765 | kcontrol->id.name); | 2805 | kcontrol->id.name); |
2766 | 2806 | ||
@@ -2773,20 +2813,23 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2773 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2813 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2774 | 2814 | ||
2775 | change = dapm_kcontrol_set_value(kcontrol, val); | 2815 | change = dapm_kcontrol_set_value(kcontrol, val); |
2776 | if (change) { | ||
2777 | if (reg != SND_SOC_NOPM) { | ||
2778 | mask = mask << shift; | ||
2779 | val = val << shift; | ||
2780 | |||
2781 | if (snd_soc_test_bits(codec, reg, mask, val)) { | ||
2782 | update.kcontrol = kcontrol; | ||
2783 | update.reg = reg; | ||
2784 | update.mask = mask; | ||
2785 | update.val = val; | ||
2786 | card->update = &update; | ||
2787 | } | ||
2788 | 2816 | ||
2817 | if (reg != SND_SOC_NOPM) { | ||
2818 | mask = mask << shift; | ||
2819 | val = val << shift; | ||
2820 | |||
2821 | reg_change = soc_dapm_test_bits(dapm, reg, mask, val); | ||
2822 | } | ||
2823 | |||
2824 | if (change || reg_change) { | ||
2825 | if (reg_change) { | ||
2826 | update.kcontrol = kcontrol; | ||
2827 | update.reg = reg; | ||
2828 | update.mask = mask; | ||
2829 | update.val = val; | ||
2830 | card->update = &update; | ||
2789 | } | 2831 | } |
2832 | change |= reg_change; | ||
2790 | 2833 | ||
2791 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); | 2834 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); |
2792 | 2835 | ||
@@ -2814,12 +2857,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
2814 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2857 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
2815 | struct snd_ctl_elem_value *ucontrol) | 2858 | struct snd_ctl_elem_value *ucontrol) |
2816 | { | 2859 | { |
2817 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2860 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2818 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2861 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2819 | unsigned int reg_val, val; | 2862 | unsigned int reg_val, val; |
2863 | int ret = 0; | ||
2820 | 2864 | ||
2821 | if (e->reg != SND_SOC_NOPM) | 2865 | if (e->reg != SND_SOC_NOPM) |
2822 | reg_val = snd_soc_read(codec, e->reg); | 2866 | ret = soc_dapm_read(dapm, e->reg, ®_val); |
2823 | else | 2867 | else |
2824 | reg_val = dapm_kcontrol_get_value(kcontrol); | 2868 | reg_val = dapm_kcontrol_get_value(kcontrol); |
2825 | 2869 | ||
@@ -2831,7 +2875,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2831 | ucontrol->value.enumerated.item[1] = val; | 2875 | ucontrol->value.enumerated.item[1] = val; |
2832 | } | 2876 | } |
2833 | 2877 | ||
2834 | return 0; | 2878 | return ret; |
2835 | } | 2879 | } |
2836 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | 2880 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); |
2837 | 2881 | ||
@@ -2847,8 +2891,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
2847 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2891 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
2848 | struct snd_ctl_elem_value *ucontrol) | 2892 | struct snd_ctl_elem_value *ucontrol) |
2849 | { | 2893 | { |
2850 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2894 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2851 | struct snd_soc_card *card = codec->card; | 2895 | struct snd_soc_card *card = dapm->card; |
2852 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2896 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2853 | unsigned int *item = ucontrol->value.enumerated.item; | 2897 | unsigned int *item = ucontrol->value.enumerated.item; |
2854 | unsigned int val, change; | 2898 | unsigned int val, change; |
@@ -2871,7 +2915,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2871 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2915 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2872 | 2916 | ||
2873 | if (e->reg != SND_SOC_NOPM) | 2917 | if (e->reg != SND_SOC_NOPM) |
2874 | change = snd_soc_test_bits(codec, e->reg, mask, val); | 2918 | change = soc_dapm_test_bits(dapm, e->reg, mask, val); |
2875 | else | 2919 | else |
2876 | change = dapm_kcontrol_set_value(kcontrol, val); | 2920 | change = dapm_kcontrol_set_value(kcontrol, val); |
2877 | 2921 | ||
@@ -2968,6 +3012,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2968 | const struct snd_soc_dapm_widget *widget) | 3012 | const struct snd_soc_dapm_widget *widget) |
2969 | { | 3013 | { |
2970 | struct snd_soc_dapm_widget *w; | 3014 | struct snd_soc_dapm_widget *w; |
3015 | const char *prefix; | ||
2971 | int ret; | 3016 | int ret; |
2972 | 3017 | ||
2973 | if ((w = dapm_cnew_widget(widget)) == NULL) | 3018 | if ((w = dapm_cnew_widget(widget)) == NULL) |
@@ -3008,9 +3053,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3008 | break; | 3053 | break; |
3009 | } | 3054 | } |
3010 | 3055 | ||
3011 | if (dapm->codec && dapm->codec->name_prefix) | 3056 | prefix = soc_dapm_prefix(dapm); |
3012 | w->name = kasprintf(GFP_KERNEL, "%s %s", | 3057 | if (prefix) |
3013 | dapm->codec->name_prefix, widget->name); | 3058 | w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); |
3014 | else | 3059 | else |
3015 | w->name = kasprintf(GFP_KERNEL, "%s", widget->name); | 3060 | w->name = kasprintf(GFP_KERNEL, "%s", widget->name); |
3016 | 3061 | ||
@@ -3063,7 +3108,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3063 | 3108 | ||
3064 | w->dapm = dapm; | 3109 | w->dapm = dapm; |
3065 | w->codec = dapm->codec; | 3110 | w->codec = dapm->codec; |
3066 | w->platform = dapm->platform; | ||
3067 | INIT_LIST_HEAD(&w->sources); | 3111 | INIT_LIST_HEAD(&w->sources); |
3068 | INIT_LIST_HEAD(&w->sinks); | 3112 | INIT_LIST_HEAD(&w->sinks); |
3069 | INIT_LIST_HEAD(&w->list); | 3113 | INIT_LIST_HEAD(&w->list); |
@@ -3170,27 +3214,15 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, | |||
3170 | 3214 | ||
3171 | switch (event) { | 3215 | switch (event) { |
3172 | case SND_SOC_DAPM_PRE_PMU: | 3216 | case SND_SOC_DAPM_PRE_PMU: |
3173 | if (source->driver->ops && source->driver->ops->hw_params) { | 3217 | substream.stream = SNDRV_PCM_STREAM_CAPTURE; |
3174 | substream.stream = SNDRV_PCM_STREAM_CAPTURE; | 3218 | ret = soc_dai_hw_params(&substream, params, source); |
3175 | ret = source->driver->ops->hw_params(&substream, | 3219 | if (ret < 0) |
3176 | params, source); | 3220 | goto out; |
3177 | if (ret != 0) { | ||
3178 | dev_err(source->dev, | ||
3179 | "ASoC: hw_params() failed: %d\n", ret); | ||
3180 | goto out; | ||
3181 | } | ||
3182 | } | ||
3183 | 3221 | ||
3184 | if (sink->driver->ops && sink->driver->ops->hw_params) { | 3222 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; |
3185 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; | 3223 | ret = soc_dai_hw_params(&substream, params, sink); |
3186 | ret = sink->driver->ops->hw_params(&substream, params, | 3224 | if (ret < 0) |
3187 | sink); | 3225 | goto out; |
3188 | if (ret != 0) { | ||
3189 | dev_err(sink->dev, | ||
3190 | "ASoC: hw_params() failed: %d\n", ret); | ||
3191 | goto out; | ||
3192 | } | ||
3193 | } | ||
3194 | break; | 3226 | break; |
3195 | 3227 | ||
3196 | case SND_SOC_DAPM_POST_PMU: | 3228 | case SND_SOC_DAPM_POST_PMU: |
@@ -3362,25 +3394,15 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3362 | return 0; | 3394 | return 0; |
3363 | } | 3395 | } |
3364 | 3396 | ||
3365 | void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | 3397 | static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, |
3398 | struct snd_soc_pcm_runtime *rtd) | ||
3366 | { | 3399 | { |
3367 | struct snd_soc_pcm_runtime *rtd = card->rtd; | 3400 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
3368 | struct snd_soc_dapm_widget *sink, *source; | 3401 | struct snd_soc_dapm_widget *sink, *source; |
3369 | struct snd_soc_dai *cpu_dai, *codec_dai; | ||
3370 | int i; | 3402 | int i; |
3371 | 3403 | ||
3372 | /* for each BE DAI link... */ | 3404 | for (i = 0; i < rtd->num_codecs; i++) { |
3373 | for (i = 0; i < card->num_rtd; i++) { | 3405 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
3374 | rtd = &card->rtd[i]; | ||
3375 | cpu_dai = rtd->cpu_dai; | ||
3376 | codec_dai = rtd->codec_dai; | ||
3377 | |||
3378 | /* | ||
3379 | * dynamic FE links have no fixed DAI mapping. | ||
3380 | * CODEC<->CODEC links have no direct connection. | ||
3381 | */ | ||
3382 | if (rtd->dai_link->dynamic || rtd->dai_link->params) | ||
3383 | continue; | ||
3384 | 3406 | ||
3385 | /* there is no point in connecting BE DAI links with dummies */ | 3407 | /* there is no point in connecting BE DAI links with dummies */ |
3386 | if (snd_soc_dai_is_dummy(codec_dai) || | 3408 | if (snd_soc_dai_is_dummy(codec_dai) || |
@@ -3392,8 +3414,8 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | |||
3392 | source = cpu_dai->playback_widget; | 3414 | source = cpu_dai->playback_widget; |
3393 | sink = codec_dai->playback_widget; | 3415 | sink = codec_dai->playback_widget; |
3394 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", | 3416 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", |
3395 | cpu_dai->codec->name, source->name, | 3417 | cpu_dai->component->name, source->name, |
3396 | codec_dai->platform->name, sink->name); | 3418 | codec_dai->component->name, sink->name); |
3397 | 3419 | ||
3398 | snd_soc_dapm_add_path(&card->dapm, source, sink, | 3420 | snd_soc_dapm_add_path(&card->dapm, source, sink, |
3399 | NULL, NULL); | 3421 | NULL, NULL); |
@@ -3404,8 +3426,8 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | |||
3404 | source = codec_dai->capture_widget; | 3426 | source = codec_dai->capture_widget; |
3405 | sink = cpu_dai->capture_widget; | 3427 | sink = cpu_dai->capture_widget; |
3406 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", | 3428 | dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", |
3407 | codec_dai->codec->name, source->name, | 3429 | codec_dai->component->name, source->name, |
3408 | cpu_dai->platform->name, sink->name); | 3430 | cpu_dai->component->name, sink->name); |
3409 | 3431 | ||
3410 | snd_soc_dapm_add_path(&card->dapm, source, sink, | 3432 | snd_soc_dapm_add_path(&card->dapm, source, sink, |
3411 | NULL, NULL); | 3433 | NULL, NULL); |
@@ -3442,11 +3464,34 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, | |||
3442 | } | 3464 | } |
3443 | } | 3465 | } |
3444 | 3466 | ||
3467 | void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) | ||
3468 | { | ||
3469 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
3470 | int i; | ||
3471 | |||
3472 | /* for each BE DAI link... */ | ||
3473 | for (i = 0; i < card->num_rtd; i++) { | ||
3474 | rtd = &card->rtd[i]; | ||
3475 | |||
3476 | /* | ||
3477 | * dynamic FE links have no fixed DAI mapping. | ||
3478 | * CODEC<->CODEC links have no direct connection. | ||
3479 | */ | ||
3480 | if (rtd->dai_link->dynamic || rtd->dai_link->params) | ||
3481 | continue; | ||
3482 | |||
3483 | dapm_connect_dai_link_widgets(card, rtd); | ||
3484 | } | ||
3485 | } | ||
3486 | |||
3445 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | 3487 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
3446 | int event) | 3488 | int event) |
3447 | { | 3489 | { |
3490 | int i; | ||
3491 | |||
3448 | soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); | 3492 | soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); |
3449 | soc_dapm_dai_stream_event(rtd->codec_dai, stream, event); | 3493 | for (i = 0; i < rtd->num_codecs; i++) |
3494 | soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); | ||
3450 | 3495 | ||
3451 | dapm_power_widgets(rtd->card, event); | 3496 | dapm_power_widgets(rtd->card, event); |
3452 | } | 3497 | } |
@@ -3755,36 +3800,31 @@ static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, | |||
3755 | } | 3800 | } |
3756 | 3801 | ||
3757 | /** | 3802 | /** |
3758 | * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins | 3803 | * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins |
3759 | * @codec: The codec whose pins should be processed | 3804 | * @card: The card whose pins should be processed |
3760 | * | 3805 | * |
3761 | * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec | 3806 | * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card |
3762 | * which are unused. Pins are used if they are connected externally to the | 3807 | * which are unused. Pins are used if they are connected externally to a |
3763 | * codec, whether that be to some other device, or a loop-back connection to | 3808 | * component, whether that be to some other device, or a loop-back connection to |
3764 | * the codec itself. | 3809 | * the component itself. |
3765 | */ | 3810 | */ |
3766 | void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) | 3811 | void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card) |
3767 | { | 3812 | { |
3768 | struct snd_soc_card *card = codec->card; | ||
3769 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
3770 | struct snd_soc_dapm_widget *w; | 3813 | struct snd_soc_dapm_widget *w; |
3771 | 3814 | ||
3772 | dev_dbg(codec->dev, "ASoC: Auto NC: DAPMs: card:%p codec:%p\n", | 3815 | dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm); |
3773 | &card->dapm, &codec->dapm); | ||
3774 | 3816 | ||
3775 | list_for_each_entry(w, &card->widgets, list) { | 3817 | list_for_each_entry(w, &card->widgets, list) { |
3776 | if (w->dapm != dapm) | ||
3777 | continue; | ||
3778 | switch (w->id) { | 3818 | switch (w->id) { |
3779 | case snd_soc_dapm_input: | 3819 | case snd_soc_dapm_input: |
3780 | case snd_soc_dapm_output: | 3820 | case snd_soc_dapm_output: |
3781 | case snd_soc_dapm_micbias: | 3821 | case snd_soc_dapm_micbias: |
3782 | dev_dbg(codec->dev, "ASoC: Auto NC: Checking widget %s\n", | 3822 | dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n", |
3783 | w->name); | 3823 | w->name); |
3784 | if (!snd_soc_dapm_widget_in_card_paths(card, w)) { | 3824 | if (!snd_soc_dapm_widget_in_card_paths(card, w)) { |
3785 | dev_dbg(codec->dev, | 3825 | dev_dbg(card->dev, |
3786 | "... Not in map; disabling\n"); | 3826 | "... Not in map; disabling\n"); |
3787 | snd_soc_dapm_nc_pin(dapm, w->name); | 3827 | snd_soc_dapm_nc_pin(w->dapm, w->name); |
3788 | } | 3828 | } |
3789 | break; | 3829 | break; |
3790 | default: | 3830 | default: |
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 5bace124ef43..6307f85e871b 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c | |||
@@ -119,7 +119,10 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea | |||
119 | struct snd_dmaengine_dai_dma_data *dma_data; | 119 | struct snd_dmaengine_dai_dma_data *dma_data; |
120 | struct dma_slave_caps dma_caps; | 120 | struct dma_slave_caps dma_caps; |
121 | struct snd_pcm_hardware hw; | 121 | struct snd_pcm_hardware hw; |
122 | int ret; | 122 | u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | |
123 | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | | ||
124 | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); | ||
125 | int i, ret; | ||
123 | 126 | ||
124 | if (pcm->config && pcm->config->pcm_hardware) | 127 | if (pcm->config && pcm->config->pcm_hardware) |
125 | return snd_soc_set_runtime_hwparams(substream, | 128 | return snd_soc_set_runtime_hwparams(substream, |
@@ -146,6 +149,38 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea | |||
146 | hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; | 149 | hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; |
147 | if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) | 150 | if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) |
148 | hw.info |= SNDRV_PCM_INFO_BATCH; | 151 | hw.info |= SNDRV_PCM_INFO_BATCH; |
152 | |||
153 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
154 | addr_widths = dma_caps.dstn_addr_widths; | ||
155 | else | ||
156 | addr_widths = dma_caps.src_addr_widths; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Prepare formats mask for valid/allowed sample types. If the dma does | ||
161 | * not have support for the given physical word size, it needs to be | ||
162 | * masked out so user space can not use the format which produces | ||
163 | * corrupted audio. | ||
164 | * In case the dma driver does not implement the slave_caps the default | ||
165 | * assumption is that it supports 1, 2 and 4 bytes widths. | ||
166 | */ | ||
167 | for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { | ||
168 | int bits = snd_pcm_format_physical_width(i); | ||
169 | |||
170 | /* Enable only samples with DMA supported physical widths */ | ||
171 | switch (bits) { | ||
172 | case 8: | ||
173 | case 16: | ||
174 | case 24: | ||
175 | case 32: | ||
176 | case 64: | ||
177 | if (addr_widths & (1 << (bits / 8))) | ||
178 | hw.formats |= (1LL << i); | ||
179 | break; | ||
180 | default: | ||
181 | /* Unsupported types */ | ||
182 | break; | ||
183 | } | ||
149 | } | 184 | } |
150 | 185 | ||
151 | return snd_soc_set_runtime_hwparams(substream, &hw); | 186 | return snd_soc_set_runtime_hwparams(substream, &hw); |
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index d0d98810af91..ab47fea997a3 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -43,7 +43,7 @@ int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, | |||
43 | INIT_LIST_HEAD(&jack->jack_zones); | 43 | INIT_LIST_HEAD(&jack->jack_zones); |
44 | BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); | 44 | BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); |
45 | 45 | ||
46 | return snd_jack_new(codec->card->snd_card, id, type, &jack->jack); | 46 | return snd_jack_new(codec->component.card->snd_card, id, type, &jack->jack); |
47 | } | 47 | } |
48 | EXPORT_SYMBOL_GPL(snd_soc_jack_new); | 48 | EXPORT_SYMBOL_GPL(snd_soc_jack_new); |
49 | 49 | ||
@@ -260,7 +260,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) | |||
260 | static irqreturn_t gpio_handler(int irq, void *data) | 260 | static irqreturn_t gpio_handler(int irq, void *data) |
261 | { | 261 | { |
262 | struct snd_soc_jack_gpio *gpio = data; | 262 | struct snd_soc_jack_gpio *gpio = data; |
263 | struct device *dev = gpio->jack->codec->card->dev; | 263 | struct device *dev = gpio->jack->codec->component.card->dev; |
264 | 264 | ||
265 | trace_snd_soc_jack_irq(gpio->name); | 265 | trace_snd_soc_jack_irq(gpio->name); |
266 | 266 | ||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 54d18f22a33e..731fdb5b5f9b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Copyright (C) 2010 Texas Instruments Inc. | 7 | * Copyright (C) 2010 Texas Instruments Inc. |
8 | * | 8 | * |
9 | * Authors: Liam Girdwood <lrg@ti.com> | 9 | * Authors: Liam Girdwood <lrg@ti.com> |
10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | 10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 12 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
@@ -47,22 +47,26 @@ | |||
47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | 47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) |
48 | { | 48 | { |
49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
50 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 50 | int i; |
51 | 51 | ||
52 | lockdep_assert_held(&rtd->pcm_mutex); | 52 | lockdep_assert_held(&rtd->pcm_mutex); |
53 | 53 | ||
54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
55 | cpu_dai->playback_active++; | 55 | cpu_dai->playback_active++; |
56 | codec_dai->playback_active++; | 56 | for (i = 0; i < rtd->num_codecs; i++) |
57 | rtd->codec_dais[i]->playback_active++; | ||
57 | } else { | 58 | } else { |
58 | cpu_dai->capture_active++; | 59 | cpu_dai->capture_active++; |
59 | codec_dai->capture_active++; | 60 | for (i = 0; i < rtd->num_codecs; i++) |
61 | rtd->codec_dais[i]->capture_active++; | ||
60 | } | 62 | } |
61 | 63 | ||
62 | cpu_dai->active++; | 64 | cpu_dai->active++; |
63 | codec_dai->active++; | ||
64 | cpu_dai->component->active++; | 65 | cpu_dai->component->active++; |
65 | codec_dai->component->active++; | 66 | for (i = 0; i < rtd->num_codecs; i++) { |
67 | rtd->codec_dais[i]->active++; | ||
68 | rtd->codec_dais[i]->component->active++; | ||
69 | } | ||
66 | } | 70 | } |
67 | 71 | ||
68 | /** | 72 | /** |
@@ -78,22 +82,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
78 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | 82 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) |
79 | { | 83 | { |
80 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 84 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 85 | int i; |
82 | 86 | ||
83 | lockdep_assert_held(&rtd->pcm_mutex); | 87 | lockdep_assert_held(&rtd->pcm_mutex); |
84 | 88 | ||
85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 89 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
86 | cpu_dai->playback_active--; | 90 | cpu_dai->playback_active--; |
87 | codec_dai->playback_active--; | 91 | for (i = 0; i < rtd->num_codecs; i++) |
92 | rtd->codec_dais[i]->playback_active--; | ||
88 | } else { | 93 | } else { |
89 | cpu_dai->capture_active--; | 94 | cpu_dai->capture_active--; |
90 | codec_dai->capture_active--; | 95 | for (i = 0; i < rtd->num_codecs; i++) |
96 | rtd->codec_dais[i]->capture_active--; | ||
91 | } | 97 | } |
92 | 98 | ||
93 | cpu_dai->active--; | 99 | cpu_dai->active--; |
94 | codec_dai->active--; | ||
95 | cpu_dai->component->active--; | 100 | cpu_dai->component->active--; |
96 | codec_dai->component->active--; | 101 | for (i = 0; i < rtd->num_codecs; i++) { |
102 | rtd->codec_dais[i]->component->active--; | ||
103 | rtd->codec_dais[i]->active--; | ||
104 | } | ||
97 | } | 105 | } |
98 | 106 | ||
99 | /** | 107 | /** |
@@ -107,11 +115,16 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
107 | */ | 115 | */ |
108 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) | 116 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) |
109 | { | 117 | { |
118 | int i; | ||
119 | bool ignore = true; | ||
120 | |||
110 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) | 121 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) |
111 | return true; | 122 | return true; |
112 | 123 | ||
113 | return rtd->cpu_dai->component->ignore_pmdown_time && | 124 | for (i = 0; i < rtd->num_codecs; i++) |
114 | rtd->codec_dai->component->ignore_pmdown_time; | 125 | ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time; |
126 | |||
127 | return rtd->cpu_dai->component->ignore_pmdown_time && ignore; | ||
115 | } | 128 | } |
116 | 129 | ||
117 | /** | 130 | /** |
@@ -222,8 +235,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
222 | { | 235 | { |
223 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 236 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
224 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 237 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
225 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 238 | unsigned int rate, channels, sample_bits, symmetry, i; |
226 | unsigned int rate, channels, sample_bits, symmetry; | ||
227 | 239 | ||
228 | rate = params_rate(params); | 240 | rate = params_rate(params); |
229 | channels = params_channels(params); | 241 | channels = params_channels(params); |
@@ -231,8 +243,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
231 | 243 | ||
232 | /* reject unmatched parameters when applying symmetry */ | 244 | /* reject unmatched parameters when applying symmetry */ |
233 | symmetry = cpu_dai->driver->symmetric_rates || | 245 | symmetry = cpu_dai->driver->symmetric_rates || |
234 | codec_dai->driver->symmetric_rates || | ||
235 | rtd->dai_link->symmetric_rates; | 246 | rtd->dai_link->symmetric_rates; |
247 | |||
248 | for (i = 0; i < rtd->num_codecs; i++) | ||
249 | symmetry |= rtd->codec_dais[i]->driver->symmetric_rates; | ||
250 | |||
236 | if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { | 251 | if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { |
237 | dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", | 252 | dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", |
238 | cpu_dai->rate, rate); | 253 | cpu_dai->rate, rate); |
@@ -240,8 +255,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
240 | } | 255 | } |
241 | 256 | ||
242 | symmetry = cpu_dai->driver->symmetric_channels || | 257 | symmetry = cpu_dai->driver->symmetric_channels || |
243 | codec_dai->driver->symmetric_channels || | ||
244 | rtd->dai_link->symmetric_channels; | 258 | rtd->dai_link->symmetric_channels; |
259 | |||
260 | for (i = 0; i < rtd->num_codecs; i++) | ||
261 | symmetry |= rtd->codec_dais[i]->driver->symmetric_channels; | ||
262 | |||
245 | if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { | 263 | if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { |
246 | dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", | 264 | dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", |
247 | cpu_dai->channels, channels); | 265 | cpu_dai->channels, channels); |
@@ -249,8 +267,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
249 | } | 267 | } |
250 | 268 | ||
251 | symmetry = cpu_dai->driver->symmetric_samplebits || | 269 | symmetry = cpu_dai->driver->symmetric_samplebits || |
252 | codec_dai->driver->symmetric_samplebits || | ||
253 | rtd->dai_link->symmetric_samplebits; | 270 | rtd->dai_link->symmetric_samplebits; |
271 | |||
272 | for (i = 0; i < rtd->num_codecs; i++) | ||
273 | symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits; | ||
274 | |||
254 | if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { | 275 | if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { |
255 | dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", | 276 | dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", |
256 | cpu_dai->sample_bits, sample_bits); | 277 | cpu_dai->sample_bits, sample_bits); |
@@ -264,15 +285,20 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) | |||
264 | { | 285 | { |
265 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 286 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
266 | struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; | 287 | struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; |
267 | struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver; | ||
268 | struct snd_soc_dai_link *link = rtd->dai_link; | 288 | struct snd_soc_dai_link *link = rtd->dai_link; |
289 | unsigned int symmetry, i; | ||
269 | 290 | ||
270 | return cpu_driver->symmetric_rates || codec_driver->symmetric_rates || | 291 | symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || |
271 | link->symmetric_rates || cpu_driver->symmetric_channels || | 292 | cpu_driver->symmetric_channels || link->symmetric_channels || |
272 | codec_driver->symmetric_channels || link->symmetric_channels || | 293 | cpu_driver->symmetric_samplebits || link->symmetric_samplebits; |
273 | cpu_driver->symmetric_samplebits || | 294 | |
274 | codec_driver->symmetric_samplebits || | 295 | for (i = 0; i < rtd->num_codecs; i++) |
275 | link->symmetric_samplebits; | 296 | symmetry = symmetry || |
297 | rtd->codec_dais[i]->driver->symmetric_rates || | ||
298 | rtd->codec_dais[i]->driver->symmetric_channels || | ||
299 | rtd->codec_dais[i]->driver->symmetric_samplebits; | ||
300 | |||
301 | return symmetry; | ||
276 | } | 302 | } |
277 | 303 | ||
278 | /* | 304 | /* |
@@ -284,15 +310,10 @@ static int sample_sizes[] = { | |||
284 | 24, 32, | 310 | 24, 32, |
285 | }; | 311 | }; |
286 | 312 | ||
287 | static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, | 313 | static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) |
288 | struct snd_soc_dai *dai) | ||
289 | { | 314 | { |
290 | int ret, i, bits; | 315 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
291 | 316 | int ret, i; | |
292 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
293 | bits = dai->driver->playback.sig_bits; | ||
294 | else | ||
295 | bits = dai->driver->capture.sig_bits; | ||
296 | 317 | ||
297 | if (!bits) | 318 | if (!bits) |
298 | return; | 319 | return; |
@@ -304,38 +325,105 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, | |||
304 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, | 325 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, |
305 | sample_sizes[i], bits); | 326 | sample_sizes[i], bits); |
306 | if (ret != 0) | 327 | if (ret != 0) |
307 | dev_warn(dai->dev, | 328 | dev_warn(rtd->dev, |
308 | "ASoC: Failed to set MSB %d/%d: %d\n", | 329 | "ASoC: Failed to set MSB %d/%d: %d\n", |
309 | bits, sample_sizes[i], ret); | 330 | bits, sample_sizes[i], ret); |
310 | } | 331 | } |
311 | } | 332 | } |
312 | 333 | ||
313 | static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime, | 334 | static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) |
314 | struct snd_soc_pcm_stream *codec_stream, | 335 | { |
315 | struct snd_soc_pcm_stream *cpu_stream) | 336 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
337 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
338 | struct snd_soc_dai *codec_dai; | ||
339 | int i; | ||
340 | unsigned int bits = 0, cpu_bits; | ||
341 | |||
342 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
343 | for (i = 0; i < rtd->num_codecs; i++) { | ||
344 | codec_dai = rtd->codec_dais[i]; | ||
345 | if (codec_dai->driver->playback.sig_bits == 0) { | ||
346 | bits = 0; | ||
347 | break; | ||
348 | } | ||
349 | bits = max(codec_dai->driver->playback.sig_bits, bits); | ||
350 | } | ||
351 | cpu_bits = cpu_dai->driver->playback.sig_bits; | ||
352 | } else { | ||
353 | for (i = 0; i < rtd->num_codecs; i++) { | ||
354 | codec_dai = rtd->codec_dais[i]; | ||
355 | if (codec_dai->driver->playback.sig_bits == 0) { | ||
356 | bits = 0; | ||
357 | break; | ||
358 | } | ||
359 | bits = max(codec_dai->driver->capture.sig_bits, bits); | ||
360 | } | ||
361 | cpu_bits = cpu_dai->driver->capture.sig_bits; | ||
362 | } | ||
363 | |||
364 | soc_pcm_set_msb(substream, bits); | ||
365 | soc_pcm_set_msb(substream, cpu_bits); | ||
366 | } | ||
367 | |||
368 | static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) | ||
316 | { | 369 | { |
370 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
317 | struct snd_pcm_hardware *hw = &runtime->hw; | 371 | struct snd_pcm_hardware *hw = &runtime->hw; |
372 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
373 | struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver; | ||
374 | struct snd_soc_dai_driver *codec_dai_drv; | ||
375 | struct snd_soc_pcm_stream *codec_stream; | ||
376 | struct snd_soc_pcm_stream *cpu_stream; | ||
377 | unsigned int chan_min = 0, chan_max = UINT_MAX; | ||
378 | unsigned int rate_min = 0, rate_max = UINT_MAX; | ||
379 | unsigned int rates = UINT_MAX; | ||
380 | u64 formats = ULLONG_MAX; | ||
381 | int i; | ||
318 | 382 | ||
319 | hw->channels_min = max(codec_stream->channels_min, | 383 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
320 | cpu_stream->channels_min); | 384 | cpu_stream = &cpu_dai_drv->playback; |
321 | hw->channels_max = min(codec_stream->channels_max, | ||
322 | cpu_stream->channels_max); | ||
323 | if (hw->formats) | ||
324 | hw->formats &= codec_stream->formats & cpu_stream->formats; | ||
325 | else | 385 | else |
326 | hw->formats = codec_stream->formats & cpu_stream->formats; | 386 | cpu_stream = &cpu_dai_drv->capture; |
327 | hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates, | ||
328 | cpu_stream->rates); | ||
329 | 387 | ||
330 | hw->rate_min = 0; | 388 | /* first calculate min/max only for CODECs in the DAI link */ |
331 | hw->rate_max = UINT_MAX; | 389 | for (i = 0; i < rtd->num_codecs; i++) { |
390 | codec_dai_drv = rtd->codec_dais[i]->driver; | ||
391 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
392 | codec_stream = &codec_dai_drv->playback; | ||
393 | else | ||
394 | codec_stream = &codec_dai_drv->capture; | ||
395 | chan_min = max(chan_min, codec_stream->channels_min); | ||
396 | chan_max = min(chan_max, codec_stream->channels_max); | ||
397 | rate_min = max(rate_min, codec_stream->rate_min); | ||
398 | rate_max = min_not_zero(rate_max, codec_stream->rate_max); | ||
399 | formats &= codec_stream->formats; | ||
400 | rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * chan min/max cannot be enforced if there are multiple CODEC DAIs | ||
405 | * connected to a single CPU DAI, use CPU DAI's directly and let | ||
406 | * channel allocation be fixed up later | ||
407 | */ | ||
408 | if (rtd->num_codecs > 1) { | ||
409 | chan_min = cpu_stream->channels_min; | ||
410 | chan_max = cpu_stream->channels_max; | ||
411 | } | ||
412 | |||
413 | hw->channels_min = max(chan_min, cpu_stream->channels_min); | ||
414 | hw->channels_max = min(chan_max, cpu_stream->channels_max); | ||
415 | if (hw->formats) | ||
416 | hw->formats &= formats & cpu_stream->formats; | ||
417 | else | ||
418 | hw->formats = formats & cpu_stream->formats; | ||
419 | hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates); | ||
332 | 420 | ||
333 | snd_pcm_limit_hw_rates(runtime); | 421 | snd_pcm_limit_hw_rates(runtime); |
334 | 422 | ||
335 | hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); | 423 | hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); |
336 | hw->rate_min = max(hw->rate_min, codec_stream->rate_min); | 424 | hw->rate_min = max(hw->rate_min, rate_min); |
337 | hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max); | 425 | hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max); |
338 | hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max); | 426 | hw->rate_max = min_not_zero(hw->rate_max, rate_max); |
339 | } | 427 | } |
340 | 428 | ||
341 | /* | 429 | /* |
@@ -349,15 +437,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
349 | struct snd_pcm_runtime *runtime = substream->runtime; | 437 | struct snd_pcm_runtime *runtime = substream->runtime; |
350 | struct snd_soc_platform *platform = rtd->platform; | 438 | struct snd_soc_platform *platform = rtd->platform; |
351 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 439 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
352 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 440 | struct snd_soc_dai *codec_dai; |
353 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 441 | const char *codec_dai_name = "multicodec"; |
354 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | 442 | int i, ret = 0; |
355 | int ret = 0; | ||
356 | 443 | ||
357 | pinctrl_pm_select_default_state(cpu_dai->dev); | 444 | pinctrl_pm_select_default_state(cpu_dai->dev); |
358 | pinctrl_pm_select_default_state(codec_dai->dev); | 445 | for (i = 0; i < rtd->num_codecs; i++) |
446 | pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); | ||
359 | pm_runtime_get_sync(cpu_dai->dev); | 447 | pm_runtime_get_sync(cpu_dai->dev); |
360 | pm_runtime_get_sync(codec_dai->dev); | 448 | for (i = 0; i < rtd->num_codecs; i++) |
449 | pm_runtime_get_sync(rtd->codec_dais[i]->dev); | ||
361 | pm_runtime_get_sync(platform->dev); | 450 | pm_runtime_get_sync(platform->dev); |
362 | 451 | ||
363 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 452 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
@@ -376,18 +465,28 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
376 | ret = platform->driver->ops->open(substream); | 465 | ret = platform->driver->ops->open(substream); |
377 | if (ret < 0) { | 466 | if (ret < 0) { |
378 | dev_err(platform->dev, "ASoC: can't open platform" | 467 | dev_err(platform->dev, "ASoC: can't open platform" |
379 | " %s: %d\n", platform->name, ret); | 468 | " %s: %d\n", platform->component.name, ret); |
380 | goto platform_err; | 469 | goto platform_err; |
381 | } | 470 | } |
382 | } | 471 | } |
383 | 472 | ||
384 | if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { | 473 | for (i = 0; i < rtd->num_codecs; i++) { |
385 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | 474 | codec_dai = rtd->codec_dais[i]; |
386 | if (ret < 0) { | 475 | if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { |
387 | dev_err(codec_dai->dev, "ASoC: can't open codec" | 476 | ret = codec_dai->driver->ops->startup(substream, |
388 | " %s: %d\n", codec_dai->name, ret); | 477 | codec_dai); |
389 | goto codec_dai_err; | 478 | if (ret < 0) { |
479 | dev_err(codec_dai->dev, | ||
480 | "ASoC: can't open codec %s: %d\n", | ||
481 | codec_dai->name, ret); | ||
482 | goto codec_dai_err; | ||
483 | } | ||
390 | } | 484 | } |
485 | |||
486 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
487 | codec_dai->tx_mask = 0; | ||
488 | else | ||
489 | codec_dai->rx_mask = 0; | ||
391 | } | 490 | } |
392 | 491 | ||
393 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | 492 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { |
@@ -404,13 +503,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
404 | goto dynamic; | 503 | goto dynamic; |
405 | 504 | ||
406 | /* Check that the codec and cpu DAIs are compatible */ | 505 | /* Check that the codec and cpu DAIs are compatible */ |
407 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 506 | soc_pcm_init_runtime_hw(substream); |
408 | soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback, | 507 | |
409 | &cpu_dai_drv->playback); | 508 | if (rtd->num_codecs == 1) |
410 | } else { | 509 | codec_dai_name = rtd->codec_dai->name; |
411 | soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture, | ||
412 | &cpu_dai_drv->capture); | ||
413 | } | ||
414 | 510 | ||
415 | if (soc_pcm_has_symmetry(substream)) | 511 | if (soc_pcm_has_symmetry(substream)) |
416 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; | 512 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; |
@@ -418,23 +514,22 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
418 | ret = -EINVAL; | 514 | ret = -EINVAL; |
419 | if (!runtime->hw.rates) { | 515 | if (!runtime->hw.rates) { |
420 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", | 516 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", |
421 | codec_dai->name, cpu_dai->name); | 517 | codec_dai_name, cpu_dai->name); |
422 | goto config_err; | 518 | goto config_err; |
423 | } | 519 | } |
424 | if (!runtime->hw.formats) { | 520 | if (!runtime->hw.formats) { |
425 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", | 521 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", |
426 | codec_dai->name, cpu_dai->name); | 522 | codec_dai_name, cpu_dai->name); |
427 | goto config_err; | 523 | goto config_err; |
428 | } | 524 | } |
429 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || | 525 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || |
430 | runtime->hw.channels_min > runtime->hw.channels_max) { | 526 | runtime->hw.channels_min > runtime->hw.channels_max) { |
431 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", | 527 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", |
432 | codec_dai->name, cpu_dai->name); | 528 | codec_dai_name, cpu_dai->name); |
433 | goto config_err; | 529 | goto config_err; |
434 | } | 530 | } |
435 | 531 | ||
436 | soc_pcm_apply_msb(substream, codec_dai); | 532 | soc_pcm_apply_msb(substream); |
437 | soc_pcm_apply_msb(substream, cpu_dai); | ||
438 | 533 | ||
439 | /* Symmetry only applies if we've already got an active stream. */ | 534 | /* Symmetry only applies if we've already got an active stream. */ |
440 | if (cpu_dai->active) { | 535 | if (cpu_dai->active) { |
@@ -443,14 +538,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
443 | goto config_err; | 538 | goto config_err; |
444 | } | 539 | } |
445 | 540 | ||
446 | if (codec_dai->active) { | 541 | for (i = 0; i < rtd->num_codecs; i++) { |
447 | ret = soc_pcm_apply_symmetry(substream, codec_dai); | 542 | if (rtd->codec_dais[i]->active) { |
448 | if (ret != 0) | 543 | ret = soc_pcm_apply_symmetry(substream, |
449 | goto config_err; | 544 | rtd->codec_dais[i]); |
545 | if (ret != 0) | ||
546 | goto config_err; | ||
547 | } | ||
450 | } | 548 | } |
451 | 549 | ||
452 | pr_debug("ASoC: %s <-> %s info:\n", | 550 | pr_debug("ASoC: %s <-> %s info:\n", |
453 | codec_dai->name, cpu_dai->name); | 551 | codec_dai_name, cpu_dai->name); |
454 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); | 552 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); |
455 | pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, | 553 | pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, |
456 | runtime->hw.channels_max); | 554 | runtime->hw.channels_max); |
@@ -469,10 +567,15 @@ config_err: | |||
469 | rtd->dai_link->ops->shutdown(substream); | 567 | rtd->dai_link->ops->shutdown(substream); |
470 | 568 | ||
471 | machine_err: | 569 | machine_err: |
472 | if (codec_dai->driver->ops->shutdown) | 570 | i = rtd->num_codecs; |
473 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
474 | 571 | ||
475 | codec_dai_err: | 572 | codec_dai_err: |
573 | while (--i >= 0) { | ||
574 | codec_dai = rtd->codec_dais[i]; | ||
575 | if (codec_dai->driver->ops->shutdown) | ||
576 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
577 | } | ||
578 | |||
476 | if (platform->driver->ops && platform->driver->ops->close) | 579 | if (platform->driver->ops && platform->driver->ops->close) |
477 | platform->driver->ops->close(substream); | 580 | platform->driver->ops->close(substream); |
478 | 581 | ||
@@ -483,10 +586,13 @@ out: | |||
483 | mutex_unlock(&rtd->pcm_mutex); | 586 | mutex_unlock(&rtd->pcm_mutex); |
484 | 587 | ||
485 | pm_runtime_put(platform->dev); | 588 | pm_runtime_put(platform->dev); |
486 | pm_runtime_put(codec_dai->dev); | 589 | for (i = 0; i < rtd->num_codecs; i++) |
590 | pm_runtime_put(rtd->codec_dais[i]->dev); | ||
487 | pm_runtime_put(cpu_dai->dev); | 591 | pm_runtime_put(cpu_dai->dev); |
488 | if (!codec_dai->active) | 592 | for (i = 0; i < rtd->num_codecs; i++) { |
489 | pinctrl_pm_select_sleep_state(codec_dai->dev); | 593 | if (!rtd->codec_dais[i]->active) |
594 | pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); | ||
595 | } | ||
490 | if (!cpu_dai->active) | 596 | if (!cpu_dai->active) |
491 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 597 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
492 | 598 | ||
@@ -502,7 +608,7 @@ static void close_delayed_work(struct work_struct *work) | |||
502 | { | 608 | { |
503 | struct snd_soc_pcm_runtime *rtd = | 609 | struct snd_soc_pcm_runtime *rtd = |
504 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | 610 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
505 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 611 | struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; |
506 | 612 | ||
507 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 613 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
508 | 614 | ||
@@ -531,7 +637,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
531 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 637 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
532 | struct snd_soc_platform *platform = rtd->platform; | 638 | struct snd_soc_platform *platform = rtd->platform; |
533 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 639 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
534 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 640 | struct snd_soc_dai *codec_dai; |
641 | int i; | ||
535 | 642 | ||
536 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 643 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
537 | 644 | ||
@@ -541,14 +648,20 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
541 | if (!cpu_dai->active) | 648 | if (!cpu_dai->active) |
542 | cpu_dai->rate = 0; | 649 | cpu_dai->rate = 0; |
543 | 650 | ||
544 | if (!codec_dai->active) | 651 | for (i = 0; i < rtd->num_codecs; i++) { |
545 | codec_dai->rate = 0; | 652 | codec_dai = rtd->codec_dais[i]; |
653 | if (!codec_dai->active) | ||
654 | codec_dai->rate = 0; | ||
655 | } | ||
546 | 656 | ||
547 | if (cpu_dai->driver->ops->shutdown) | 657 | if (cpu_dai->driver->ops->shutdown) |
548 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 658 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
549 | 659 | ||
550 | if (codec_dai->driver->ops->shutdown) | 660 | for (i = 0; i < rtd->num_codecs; i++) { |
551 | codec_dai->driver->ops->shutdown(substream, codec_dai); | 661 | codec_dai = rtd->codec_dais[i]; |
662 | if (codec_dai->driver->ops->shutdown) | ||
663 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
664 | } | ||
552 | 665 | ||
553 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 666 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
554 | rtd->dai_link->ops->shutdown(substream); | 667 | rtd->dai_link->ops->shutdown(substream); |
@@ -578,10 +691,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
578 | mutex_unlock(&rtd->pcm_mutex); | 691 | mutex_unlock(&rtd->pcm_mutex); |
579 | 692 | ||
580 | pm_runtime_put(platform->dev); | 693 | pm_runtime_put(platform->dev); |
581 | pm_runtime_put(codec_dai->dev); | 694 | for (i = 0; i < rtd->num_codecs; i++) |
695 | pm_runtime_put(rtd->codec_dais[i]->dev); | ||
582 | pm_runtime_put(cpu_dai->dev); | 696 | pm_runtime_put(cpu_dai->dev); |
583 | if (!codec_dai->active) | 697 | for (i = 0; i < rtd->num_codecs; i++) { |
584 | pinctrl_pm_select_sleep_state(codec_dai->dev); | 698 | if (!rtd->codec_dais[i]->active) |
699 | pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); | ||
700 | } | ||
585 | if (!cpu_dai->active) | 701 | if (!cpu_dai->active) |
586 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 702 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
587 | 703 | ||
@@ -598,8 +714,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
598 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 714 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
599 | struct snd_soc_platform *platform = rtd->platform; | 715 | struct snd_soc_platform *platform = rtd->platform; |
600 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 716 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
601 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 717 | struct snd_soc_dai *codec_dai; |
602 | int ret = 0; | 718 | int i, ret = 0; |
603 | 719 | ||
604 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 720 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
605 | 721 | ||
@@ -621,12 +737,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
621 | } | 737 | } |
622 | } | 738 | } |
623 | 739 | ||
624 | if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { | 740 | for (i = 0; i < rtd->num_codecs; i++) { |
625 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | 741 | codec_dai = rtd->codec_dais[i]; |
626 | if (ret < 0) { | 742 | if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { |
627 | dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n", | 743 | ret = codec_dai->driver->ops->prepare(substream, |
628 | ret); | 744 | codec_dai); |
629 | goto out; | 745 | if (ret < 0) { |
746 | dev_err(codec_dai->dev, | ||
747 | "ASoC: DAI prepare error: %d\n", ret); | ||
748 | goto out; | ||
749 | } | ||
630 | } | 750 | } |
631 | } | 751 | } |
632 | 752 | ||
@@ -649,13 +769,44 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
649 | snd_soc_dapm_stream_event(rtd, substream->stream, | 769 | snd_soc_dapm_stream_event(rtd, substream->stream, |
650 | SND_SOC_DAPM_STREAM_START); | 770 | SND_SOC_DAPM_STREAM_START); |
651 | 771 | ||
652 | snd_soc_dai_digital_mute(codec_dai, 0, substream->stream); | 772 | for (i = 0; i < rtd->num_codecs; i++) |
773 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, | ||
774 | substream->stream); | ||
653 | 775 | ||
654 | out: | 776 | out: |
655 | mutex_unlock(&rtd->pcm_mutex); | 777 | mutex_unlock(&rtd->pcm_mutex); |
656 | return ret; | 778 | return ret; |
657 | } | 779 | } |
658 | 780 | ||
781 | static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, | ||
782 | unsigned int mask) | ||
783 | { | ||
784 | struct snd_interval *interval; | ||
785 | int channels = hweight_long(mask); | ||
786 | |||
787 | interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
788 | interval->min = channels; | ||
789 | interval->max = channels; | ||
790 | } | ||
791 | |||
792 | int soc_dai_hw_params(struct snd_pcm_substream *substream, | ||
793 | struct snd_pcm_hw_params *params, | ||
794 | struct snd_soc_dai *dai) | ||
795 | { | ||
796 | int ret; | ||
797 | |||
798 | if (dai->driver->ops && dai->driver->ops->hw_params) { | ||
799 | ret = dai->driver->ops->hw_params(substream, params, dai); | ||
800 | if (ret < 0) { | ||
801 | dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", | ||
802 | dai->name, ret); | ||
803 | return ret; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
659 | /* | 810 | /* |
660 | * Called by ALSA when the hardware params are set by application. This | 811 | * Called by ALSA when the hardware params are set by application. This |
661 | * function can also be called multiple times and can allocate buffers | 812 | * function can also be called multiple times and can allocate buffers |
@@ -667,8 +818,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
667 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 818 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
668 | struct snd_soc_platform *platform = rtd->platform; | 819 | struct snd_soc_platform *platform = rtd->platform; |
669 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 820 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
670 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 821 | int i, ret = 0; |
671 | int ret = 0; | ||
672 | 822 | ||
673 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 823 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
674 | 824 | ||
@@ -685,29 +835,40 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
685 | } | 835 | } |
686 | } | 836 | } |
687 | 837 | ||
688 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) { | 838 | for (i = 0; i < rtd->num_codecs; i++) { |
689 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | 839 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
690 | if (ret < 0) { | 840 | struct snd_pcm_hw_params codec_params; |
691 | dev_err(codec_dai->dev, "ASoC: can't set %s hw params:" | 841 | |
692 | " %d\n", codec_dai->name, ret); | 842 | /* copy params for each codec */ |
843 | codec_params = *params; | ||
844 | |||
845 | /* fixup params based on TDM slot masks */ | ||
846 | if (codec_dai->tx_mask) | ||
847 | soc_pcm_codec_params_fixup(&codec_params, | ||
848 | codec_dai->tx_mask); | ||
849 | if (codec_dai->rx_mask) | ||
850 | soc_pcm_codec_params_fixup(&codec_params, | ||
851 | codec_dai->rx_mask); | ||
852 | |||
853 | ret = soc_dai_hw_params(substream, &codec_params, codec_dai); | ||
854 | if(ret < 0) | ||
693 | goto codec_err; | 855 | goto codec_err; |
694 | } | ||
695 | } | ||
696 | 856 | ||
697 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) { | 857 | codec_dai->rate = params_rate(&codec_params); |
698 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); | 858 | codec_dai->channels = params_channels(&codec_params); |
699 | if (ret < 0) { | 859 | codec_dai->sample_bits = snd_pcm_format_physical_width( |
700 | dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n", | 860 | params_format(&codec_params)); |
701 | cpu_dai->name, ret); | ||
702 | goto interface_err; | ||
703 | } | ||
704 | } | 861 | } |
705 | 862 | ||
863 | ret = soc_dai_hw_params(substream, params, cpu_dai); | ||
864 | if (ret < 0) | ||
865 | goto interface_err; | ||
866 | |||
706 | if (platform->driver->ops && platform->driver->ops->hw_params) { | 867 | if (platform->driver->ops && platform->driver->ops->hw_params) { |
707 | ret = platform->driver->ops->hw_params(substream, params); | 868 | ret = platform->driver->ops->hw_params(substream, params); |
708 | if (ret < 0) { | 869 | if (ret < 0) { |
709 | dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", | 870 | dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", |
710 | platform->name, ret); | 871 | platform->component.name, ret); |
711 | goto platform_err; | 872 | goto platform_err; |
712 | } | 873 | } |
713 | } | 874 | } |
@@ -718,11 +879,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
718 | cpu_dai->sample_bits = | 879 | cpu_dai->sample_bits = |
719 | snd_pcm_format_physical_width(params_format(params)); | 880 | snd_pcm_format_physical_width(params_format(params)); |
720 | 881 | ||
721 | codec_dai->rate = params_rate(params); | ||
722 | codec_dai->channels = params_channels(params); | ||
723 | codec_dai->sample_bits = | ||
724 | snd_pcm_format_physical_width(params_format(params)); | ||
725 | |||
726 | out: | 882 | out: |
727 | mutex_unlock(&rtd->pcm_mutex); | 883 | mutex_unlock(&rtd->pcm_mutex); |
728 | return ret; | 884 | return ret; |
@@ -732,10 +888,16 @@ platform_err: | |||
732 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 888 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
733 | 889 | ||
734 | interface_err: | 890 | interface_err: |
735 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | 891 | i = rtd->num_codecs; |
736 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
737 | 892 | ||
738 | codec_err: | 893 | codec_err: |
894 | while (--i >= 0) { | ||
895 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | ||
896 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | ||
897 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
898 | codec_dai->rate = 0; | ||
899 | } | ||
900 | |||
739 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 901 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
740 | rtd->dai_link->ops->hw_free(substream); | 902 | rtd->dai_link->ops->hw_free(substream); |
741 | 903 | ||
@@ -751,8 +913,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
751 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 913 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
752 | struct snd_soc_platform *platform = rtd->platform; | 914 | struct snd_soc_platform *platform = rtd->platform; |
753 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 915 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
754 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 916 | struct snd_soc_dai *codec_dai; |
755 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 917 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
918 | int i; | ||
756 | 919 | ||
757 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 920 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
758 | 921 | ||
@@ -763,16 +926,22 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
763 | cpu_dai->sample_bits = 0; | 926 | cpu_dai->sample_bits = 0; |
764 | } | 927 | } |
765 | 928 | ||
766 | if (codec_dai->active == 1) { | 929 | for (i = 0; i < rtd->num_codecs; i++) { |
767 | codec_dai->rate = 0; | 930 | codec_dai = rtd->codec_dais[i]; |
768 | codec_dai->channels = 0; | 931 | if (codec_dai->active == 1) { |
769 | codec_dai->sample_bits = 0; | 932 | codec_dai->rate = 0; |
933 | codec_dai->channels = 0; | ||
934 | codec_dai->sample_bits = 0; | ||
935 | } | ||
770 | } | 936 | } |
771 | 937 | ||
772 | /* apply codec digital mute */ | 938 | /* apply codec digital mute */ |
773 | if ((playback && codec_dai->playback_active == 1) || | 939 | for (i = 0; i < rtd->num_codecs; i++) { |
774 | (!playback && codec_dai->capture_active == 1)) | 940 | if ((playback && rtd->codec_dais[i]->playback_active == 1) || |
775 | snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); | 941 | (!playback && rtd->codec_dais[i]->capture_active == 1)) |
942 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, | ||
943 | substream->stream); | ||
944 | } | ||
776 | 945 | ||
777 | /* free any machine hw params */ | 946 | /* free any machine hw params */ |
778 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 947 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
@@ -783,8 +952,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
783 | platform->driver->ops->hw_free(substream); | 952 | platform->driver->ops->hw_free(substream); |
784 | 953 | ||
785 | /* now free hw params for the DAIs */ | 954 | /* now free hw params for the DAIs */ |
786 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | 955 | for (i = 0; i < rtd->num_codecs; i++) { |
787 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 956 | codec_dai = rtd->codec_dais[i]; |
957 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | ||
958 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
959 | } | ||
788 | 960 | ||
789 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) | 961 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) |
790 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 962 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
@@ -798,13 +970,17 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
798 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 970 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
799 | struct snd_soc_platform *platform = rtd->platform; | 971 | struct snd_soc_platform *platform = rtd->platform; |
800 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 972 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
801 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 973 | struct snd_soc_dai *codec_dai; |
802 | int ret; | 974 | int i, ret; |
803 | 975 | ||
804 | if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { | 976 | for (i = 0; i < rtd->num_codecs; i++) { |
805 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | 977 | codec_dai = rtd->codec_dais[i]; |
806 | if (ret < 0) | 978 | if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { |
807 | return ret; | 979 | ret = codec_dai->driver->ops->trigger(substream, |
980 | cmd, codec_dai); | ||
981 | if (ret < 0) | ||
982 | return ret; | ||
983 | } | ||
808 | } | 984 | } |
809 | 985 | ||
810 | if (platform->driver->ops && platform->driver->ops->trigger) { | 986 | if (platform->driver->ops && platform->driver->ops->trigger) { |
@@ -834,14 +1010,18 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, | |||
834 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1010 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
835 | struct snd_soc_platform *platform = rtd->platform; | 1011 | struct snd_soc_platform *platform = rtd->platform; |
836 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1012 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
837 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1013 | struct snd_soc_dai *codec_dai; |
838 | int ret; | 1014 | int i, ret; |
839 | 1015 | ||
840 | if (codec_dai->driver->ops && | 1016 | for (i = 0; i < rtd->num_codecs; i++) { |
841 | codec_dai->driver->ops->bespoke_trigger) { | 1017 | codec_dai = rtd->codec_dais[i]; |
842 | ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); | 1018 | if (codec_dai->driver->ops && |
843 | if (ret < 0) | 1019 | codec_dai->driver->ops->bespoke_trigger) { |
844 | return ret; | 1020 | ret = codec_dai->driver->ops->bespoke_trigger(substream, |
1021 | cmd, codec_dai); | ||
1022 | if (ret < 0) | ||
1023 | return ret; | ||
1024 | } | ||
845 | } | 1025 | } |
846 | 1026 | ||
847 | if (platform->driver->bespoke_trigger) { | 1027 | if (platform->driver->bespoke_trigger) { |
@@ -867,10 +1047,12 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
867 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1047 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
868 | struct snd_soc_platform *platform = rtd->platform; | 1048 | struct snd_soc_platform *platform = rtd->platform; |
869 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1049 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
870 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1050 | struct snd_soc_dai *codec_dai; |
871 | struct snd_pcm_runtime *runtime = substream->runtime; | 1051 | struct snd_pcm_runtime *runtime = substream->runtime; |
872 | snd_pcm_uframes_t offset = 0; | 1052 | snd_pcm_uframes_t offset = 0; |
873 | snd_pcm_sframes_t delay = 0; | 1053 | snd_pcm_sframes_t delay = 0; |
1054 | snd_pcm_sframes_t codec_delay = 0; | ||
1055 | int i; | ||
874 | 1056 | ||
875 | if (platform->driver->ops && platform->driver->ops->pointer) | 1057 | if (platform->driver->ops && platform->driver->ops->pointer) |
876 | offset = platform->driver->ops->pointer(substream); | 1058 | offset = platform->driver->ops->pointer(substream); |
@@ -878,11 +1060,21 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
878 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) | 1060 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) |
879 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | 1061 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); |
880 | 1062 | ||
881 | if (codec_dai->driver->ops && codec_dai->driver->ops->delay) | 1063 | for (i = 0; i < rtd->num_codecs; i++) { |
882 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | 1064 | codec_dai = rtd->codec_dais[i]; |
1065 | if (codec_dai->driver->ops && codec_dai->driver->ops->delay) | ||
1066 | codec_delay = max(codec_delay, | ||
1067 | codec_dai->driver->ops->delay(substream, | ||
1068 | codec_dai)); | ||
1069 | } | ||
1070 | delay += codec_delay; | ||
883 | 1071 | ||
1072 | /* | ||
1073 | * None of the existing platform drivers implement delay(), so | ||
1074 | * for now the codec_dai of first multicodec entry is used | ||
1075 | */ | ||
884 | if (platform->driver->delay) | 1076 | if (platform->driver->delay) |
885 | delay += platform->driver->delay(substream, codec_dai); | 1077 | delay += platform->driver->delay(substream, rtd->codec_dais[0]); |
886 | 1078 | ||
887 | runtime->delay = delay; | 1079 | runtime->delay = delay; |
888 | 1080 | ||
@@ -985,7 +1177,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
985 | struct snd_soc_dapm_widget *widget, int stream) | 1177 | struct snd_soc_dapm_widget *widget, int stream) |
986 | { | 1178 | { |
987 | struct snd_soc_pcm_runtime *be; | 1179 | struct snd_soc_pcm_runtime *be; |
988 | int i; | 1180 | int i, j; |
989 | 1181 | ||
990 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1182 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
991 | for (i = 0; i < card->num_links; i++) { | 1183 | for (i = 0; i < card->num_links; i++) { |
@@ -994,9 +1186,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
994 | if (!be->dai_link->no_pcm) | 1186 | if (!be->dai_link->no_pcm) |
995 | continue; | 1187 | continue; |
996 | 1188 | ||
997 | if (be->cpu_dai->playback_widget == widget || | 1189 | if (be->cpu_dai->playback_widget == widget) |
998 | be->codec_dai->playback_widget == widget) | ||
999 | return be; | 1190 | return be; |
1191 | |||
1192 | for (j = 0; j < be->num_codecs; j++) { | ||
1193 | struct snd_soc_dai *dai = be->codec_dais[j]; | ||
1194 | if (dai->playback_widget == widget) | ||
1195 | return be; | ||
1196 | } | ||
1000 | } | 1197 | } |
1001 | } else { | 1198 | } else { |
1002 | 1199 | ||
@@ -1006,9 +1203,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
1006 | if (!be->dai_link->no_pcm) | 1203 | if (!be->dai_link->no_pcm) |
1007 | continue; | 1204 | continue; |
1008 | 1205 | ||
1009 | if (be->cpu_dai->capture_widget == widget || | 1206 | if (be->cpu_dai->capture_widget == widget) |
1010 | be->codec_dai->capture_widget == widget) | ||
1011 | return be; | 1207 | return be; |
1208 | |||
1209 | for (j = 0; j < be->num_codecs; j++) { | ||
1210 | struct snd_soc_dai *dai = be->codec_dais[j]; | ||
1211 | if (dai->capture_widget == widget) | ||
1212 | return be; | ||
1213 | } | ||
1012 | } | 1214 | } |
1013 | } | 1215 | } |
1014 | 1216 | ||
@@ -1071,6 +1273,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | |||
1071 | 1273 | ||
1072 | /* Destroy any old FE <--> BE connections */ | 1274 | /* Destroy any old FE <--> BE connections */ |
1073 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1275 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1276 | unsigned int i; | ||
1074 | 1277 | ||
1075 | /* is there a valid CPU DAI widget for this BE */ | 1278 | /* is there a valid CPU DAI widget for this BE */ |
1076 | widget = dai_get_widget(dpcm->be->cpu_dai, stream); | 1279 | widget = dai_get_widget(dpcm->be->cpu_dai, stream); |
@@ -1080,11 +1283,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | |||
1080 | continue; | 1283 | continue; |
1081 | 1284 | ||
1082 | /* is there a valid CODEC DAI widget for this BE */ | 1285 | /* is there a valid CODEC DAI widget for this BE */ |
1083 | widget = dai_get_widget(dpcm->be->codec_dai, stream); | 1286 | for (i = 0; i < dpcm->be->num_codecs; i++) { |
1287 | struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; | ||
1288 | widget = dai_get_widget(dai, stream); | ||
1084 | 1289 | ||
1085 | /* prune the BE if it's no longer in our active list */ | 1290 | /* prune the BE if it's no longer in our active list */ |
1086 | if (widget && widget_in_list(list, widget)) | 1291 | if (widget && widget_in_list(list, widget)) |
1087 | continue; | 1292 | continue; |
1293 | } | ||
1088 | 1294 | ||
1089 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", | 1295 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", |
1090 | stream ? "capture" : "playback", | 1296 | stream ? "capture" : "playback", |
@@ -2069,6 +2275,7 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
2069 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); | 2275 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); |
2070 | } | 2276 | } |
2071 | 2277 | ||
2278 | dpcm_path_put(&list); | ||
2072 | capture: | 2279 | capture: |
2073 | /* skip if FE doesn't have capture capability */ | 2280 | /* skip if FE doesn't have capture capability */ |
2074 | if (!fe->cpu_dai->driver->capture.channels_min) | 2281 | if (!fe->cpu_dai->driver->capture.channels_min) |
@@ -2113,16 +2320,22 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) | |||
2113 | list_for_each_entry(dpcm, clients, list_be) { | 2320 | list_for_each_entry(dpcm, clients, list_be) { |
2114 | 2321 | ||
2115 | struct snd_soc_pcm_runtime *be = dpcm->be; | 2322 | struct snd_soc_pcm_runtime *be = dpcm->be; |
2116 | struct snd_soc_dai *dai = be->codec_dai; | 2323 | int i; |
2117 | struct snd_soc_dai_driver *drv = dai->driver; | ||
2118 | 2324 | ||
2119 | if (be->dai_link->ignore_suspend) | 2325 | if (be->dai_link->ignore_suspend) |
2120 | continue; | 2326 | continue; |
2121 | 2327 | ||
2122 | dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name); | 2328 | for (i = 0; i < be->num_codecs; i++) { |
2329 | struct snd_soc_dai *dai = be->codec_dais[i]; | ||
2330 | struct snd_soc_dai_driver *drv = dai->driver; | ||
2331 | |||
2332 | dev_dbg(be->dev, "ASoC: BE digital mute %s\n", | ||
2333 | be->dai_link->name); | ||
2123 | 2334 | ||
2124 | if (drv->ops && drv->ops->digital_mute && dai->playback_active) | 2335 | if (drv->ops && drv->ops->digital_mute && |
2125 | drv->ops->digital_mute(dai, mute); | 2336 | dai->playback_active) |
2337 | drv->ops->digital_mute(dai, mute); | ||
2338 | } | ||
2126 | } | 2339 | } |
2127 | 2340 | ||
2128 | return 0; | 2341 | return 0; |
@@ -2187,22 +2400,27 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) | |||
2187 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 2400 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
2188 | { | 2401 | { |
2189 | struct snd_soc_platform *platform = rtd->platform; | 2402 | struct snd_soc_platform *platform = rtd->platform; |
2190 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 2403 | struct snd_soc_dai *codec_dai; |
2191 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 2404 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2192 | struct snd_pcm *pcm; | 2405 | struct snd_pcm *pcm; |
2193 | char new_name[64]; | 2406 | char new_name[64]; |
2194 | int ret = 0, playback = 0, capture = 0; | 2407 | int ret = 0, playback = 0, capture = 0; |
2408 | int i; | ||
2195 | 2409 | ||
2196 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { | 2410 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { |
2197 | playback = rtd->dai_link->dpcm_playback; | 2411 | playback = rtd->dai_link->dpcm_playback; |
2198 | capture = rtd->dai_link->dpcm_capture; | 2412 | capture = rtd->dai_link->dpcm_capture; |
2199 | } else { | 2413 | } else { |
2200 | if (codec_dai->driver->playback.channels_min && | 2414 | for (i = 0; i < rtd->num_codecs; i++) { |
2201 | cpu_dai->driver->playback.channels_min) | 2415 | codec_dai = rtd->codec_dais[i]; |
2202 | playback = 1; | 2416 | if (codec_dai->driver->playback.channels_min) |
2203 | if (codec_dai->driver->capture.channels_min && | 2417 | playback = 1; |
2204 | cpu_dai->driver->capture.channels_min) | 2418 | if (codec_dai->driver->capture.channels_min) |
2205 | capture = 1; | 2419 | capture = 1; |
2420 | } | ||
2421 | |||
2422 | capture = capture && cpu_dai->driver->capture.channels_min; | ||
2423 | playback = playback && cpu_dai->driver->playback.channels_min; | ||
2206 | } | 2424 | } |
2207 | 2425 | ||
2208 | if (rtd->dai_link->playback_only) { | 2426 | if (rtd->dai_link->playback_only) { |
@@ -2228,7 +2446,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2228 | rtd->dai_link->stream_name); | 2446 | rtd->dai_link->stream_name); |
2229 | else | 2447 | else |
2230 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 2448 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
2231 | rtd->dai_link->stream_name, codec_dai->name, num); | 2449 | rtd->dai_link->stream_name, |
2450 | (rtd->num_codecs > 1) ? | ||
2451 | "multicodec" : rtd->codec_dai->name, num); | ||
2232 | 2452 | ||
2233 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, | 2453 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, |
2234 | capture, &pcm); | 2454 | capture, &pcm); |
@@ -2301,8 +2521,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2301 | 2521 | ||
2302 | pcm->private_free = platform->driver->pcm_free; | 2522 | pcm->private_free = platform->driver->pcm_free; |
2303 | out: | 2523 | out: |
2304 | dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name, | 2524 | dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", |
2305 | cpu_dai->name); | 2525 | (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, |
2526 | cpu_dai->name); | ||
2306 | return ret; | 2527 | return ret; |
2307 | } | 2528 | } |
2308 | 2529 | ||
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 02734bd4f09b..a83aff09dce2 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c | |||
@@ -41,8 +41,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, | |||
41 | { | 41 | { |
42 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 42 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
43 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 43 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
44 | struct snd_soc_codec *codec = codec_dai->codec; | 44 | struct snd_soc_card *card = rtd->card; |
45 | struct snd_soc_card *card = codec->card; | ||
46 | struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); | 45 | struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); |
47 | int srate, mclk; | 46 | int srate, mclk; |
48 | int err; | 47 | int err; |
@@ -105,7 +104,7 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
105 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 104 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
106 | struct snd_soc_codec *codec = codec_dai->codec; | 105 | struct snd_soc_codec *codec = codec_dai->codec; |
107 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 106 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
108 | struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card); | 107 | struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card); |
109 | 108 | ||
110 | snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, | 109 | snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, |
111 | &tegra_alc5632_hs_jack); | 110 | &tegra_alc5632_hs_jack); |
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index ce73e1f62c4b..b86cd9936ef1 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c | |||
@@ -49,8 +49,7 @@ static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, | |||
49 | { | 49 | { |
50 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 50 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
51 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 51 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
52 | struct snd_soc_codec *codec = codec_dai->codec; | 52 | struct snd_soc_card *card = rtd->card; |
53 | struct snd_soc_card *card = codec->card; | ||
54 | struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); | 53 | struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); |
55 | int srate, mclk; | 54 | int srate, mclk; |
56 | int err; | 55 | int err; |
@@ -127,7 +126,7 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
127 | { | 126 | { |
128 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 127 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
129 | struct snd_soc_codec *codec = codec_dai->codec; | 128 | struct snd_soc_codec *codec = codec_dai->codec; |
130 | struct tegra_max98090 *machine = snd_soc_card_get_drvdata(codec->card); | 129 | struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card); |
131 | 130 | ||
132 | if (gpio_is_valid(machine->gpio_hp_det)) { | 131 | if (gpio_is_valid(machine->gpio_hp_det)) { |
133 | snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, | 132 | snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, |
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 4feb16a99e02..a6898831fb9f 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c | |||
@@ -51,8 +51,7 @@ static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, | |||
51 | { | 51 | { |
52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
53 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 53 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
54 | struct snd_soc_codec *codec = codec_dai->codec; | 54 | struct snd_soc_card *card = rtd->card; |
55 | struct snd_soc_card *card = codec->card; | ||
56 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | 55 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); |
57 | int srate, mclk; | 56 | int srate, mclk; |
58 | int err; | 57 | int err; |
@@ -110,7 +109,7 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
110 | { | 109 | { |
111 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 110 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
112 | struct snd_soc_codec *codec = codec_dai->codec; | 111 | struct snd_soc_codec *codec = codec_dai->codec; |
113 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(codec->card); | 112 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card); |
114 | 113 | ||
115 | snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, | 114 | snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, |
116 | &tegra_rt5640_hp_jack); | 115 | &tegra_rt5640_hp_jack); |
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index 8e774d1a243c..769e28f6642e 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c | |||
@@ -55,8 +55,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, | |||
55 | { | 55 | { |
56 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 56 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
57 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 57 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
58 | struct snd_soc_codec *codec = codec_dai->codec; | 58 | struct snd_soc_card *card = rtd->card; |
59 | struct snd_soc_card *card = codec->card; | ||
60 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | 59 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); |
61 | int srate, mclk; | 60 | int srate, mclk; |
62 | int err; | 61 | int err; |
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 0939661df60b..86e05e938585 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c | |||
@@ -60,8 +60,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | |||
60 | { | 60 | { |
61 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 61 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
62 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 62 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
63 | struct snd_soc_codec *codec = codec_dai->codec; | 63 | struct snd_soc_card *card = rtd->card; |
64 | struct snd_soc_card *card = codec->card; | ||
65 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 64 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
66 | int srate, mclk; | 65 | int srate, mclk; |
67 | int err; | 66 | int err; |
@@ -173,7 +172,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
173 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 172 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
174 | struct snd_soc_codec *codec = codec_dai->codec; | 173 | struct snd_soc_codec *codec = codec_dai->codec; |
175 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 174 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
176 | struct snd_soc_card *card = codec->card; | 175 | struct snd_soc_card *card = rtd->card; |
177 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 176 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
178 | 177 | ||
179 | if (gpio_is_valid(machine->gpio_hp_det)) { | 178 | if (gpio_is_valid(machine->gpio_hp_det)) { |
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 734bfcd21148..589d2d9b553a 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c | |||
@@ -50,8 +50,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, | |||
50 | { | 50 | { |
51 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 51 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
52 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 52 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
53 | struct snd_soc_codec *codec = codec_dai->codec; | 53 | struct snd_soc_card *card = rtd->card; |
54 | struct snd_soc_card *card = codec->card; | ||
55 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); | 54 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); |
56 | int srate, mclk; | 55 | int srate, mclk; |
57 | int err; | 56 | int err; |
diff --git a/sound/usb/card.c b/sound/usb/card.c index c3b5b7dca1c3..a09e5f3519e3 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -307,6 +307,11 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
307 | 307 | ||
308 | static int snd_usb_audio_free(struct snd_usb_audio *chip) | 308 | static int snd_usb_audio_free(struct snd_usb_audio *chip) |
309 | { | 309 | { |
310 | struct list_head *p, *n; | ||
311 | |||
312 | list_for_each_safe(p, n, &chip->ep_list) | ||
313 | snd_usb_endpoint_free(p); | ||
314 | |||
310 | mutex_destroy(&chip->mutex); | 315 | mutex_destroy(&chip->mutex); |
311 | kfree(chip); | 316 | kfree(chip); |
312 | return 0; | 317 | return 0; |
@@ -585,7 +590,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
585 | struct snd_usb_audio *chip) | 590 | struct snd_usb_audio *chip) |
586 | { | 591 | { |
587 | struct snd_card *card; | 592 | struct snd_card *card; |
588 | struct list_head *p, *n; | 593 | struct list_head *p; |
589 | 594 | ||
590 | if (chip == (void *)-1L) | 595 | if (chip == (void *)-1L) |
591 | return; | 596 | return; |
@@ -598,14 +603,16 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
598 | mutex_lock(®ister_mutex); | 603 | mutex_lock(®ister_mutex); |
599 | chip->num_interfaces--; | 604 | chip->num_interfaces--; |
600 | if (chip->num_interfaces <= 0) { | 605 | if (chip->num_interfaces <= 0) { |
606 | struct snd_usb_endpoint *ep; | ||
607 | |||
601 | snd_card_disconnect(card); | 608 | snd_card_disconnect(card); |
602 | /* release the pcm resources */ | 609 | /* release the pcm resources */ |
603 | list_for_each(p, &chip->pcm_list) { | 610 | list_for_each(p, &chip->pcm_list) { |
604 | snd_usb_stream_disconnect(p); | 611 | snd_usb_stream_disconnect(p); |
605 | } | 612 | } |
606 | /* release the endpoint resources */ | 613 | /* release the endpoint resources */ |
607 | list_for_each_safe(p, n, &chip->ep_list) { | 614 | list_for_each_entry(ep, &chip->ep_list, list) { |
608 | snd_usb_endpoint_free(p); | 615 | snd_usb_endpoint_release(ep); |
609 | } | 616 | } |
610 | /* release the midi resources */ | 617 | /* release the midi resources */ |
611 | list_for_each(p, &chip->midi_list) { | 618 | list_for_each(p, &chip->midi_list) { |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 289f582c9130..114e3e7ff511 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -987,19 +987,30 @@ void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) | |||
987 | } | 987 | } |
988 | 988 | ||
989 | /** | 989 | /** |
990 | * snd_usb_endpoint_release: Tear down an snd_usb_endpoint | ||
991 | * | ||
992 | * @ep: the endpoint to release | ||
993 | * | ||
994 | * This function does not care for the endpoint's use count but will tear | ||
995 | * down all the streaming URBs immediately. | ||
996 | */ | ||
997 | void snd_usb_endpoint_release(struct snd_usb_endpoint *ep) | ||
998 | { | ||
999 | release_urbs(ep, 1); | ||
1000 | } | ||
1001 | |||
1002 | /** | ||
990 | * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint | 1003 | * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint |
991 | * | 1004 | * |
992 | * @ep: the list header of the endpoint to free | 1005 | * @ep: the list header of the endpoint to free |
993 | * | 1006 | * |
994 | * This function does not care for the endpoint's use count but will tear | 1007 | * This free all resources of the given ep. |
995 | * down all the streaming URBs immediately and free all resources. | ||
996 | */ | 1008 | */ |
997 | void snd_usb_endpoint_free(struct list_head *head) | 1009 | void snd_usb_endpoint_free(struct list_head *head) |
998 | { | 1010 | { |
999 | struct snd_usb_endpoint *ep; | 1011 | struct snd_usb_endpoint *ep; |
1000 | 1012 | ||
1001 | ep = list_entry(head, struct snd_usb_endpoint, list); | 1013 | ep = list_entry(head, struct snd_usb_endpoint, list); |
1002 | release_urbs(ep, 1); | ||
1003 | kfree(ep); | 1014 | kfree(ep); |
1004 | } | 1015 | } |
1005 | 1016 | ||
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 1c7e8ee48abc..e61ee5c356a3 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h | |||
@@ -23,6 +23,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep); | |||
23 | void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); | 23 | void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); |
24 | int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); | 24 | int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); |
25 | void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); | 25 | void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); |
26 | void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); | ||
26 | void snd_usb_endpoint_free(struct list_head *head); | 27 | void snd_usb_endpoint_free(struct list_head *head); |
27 | 28 | ||
28 | int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); | 29 | int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); |