diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2006-09-17 15:59:25 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-09-23 04:47:06 -0400 |
commit | 307192065c55dbc70159037c1e3006a9f761192b (patch) | |
tree | 462ed687281672986f54af5ac1d7abc2f2b8c999 /sound/aoa | |
parent | 43001c9515cf87935c50e84b3e27b1f3b3776b5d (diff) |
[ALSA] aoa: add locking to tas codec
Looks like I completely forgot to do this. This patch adds locking to
the tas codec so two userspace programs can't hit the controls at the
same time. Tested on my powerbook, but I obviously can't find any
problems even without it since it doesn't do SMP.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/aoa')
-rw-r--r-- | sound/aoa/codecs/snd-aoa-codec-tas.c | 96 |
1 files changed, 83 insertions, 13 deletions
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 16c0b6b0a805..2ef55a17917c 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #include <asm/prom.h> | 66 | #include <asm/prom.h> |
67 | #include <linux/delay.h> | 67 | #include <linux/delay.h> |
68 | #include <linux/module.h> | 68 | #include <linux/module.h> |
69 | #include <linux/mutex.h> | ||
70 | |||
69 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | 71 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); |
70 | MODULE_LICENSE("GPL"); | 72 | MODULE_LICENSE("GPL"); |
71 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); | 73 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); |
@@ -91,6 +93,10 @@ struct tas { | |||
91 | u8 bass, treble; | 93 | u8 bass, treble; |
92 | u8 acr; | 94 | u8 acr; |
93 | int drc_range; | 95 | int drc_range; |
96 | /* protects hardware access against concurrency from | ||
97 | * userspace when hitting controls and during | ||
98 | * codec init/suspend/resume */ | ||
99 | struct mutex mtx; | ||
94 | }; | 100 | }; |
95 | 101 | ||
96 | static int tas_reset_init(struct tas *tas); | 102 | static int tas_reset_init(struct tas *tas); |
@@ -231,8 +237,10 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol, | |||
231 | { | 237 | { |
232 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 238 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
233 | 239 | ||
240 | mutex_lock(&tas->mtx); | ||
234 | ucontrol->value.integer.value[0] = tas->cached_volume_l; | 241 | ucontrol->value.integer.value[0] = tas->cached_volume_l; |
235 | ucontrol->value.integer.value[1] = tas->cached_volume_r; | 242 | ucontrol->value.integer.value[1] = tas->cached_volume_r; |
243 | mutex_unlock(&tas->mtx); | ||
236 | return 0; | 244 | return 0; |
237 | } | 245 | } |
238 | 246 | ||
@@ -241,14 +249,18 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, | |||
241 | { | 249 | { |
242 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 250 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
243 | 251 | ||
252 | mutex_lock(&tas->mtx); | ||
244 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] | 253 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] |
245 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) | 254 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) { |
255 | mutex_unlock(&tas->mtx); | ||
246 | return 0; | 256 | return 0; |
257 | } | ||
247 | 258 | ||
248 | tas->cached_volume_l = ucontrol->value.integer.value[0]; | 259 | tas->cached_volume_l = ucontrol->value.integer.value[0]; |
249 | tas->cached_volume_r = ucontrol->value.integer.value[1]; | 260 | tas->cached_volume_r = ucontrol->value.integer.value[1]; |
250 | if (tas->hw_enabled) | 261 | if (tas->hw_enabled) |
251 | tas_set_volume(tas); | 262 | tas_set_volume(tas); |
263 | mutex_unlock(&tas->mtx); | ||
252 | return 1; | 264 | return 1; |
253 | } | 265 | } |
254 | 266 | ||
@@ -276,8 +288,10 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, | |||
276 | { | 288 | { |
277 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 289 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
278 | 290 | ||
291 | mutex_lock(&tas->mtx); | ||
279 | ucontrol->value.integer.value[0] = !tas->mute_l; | 292 | ucontrol->value.integer.value[0] = !tas->mute_l; |
280 | ucontrol->value.integer.value[1] = !tas->mute_r; | 293 | ucontrol->value.integer.value[1] = !tas->mute_r; |
294 | mutex_unlock(&tas->mtx); | ||
281 | return 0; | 295 | return 0; |
282 | } | 296 | } |
283 | 297 | ||
@@ -286,14 +300,18 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, | |||
286 | { | 300 | { |
287 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 301 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
288 | 302 | ||
303 | mutex_lock(&tas->mtx); | ||
289 | if (tas->mute_l == !ucontrol->value.integer.value[0] | 304 | if (tas->mute_l == !ucontrol->value.integer.value[0] |
290 | && tas->mute_r == !ucontrol->value.integer.value[1]) | 305 | && tas->mute_r == !ucontrol->value.integer.value[1]) { |
306 | mutex_unlock(&tas->mtx); | ||
291 | return 0; | 307 | return 0; |
308 | } | ||
292 | 309 | ||
293 | tas->mute_l = !ucontrol->value.integer.value[0]; | 310 | tas->mute_l = !ucontrol->value.integer.value[0]; |
294 | tas->mute_r = !ucontrol->value.integer.value[1]; | 311 | tas->mute_r = !ucontrol->value.integer.value[1]; |
295 | if (tas->hw_enabled) | 312 | if (tas->hw_enabled) |
296 | tas_set_volume(tas); | 313 | tas_set_volume(tas); |
314 | mutex_unlock(&tas->mtx); | ||
297 | return 1; | 315 | return 1; |
298 | } | 316 | } |
299 | 317 | ||
@@ -322,8 +340,10 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol, | |||
322 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 340 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
323 | int idx = kcontrol->private_value; | 341 | int idx = kcontrol->private_value; |
324 | 342 | ||
343 | mutex_lock(&tas->mtx); | ||
325 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; | 344 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; |
326 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; | 345 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; |
346 | mutex_unlock(&tas->mtx); | ||
327 | 347 | ||
328 | return 0; | 348 | return 0; |
329 | } | 349 | } |
@@ -334,15 +354,19 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, | |||
334 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 354 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
335 | int idx = kcontrol->private_value; | 355 | int idx = kcontrol->private_value; |
336 | 356 | ||
357 | mutex_lock(&tas->mtx); | ||
337 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] | 358 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] |
338 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) | 359 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) { |
360 | mutex_unlock(&tas->mtx); | ||
339 | return 0; | 361 | return 0; |
362 | } | ||
340 | 363 | ||
341 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; | 364 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; |
342 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; | 365 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; |
343 | 366 | ||
344 | if (tas->hw_enabled) | 367 | if (tas->hw_enabled) |
345 | tas_set_mixer(tas); | 368 | tas_set_mixer(tas); |
369 | mutex_unlock(&tas->mtx); | ||
346 | return 1; | 370 | return 1; |
347 | } | 371 | } |
348 | 372 | ||
@@ -375,7 +399,9 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol, | |||
375 | { | 399 | { |
376 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 400 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
377 | 401 | ||
402 | mutex_lock(&tas->mtx); | ||
378 | ucontrol->value.integer.value[0] = tas->drc_range; | 403 | ucontrol->value.integer.value[0] = tas->drc_range; |
404 | mutex_unlock(&tas->mtx); | ||
379 | return 0; | 405 | return 0; |
380 | } | 406 | } |
381 | 407 | ||
@@ -384,12 +410,16 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, | |||
384 | { | 410 | { |
385 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 411 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
386 | 412 | ||
387 | if (tas->drc_range == ucontrol->value.integer.value[0]) | 413 | mutex_lock(&tas->mtx); |
414 | if (tas->drc_range == ucontrol->value.integer.value[0]) { | ||
415 | mutex_unlock(&tas->mtx); | ||
388 | return 0; | 416 | return 0; |
417 | } | ||
389 | 418 | ||
390 | tas->drc_range = ucontrol->value.integer.value[0]; | 419 | tas->drc_range = ucontrol->value.integer.value[0]; |
391 | if (tas->hw_enabled) | 420 | if (tas->hw_enabled) |
392 | tas3004_set_drc(tas); | 421 | tas3004_set_drc(tas); |
422 | mutex_unlock(&tas->mtx); | ||
393 | return 1; | 423 | return 1; |
394 | } | 424 | } |
395 | 425 | ||
@@ -417,7 +447,9 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, | |||
417 | { | 447 | { |
418 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 448 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
419 | 449 | ||
450 | mutex_lock(&tas->mtx); | ||
420 | ucontrol->value.integer.value[0] = tas->drc_enabled; | 451 | ucontrol->value.integer.value[0] = tas->drc_enabled; |
452 | mutex_unlock(&tas->mtx); | ||
421 | return 0; | 453 | return 0; |
422 | } | 454 | } |
423 | 455 | ||
@@ -426,12 +458,16 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, | |||
426 | { | 458 | { |
427 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 459 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
428 | 460 | ||
429 | if (tas->drc_enabled == ucontrol->value.integer.value[0]) | 461 | mutex_lock(&tas->mtx); |
462 | if (tas->drc_enabled == ucontrol->value.integer.value[0]) { | ||
463 | mutex_unlock(&tas->mtx); | ||
430 | return 0; | 464 | return 0; |
465 | } | ||
431 | 466 | ||
432 | tas->drc_enabled = ucontrol->value.integer.value[0]; | 467 | tas->drc_enabled = ucontrol->value.integer.value[0]; |
433 | if (tas->hw_enabled) | 468 | if (tas->hw_enabled) |
434 | tas3004_set_drc(tas); | 469 | tas3004_set_drc(tas); |
470 | mutex_unlock(&tas->mtx); | ||
435 | return 1; | 471 | return 1; |
436 | } | 472 | } |
437 | 473 | ||
@@ -463,7 +499,9 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, | |||
463 | { | 499 | { |
464 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 500 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
465 | 501 | ||
502 | mutex_lock(&tas->mtx); | ||
466 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); | 503 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); |
504 | mutex_unlock(&tas->mtx); | ||
467 | return 0; | 505 | return 0; |
468 | } | 506 | } |
469 | 507 | ||
@@ -471,15 +509,21 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, | |||
471 | struct snd_ctl_elem_value *ucontrol) | 509 | struct snd_ctl_elem_value *ucontrol) |
472 | { | 510 | { |
473 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 511 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
474 | int oldacr = tas->acr; | 512 | int oldacr; |
513 | |||
514 | mutex_lock(&tas->mtx); | ||
515 | oldacr = tas->acr; | ||
475 | 516 | ||
476 | tas->acr &= ~TAS_ACR_INPUT_B; | 517 | tas->acr &= ~TAS_ACR_INPUT_B; |
477 | if (ucontrol->value.enumerated.item[0]) | 518 | if (ucontrol->value.enumerated.item[0]) |
478 | tas->acr |= TAS_ACR_INPUT_B; | 519 | tas->acr |= TAS_ACR_INPUT_B; |
479 | if (oldacr == tas->acr) | 520 | if (oldacr == tas->acr) { |
521 | mutex_unlock(&tas->mtx); | ||
480 | return 0; | 522 | return 0; |
523 | } | ||
481 | if (tas->hw_enabled) | 524 | if (tas->hw_enabled) |
482 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | 525 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); |
526 | mutex_unlock(&tas->mtx); | ||
483 | return 1; | 527 | return 1; |
484 | } | 528 | } |
485 | 529 | ||
@@ -518,7 +562,9 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol, | |||
518 | { | 562 | { |
519 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 563 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
520 | 564 | ||
565 | mutex_lock(&tas->mtx); | ||
521 | ucontrol->value.integer.value[0] = tas->treble; | 566 | ucontrol->value.integer.value[0] = tas->treble; |
567 | mutex_unlock(&tas->mtx); | ||
522 | return 0; | 568 | return 0; |
523 | } | 569 | } |
524 | 570 | ||
@@ -527,12 +573,16 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, | |||
527 | { | 573 | { |
528 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 574 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
529 | 575 | ||
530 | if (tas->treble == ucontrol->value.integer.value[0]) | 576 | mutex_lock(&tas->mtx); |
577 | if (tas->treble == ucontrol->value.integer.value[0]) { | ||
578 | mutex_unlock(&tas->mtx); | ||
531 | return 0; | 579 | return 0; |
580 | } | ||
532 | 581 | ||
533 | tas->treble = ucontrol->value.integer.value[0]; | 582 | tas->treble = ucontrol->value.integer.value[0]; |
534 | if (tas->hw_enabled) | 583 | if (tas->hw_enabled) |
535 | tas_set_treble(tas); | 584 | tas_set_treble(tas); |
585 | mutex_unlock(&tas->mtx); | ||
536 | return 1; | 586 | return 1; |
537 | } | 587 | } |
538 | 588 | ||
@@ -560,7 +610,9 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol, | |||
560 | { | 610 | { |
561 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 611 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
562 | 612 | ||
613 | mutex_lock(&tas->mtx); | ||
563 | ucontrol->value.integer.value[0] = tas->bass; | 614 | ucontrol->value.integer.value[0] = tas->bass; |
615 | mutex_unlock(&tas->mtx); | ||
564 | return 0; | 616 | return 0; |
565 | } | 617 | } |
566 | 618 | ||
@@ -569,12 +621,16 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, | |||
569 | { | 621 | { |
570 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 622 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
571 | 623 | ||
572 | if (tas->bass == ucontrol->value.integer.value[0]) | 624 | mutex_lock(&tas->mtx); |
625 | if (tas->bass == ucontrol->value.integer.value[0]) { | ||
626 | mutex_unlock(&tas->mtx); | ||
573 | return 0; | 627 | return 0; |
628 | } | ||
574 | 629 | ||
575 | tas->bass = ucontrol->value.integer.value[0]; | 630 | tas->bass = ucontrol->value.integer.value[0]; |
576 | if (tas->hw_enabled) | 631 | if (tas->hw_enabled) |
577 | tas_set_bass(tas); | 632 | tas_set_bass(tas); |
633 | mutex_unlock(&tas->mtx); | ||
578 | return 1; | 634 | return 1; |
579 | } | 635 | } |
580 | 636 | ||
@@ -628,16 +684,16 @@ static int tas_reset_init(struct tas *tas) | |||
628 | 684 | ||
629 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; | 685 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; |
630 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) | 686 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) |
631 | return -ENODEV; | 687 | goto outerr; |
632 | 688 | ||
633 | tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | | 689 | tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | |
634 | TAS_ACR_B_MON_SEL_RIGHT; | 690 | TAS_ACR_B_MON_SEL_RIGHT; |
635 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | 691 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) |
636 | return -ENODEV; | 692 | goto outerr; |
637 | 693 | ||
638 | tmp = 0; | 694 | tmp = 0; |
639 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) | 695 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) |
640 | return -ENODEV; | 696 | goto outerr; |
641 | 697 | ||
642 | tas3004_set_drc(tas); | 698 | tas3004_set_drc(tas); |
643 | 699 | ||
@@ -649,9 +705,11 @@ static int tas_reset_init(struct tas *tas) | |||
649 | 705 | ||
650 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; | 706 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; |
651 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | 707 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) |
652 | return -ENODEV; | 708 | goto outerr; |
653 | 709 | ||
654 | return 0; | 710 | return 0; |
711 | outerr: | ||
712 | return -ENODEV; | ||
655 | } | 713 | } |
656 | 714 | ||
657 | static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) | 715 | static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) |
@@ -666,11 +724,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock | |||
666 | break; | 724 | break; |
667 | case CLOCK_SWITCH_SLAVE: | 725 | case CLOCK_SWITCH_SLAVE: |
668 | /* Clocks are back, re-init the codec */ | 726 | /* Clocks are back, re-init the codec */ |
727 | mutex_lock(&tas->mtx); | ||
669 | tas_reset_init(tas); | 728 | tas_reset_init(tas); |
670 | tas_set_volume(tas); | 729 | tas_set_volume(tas); |
671 | tas_set_mixer(tas); | 730 | tas_set_mixer(tas); |
672 | tas->hw_enabled = 1; | 731 | tas->hw_enabled = 1; |
673 | tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); | 732 | tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); |
733 | mutex_unlock(&tas->mtx); | ||
674 | break; | 734 | break; |
675 | default: | 735 | default: |
676 | /* doesn't happen as of now */ | 736 | /* doesn't happen as of now */ |
@@ -684,19 +744,23 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock | |||
684 | * our i2c device is suspended, and then take note of that! */ | 744 | * our i2c device is suspended, and then take note of that! */ |
685 | static int tas_suspend(struct tas *tas) | 745 | static int tas_suspend(struct tas *tas) |
686 | { | 746 | { |
747 | mutex_lock(&tas->mtx); | ||
687 | tas->hw_enabled = 0; | 748 | tas->hw_enabled = 0; |
688 | tas->acr |= TAS_ACR_ANALOG_PDOWN; | 749 | tas->acr |= TAS_ACR_ANALOG_PDOWN; |
689 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | 750 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); |
751 | mutex_unlock(&tas->mtx); | ||
690 | return 0; | 752 | return 0; |
691 | } | 753 | } |
692 | 754 | ||
693 | static int tas_resume(struct tas *tas) | 755 | static int tas_resume(struct tas *tas) |
694 | { | 756 | { |
695 | /* reset codec */ | 757 | /* reset codec */ |
758 | mutex_lock(&tas->mtx); | ||
696 | tas_reset_init(tas); | 759 | tas_reset_init(tas); |
697 | tas_set_volume(tas); | 760 | tas_set_volume(tas); |
698 | tas_set_mixer(tas); | 761 | tas_set_mixer(tas); |
699 | tas->hw_enabled = 1; | 762 | tas->hw_enabled = 1; |
763 | mutex_unlock(&tas->mtx); | ||
700 | return 0; | 764 | return 0; |
701 | } | 765 | } |
702 | 766 | ||
@@ -739,11 +803,14 @@ static int tas_init_codec(struct aoa_codec *codec) | |||
739 | return -EINVAL; | 803 | return -EINVAL; |
740 | } | 804 | } |
741 | 805 | ||
806 | mutex_lock(&tas->mtx); | ||
742 | if (tas_reset_init(tas)) { | 807 | if (tas_reset_init(tas)) { |
743 | printk(KERN_ERR PFX "tas failed to initialise\n"); | 808 | printk(KERN_ERR PFX "tas failed to initialise\n"); |
809 | mutex_unlock(&tas->mtx); | ||
744 | return -ENXIO; | 810 | return -ENXIO; |
745 | } | 811 | } |
746 | tas->hw_enabled = 1; | 812 | tas->hw_enabled = 1; |
813 | mutex_unlock(&tas->mtx); | ||
747 | 814 | ||
748 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, | 815 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, |
749 | aoa_get_card(), | 816 | aoa_get_card(), |
@@ -822,6 +889,7 @@ static int tas_create(struct i2c_adapter *adapter, | |||
822 | if (!tas) | 889 | if (!tas) |
823 | return -ENOMEM; | 890 | return -ENOMEM; |
824 | 891 | ||
892 | mutex_init(&tas->mtx); | ||
825 | tas->i2c.driver = &tas_driver; | 893 | tas->i2c.driver = &tas_driver; |
826 | tas->i2c.adapter = adapter; | 894 | tas->i2c.adapter = adapter; |
827 | tas->i2c.addr = addr; | 895 | tas->i2c.addr = addr; |
@@ -850,6 +918,7 @@ static int tas_create(struct i2c_adapter *adapter, | |||
850 | detach: | 918 | detach: |
851 | i2c_detach_client(&tas->i2c); | 919 | i2c_detach_client(&tas->i2c); |
852 | fail: | 920 | fail: |
921 | mutex_destroy(&tas->mtx); | ||
853 | kfree(tas); | 922 | kfree(tas); |
854 | return -EINVAL; | 923 | return -EINVAL; |
855 | } | 924 | } |
@@ -908,6 +977,7 @@ static int tas_i2c_detach(struct i2c_client *client) | |||
908 | /* power down codec chip */ | 977 | /* power down codec chip */ |
909 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); | 978 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); |
910 | 979 | ||
980 | mutex_destroy(&tas->mtx); | ||
911 | kfree(tas); | 981 | kfree(tas); |
912 | return 0; | 982 | return 0; |
913 | } | 983 | } |