1/* 2 * Apple Onboard Audio driver -- layout fabric 3 * 4 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 5 * 6 * GPL v2, can be found in COPYING. 7 * 8 * 9 * This fabric module looks for sound codecs 10 * based on the layout-id property in the device tree. 11 * 12 */ 13 14#include <asm/prom.h> 15#include <linux/list.h> 16#include <linux/module.h> 17#include "../aoa.h" 18#include "../soundbus/soundbus.h" 19 20MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); 21MODULE_LICENSE("GPL"); 22MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa"); 23 24#define MAX_CODECS_PER_BUS 2 25 26/* These are the connections the layout fabric 27 * knows about. It doesn't really care about the 28 * input ones, but I thought I'd separate them 29 * to give them proper names. The thing is that 30 * Apple usually will distinguish the active output 31 * by GPIOs, while the active input is set directly 32 * on the codec. Hence we here tell the codec what 33 * we think is connected. This information is hard- 34 * coded below ... */ 35#define CC_SPEAKERS (1<<0) 36#define CC_HEADPHONE (1<<1) 37#define CC_LINEOUT (1<<2) 38#define CC_DIGITALOUT (1<<3) 39#define CC_LINEIN (1<<4) 40#define CC_MICROPHONE (1<<5) 41#define CC_DIGITALIN (1<<6) 42/* pretty bogus but users complain... 43 * This is a flag saying that the LINEOUT 44 * should be renamed to HEADPHONE. 45 * be careful with input detection! */ 46#define CC_LINEOUT_LABELLED_HEADPHONE (1<<7) 47 48struct codec_connection { 49 /* CC_ flags from above */ 50 int connected; 51 /* codec dependent bit to be set in the aoa_codec.connected field. 52 * This intentionally doesn't have any generic flags because the 53 * fabric has to know the codec anyway and all codecs might have 54 * different connectors */ 55 int codec_bit; 56}; 57 58struct codec_connect_info { 59 char *name; 60 struct codec_connection *connections; 61}; 62 63#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0) 64 65struct layout { 66 unsigned int layout_id; 67 struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; 68 int flags; 69 70 /* if busname is not assigned, we use 'Master' below, 71 * so that our layout table doesn't need to be filled 72 * too much. 73 * We only assign these two if we expect to find more 74 * than one soundbus, i.e. on those machines with 75 * multiple layout-ids */ 76 char *busname; 77 int pcmid; 78}; 79 80MODULE_ALIAS("sound-layout-36"); 81MODULE_ALIAS("sound-layout-41"); 82MODULE_ALIAS("sound-layout-45"); 83MODULE_ALIAS("sound-layout-47"); 84MODULE_ALIAS("sound-layout-48"); 85MODULE_ALIAS("sound-layout-49"); 86MODULE_ALIAS("sound-layout-50"); 87MODULE_ALIAS("sound-layout-51"); 88MODULE_ALIAS("sound-layout-56"); 89MODULE_ALIAS("sound-layout-57"); 90MODULE_ALIAS("sound-layout-58"); 91MODULE_ALIAS("sound-layout-60"); 92MODULE_ALIAS("sound-layout-61"); 93MODULE_ALIAS("sound-layout-62"); 94MODULE_ALIAS("sound-layout-64"); 95MODULE_ALIAS("sound-layout-65"); 96MODULE_ALIAS("sound-layout-66"); 97MODULE_ALIAS("sound-layout-67"); 98MODULE_ALIAS("sound-layout-68"); 99MODULE_ALIAS("sound-layout-69"); 100MODULE_ALIAS("sound-layout-70"); 101MODULE_ALIAS("sound-layout-72"); 102MODULE_ALIAS("sound-layout-76"); 103MODULE_ALIAS("sound-layout-80"); 104MODULE_ALIAS("sound-layout-82"); 105MODULE_ALIAS("sound-layout-84"); 106MODULE_ALIAS("sound-layout-86"); 107MODULE_ALIAS("sound-layout-90"); 108MODULE_ALIAS("sound-layout-92"); 109MODULE_ALIAS("sound-layout-94"); 110MODULE_ALIAS("sound-layout-96"); 111MODULE_ALIAS("sound-layout-98"); 112MODULE_ALIAS("sound-layout-100"); 113 114/* onyx with all but microphone connected */ 115static struct codec_connection onyx_connections_nomic[] = { 116 { 117 .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, 118 .codec_bit = 0, 119 }, 120 { 121 .connected = CC_DIGITALOUT, 122 .codec_bit = 1, 123 }, 124 { 125 .connected = CC_LINEIN, 126 .codec_bit = 2, 127 }, 128 {} /* terminate array by .connected == 0 */ 129}; 130 131/* onyx on machines without headphone */ 132static struct codec_connection onyx_connections_noheadphones[] = { 133 { 134 .connected = CC_SPEAKERS | CC_LINEOUT | 135 CC_LINEOUT_LABELLED_HEADPHONE, 136 .codec_bit = 0, 137 }, 138 { 139 .connected = CC_DIGITALOUT, 140 .codec_bit = 1, 141 }, 142 { 143 .connected = CC_LINEIN, 144 .codec_bit = 2, 145 }, 146 { 147 .connected = CC_MICROPHONE, 148 .codec_bit = 3, 149 }, 150 {} /* terminate array by .connected == 0 */ 151}; 152 153/* onyx on machines with real line-out */ 154static struct codec_connection onyx_connections_reallineout[] = { 155 { 156 .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE, 157 .codec_bit = 0, 158 }, 159 { 160 .connected = CC_DIGITALOUT, 161 .codec_bit = 1, 162 }, 163 { 164 .connected = CC_LINEIN, 165 .codec_bit = 2, 166 }, 167 {} /* terminate array by .connected == 0 */ 168}; 169 170/* tas on machines without line out */ 171static struct codec_connection tas_connections_nolineout[] = { 172 { 173 .connected = CC_SPEAKERS | CC_HEADPHONE, 174 .codec_bit = 0, 175 }, 176 { 177 .connected = CC_LINEIN, 178 .codec_bit = 2, 179 }, 180 { 181 .connected = CC_MICROPHONE, 182 .codec_bit = 3, 183 }, 184 {} /* terminate array by .connected == 0 */ 185}; 186 187/* tas on machines with neither line out nor line in */ 188static struct codec_connection tas_connections_noline[] = { 189 { 190 .connected = CC_SPEAKERS | CC_HEADPHONE, 191 .codec_bit = 0, 192 }, 193 { 194 .connected = CC_MICROPHONE, 195 .codec_bit = 3, 196 }, 197 {} /* terminate array by .connected == 0 */ 198}; 199 200/* tas on machines without microphone */ 201static struct codec_connection tas_connections_nomic[] = { 202 { 203 .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, 204 .codec_bit = 0, 205 }, 206 { 207 .connected = CC_LINEIN, 208 .codec_bit = 2, 209 }, 210 {} /* terminate array by .connected == 0 */ 211}; 212 213/* tas on machines with everything connected */ 214static struct codec_connection tas_connections_all[] = { 215 { 216 .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, 217 .codec_bit = 0, 218 }, 219 { 220 .connected = CC_LINEIN, 221 .codec_bit = 2, 222 }, 223 { 224 .connected = CC_MICROPHONE, 225 .codec_bit = 3, 226 }, 227 {} /* terminate array by .connected == 0 */ 228}; 229 230static struct codec_connection toonie_connections[] = { 231 { 232 .connected = CC_SPEAKERS | CC_HEADPHONE, 233 .codec_bit = 0, 234 }, 235 {} /* terminate array by .connected == 0 */ 236}; 237 238static struct codec_connection topaz_input[] = { 239 { 240 .connected = CC_DIGITALIN, 241 .codec_bit = 0, 242 }, 243 {} /* terminate array by .connected == 0 */ 244}; 245 246static struct codec_connection topaz_output[] = { 247 { 248 .connected = CC_DIGITALOUT, 249 .codec_bit = 1, 250 }, 251 {} /* terminate array by .connected == 0 */ 252}; 253 254static struct codec_connection topaz_inout[] = { 255 { 256 .connected = CC_DIGITALIN, 257 .codec_bit = 0, 258 }, 259 { 260 .connected = CC_DIGITALOUT, 261 .codec_bit = 1, 262 }, 263 {} /* terminate array by .connected == 0 */ 264}; 265 266static struct layout layouts[] = { 267 /* last PowerBooks (15" Oct 2005) */ 268 { .layout_id = 82, 269 .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, 270 .codecs[0] = { 271 .name = "onyx", 272 .connections = onyx_connections_noheadphones, 273 }, 274 .codecs[1] = { 275 .name = "topaz", 276 .connections = topaz_input, 277 }, 278 }, 279 /* PowerMac9,1 */ 280 { .layout_id = 60, 281 .codecs[0] = { 282 .name = "onyx", 283 .connections = onyx_connections_reallineout, 284 }, 285 }, 286 /* PowerMac9,1 */ 287 { .layout_id = 61, 288 .codecs[0] = { 289 .name = "topaz", 290 .connections = topaz_input, 291 }, 292 }, 293 /* PowerBook5,7 */ 294 { .layout_id = 64, 295 .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, 296 .codecs[0] = { 297 .name = "onyx", 298 .connections = onyx_connections_noheadphones, 299 }, 300 }, 301 /* PowerBook5,7 */ 302 { .layout_id = 65, 303 .codecs[0] = { 304 .name = "topaz", 305 .connections = topaz_input, 306 }, 307 }, 308 /* PowerBook5,9 [17" Oct 2005] */ 309 { .layout_id = 84, 310 .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, 311 .codecs[0] = { 312 .name = "onyx", 313 .connections = onyx_connections_noheadphones, 314 }, 315 .codecs[1] = { 316 .name = "topaz", 317 .connections = topaz_input, 318 }, 319 }, 320 /* PowerMac8,1 */ 321 { .layout_id = 45, 322 .codecs[0] = { 323 .name = "onyx", 324 .connections = onyx_connections_noheadphones, 325 }, 326 .codecs[1] = { 327 .name = "topaz", 328 .connections = topaz_input, 329 }, 330 }, 331 /* Quad PowerMac (analog in, analog/digital out) */ 332 { .layout_id = 68, 333 .codecs[0] = { 334 .name = "onyx", 335 .connections = onyx_connections_nomic, 336 }, 337 }, 338 /* Quad PowerMac (digital in) */ 339 { .layout_id = 69, 340 .codecs[0] = { 341 .name = "topaz", 342 .connections = topaz_input, 343 }, 344 .busname = "digital in", .pcmid = 1 }, 345 /* Early 2005 PowerBook (PowerBook 5,6) */ 346 { .layout_id = 70, 347 .codecs[0] = { 348 .name = "tas", 349 .connections = tas_connections_nolineout, 350 }, 351 }, 352 /* PowerBook 5,4 */ 353 { .layout_id = 51, 354 .codecs[0] = { 355 .name = "tas", 356 .connections = tas_connections_nolineout, 357 }, 358 }, 359 /* PowerBook6,7 */ 360 { .layout_id = 80, 361 .codecs[0] = { 362 .name = "tas", 363 .connections = tas_connections_noline, 364 }, 365 }, 366 /* PowerBook6,8 */ 367 { .layout_id = 72, 368 .codecs[0] = { 369 .name = "tas", 370 .connections = tas_connections_nolineout, 371 }, 372 }, 373 /* PowerMac8,2 */ 374 { .layout_id = 86, 375 .codecs[0] = { 376 .name = "onyx", 377 .connections = onyx_connections_nomic, 378 }, 379 .codecs[1] = { 380 .name = "topaz", 381 .connections = topaz_input, 382 }, 383 }, 384 /* PowerBook6,7 */ 385 { .layout_id = 92, 386 .codecs[0] = { 387 .name = "tas", 388 .connections = tas_connections_nolineout, 389 }, 390 }, 391 /* PowerMac10,1 (Mac Mini) */ 392 { .layout_id = 58, 393 .codecs[0] = { 394 .name = "toonie", 395 .connections = toonie_connections, 396 }, 397 }, 398 { 399 .layout_id = 96, 400 .codecs[0] = { 401 .name = "onyx", 402 .connections = onyx_connections_noheadphones, 403 }, 404 }, 405 /* unknown, untested, but this comes from Apple */ 406 { .layout_id = 41, 407 .codecs[0] = { 408 .name = "tas", 409 .connections = tas_connections_all, 410 }, 411 }, 412 { .layout_id = 36, 413 .codecs[0] = { 414 .name = "tas", 415 .connections = tas_connections_nomic, 416 }, 417 .codecs[1] = { 418 .name = "topaz", 419 .connections = topaz_inout, 420 }, 421 }, 422 { .layout_id = 47, 423 .codecs[0] = { 424 .name = "onyx", 425 .connections = onyx_connections_noheadphones, 426 }, 427 }, 428 { .layout_id = 48, 429 .codecs[0] = { 430 .name = "topaz", 431 .connections = topaz_input, 432 }, 433 }, 434 { .layout_id = 49, 435 .codecs[0] = { 436 .name = "onyx", 437 .connections = onyx_connections_nomic, 438 }, 439 }, 440 { .layout_id = 50, 441 .codecs[0] = { 442 .name = "topaz", 443 .connections = topaz_input, 444 }, 445 }, 446 { .layout_id = 56, 447 .codecs[0] = { 448 .name = "onyx", 449 .connections = onyx_connections_noheadphones, 450 }, 451 }, 452 { .layout_id = 57, 453 .codecs[0] = { 454 .name = "topaz", 455 .connections = topaz_input, 456 }, 457 }, 458 { .layout_id = 62, 459 .codecs[0] = { 460 .name = "onyx", 461 .connections = onyx_connections_noheadphones, 462 }, 463 .codecs[1] = { 464 .name = "topaz", 465 .connections = topaz_output, 466 }, 467 }, 468 { .layout_id = 66, 469 .codecs[0] = { 470 .name = "onyx", 471 .connections = onyx_connections_noheadphones, 472 }, 473 }, 474 { .layout_id = 67, 475 .codecs[0] = { 476 .name = "topaz", 477 .connections = topaz_input, 478 }, 479 }, 480 { .layout_id = 76, 481 .codecs[0] = { 482 .name = "tas", 483 .connections = tas_connections_nomic, 484 }, 485 .codecs[1] = { 486 .name = "topaz", 487 .connections = topaz_inout, 488 }, 489 }, 490 { .layout_id = 90, 491 .codecs[0] = { 492 .name = "tas", 493 .connections = tas_connections_noline, 494 }, 495 }, 496 { .layout_id = 94, 497 .codecs[0] = { 498 .name = "onyx", 499 /* but it has an external mic?? how to select? */ 500 .connections = onyx_connections_noheadphones, 501 }, 502 }, 503 { .layout_id = 98, 504 .codecs[0] = { 505 .name = "toonie", 506 .connections = toonie_connections, 507 }, 508 }, 509 { .layout_id = 100, 510 .codecs[0] = { 511 .name = "topaz", 512 .connections = topaz_input, 513 }, 514 .codecs[1] = { 515 .name = "onyx", 516 .connections = onyx_connections_noheadphones, 517 }, 518 }, 519 {} 520}; 521 522static struct layout *find_layout_by_id(unsigned int id) 523{ 524 struct layout *l; 525 526 l = layouts; 527 while (l->layout_id) { 528 if (l->layout_id == id) 529 return l; 530 l++; 531 } 532 return NULL; 533} 534 535static void use_layout(struct layout *l) 536{ 537 int i; 538 539 for (i=0; i<MAX_CODECS_PER_BUS; i++) { 540 if (l->codecs[i].name) { 541 request_module("snd-aoa-codec-%s", l->codecs[i].name); 542 } 543 } 544 /* now we wait for the codecs to call us back */ 545} 546 547struct layout_dev; 548 549struct layout_dev_ptr { 550 struct layout_dev *ptr; 551}; 552 553struct layout_dev { 554 struct list_head list; 555 struct soundbus_dev *sdev; 556 struct device_node *sound; 557 struct aoa_codec *codecs[MAX_CODECS_PER_BUS]; 558 struct layout *layout; 559 struct gpio_runtime gpio; 560 561 /* we need these for headphone/lineout detection */ 562 struct snd_kcontrol *headphone_ctrl; 563 struct snd_kcontrol *lineout_ctrl; 564 struct snd_kcontrol *speaker_ctrl; 565 struct snd_kcontrol *headphone_detected_ctrl; 566 struct snd_kcontrol *lineout_detected_ctrl; 567 568 struct layout_dev_ptr selfptr_headphone; 569 struct layout_dev_ptr selfptr_lineout; 570 571 u32 have_lineout_detect:1, 572 have_headphone_detect:1, 573 switch_on_headphone:1, 574 switch_on_lineout:1; 575}; 576 577static LIST_HEAD(layouts_list); 578static int layouts_list_items; 579/* this can go away but only if we allow multiple cards, 580 * make the fabric handle all the card stuff, etc... */ 581static struct layout_dev *layout_device; 582 583static int control_info(struct snd_kcontrol *kcontrol, 584 struct snd_ctl_elem_info *uinfo) 585{ 586 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 587 uinfo->count = 1; 588 uinfo->value.integer.min = 0; 589 uinfo->value.integer.max = 1; 590 return 0; 591} 592 593#define AMP_CONTROL(n, description) \ 594static int n##_control_get(struct snd_kcontrol *kcontrol, \ 595 struct snd_ctl_elem_value *ucontrol) \ 596{ \ 597 struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ 598 if (gpio->methods && gpio->methods->get_##n) \ 599 ucontrol->value.integer.value[0] = \ 600 gpio->methods->get_##n(gpio); \ 601 return 0; \ 602} \ 603static int n##_control_put(struct snd_kcontrol *kcontrol, \ 604 struct snd_ctl_elem_value *ucontrol) \ 605{ \ 606 struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ 607 if (gpio->methods && gpio->methods->get_##n) \ 608 gpio->methods->set_##n(gpio, \ 609 ucontrol->value.integer.value[0]); \ 610 return 1; \ 611} \ 612static struct snd_kcontrol_new n##_ctl = { \ 613 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 614 .name = description, \ 615 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 616 .info = control_info, \ 617 .get = n##_control_get, \ 618 .put = n##_control_put, \ 619} 620 621AMP_CONTROL(headphone, "Headphone Switch"); 622AMP_CONTROL(speakers, "Speakers Switch"); 623AMP_CONTROL(lineout, "Line-Out Switch"); 624 625static int detect_choice_get(struct snd_kcontrol *kcontrol, 626 struct snd_ctl_elem_value *ucontrol) 627{ 628 struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); 629 630 switch (kcontrol->private_value) { 631 case 0: 632 ucontrol->value.integer.value[0] = ldev->switch_on_headphone; 633 break; 634 case 1: 635 ucontrol->value.integer.value[0] = ldev->switch_on_lineout; 636 break; 637 default: 638 return -ENODEV; 639 } 640 return 0; 641} 642 643static int detect_choice_put(struct snd_kcontrol *kcontrol, 644 struct snd_ctl_elem_value *ucontrol) 645{ 646 struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); 647 648 switch (kcontrol->private_value) { 649 case 0: 650 ldev->switch_on_headphone = !!ucontrol->value.integer.value[0]; 651 break; 652 case 1: 653 ldev->switch_on_lineout = !!ucontrol->value.integer.value[0]; 654 break; 655 default: 656 return -ENODEV; 657 } 658 return 1; 659} 660 661static struct snd_kcontrol_new headphone_detect_choice = { 662 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 663 .name = "Headphone Detect Autoswitch", 664 .info = control_info, 665 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 666 .get = detect_choice_get, 667 .put = detect_choice_put, 668 .private_value = 0, 669}; 670 671static struct snd_kcontrol_new lineout_detect_choice = { 672 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 673 .name = "Line-Out Detect Autoswitch", 674 .info = control_info, 675 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 676 .get = detect_choice_get, 677 .put = detect_choice_put, 678 .private_value = 1, 679}; 680 681static int detected_get(struct snd_kcontrol *kcontrol, 682 struct snd_ctl_elem_value *ucontrol) 683{ 684 struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); 685 int v; 686 687 switch (kcontrol->private_value) { 688 case 0: 689 v = ldev->gpio.methods->get_detect(&ldev->gpio, 690 AOA_NOTIFY_HEADPHONE); 691 break; 692 case 1: 693 v = ldev->gpio.methods->get_detect(&ldev->gpio, 694 AOA_NOTIFY_LINE_OUT); 695 break; 696 default: 697 return -ENODEV; 698 } 699 ucontrol->value.integer.value[0] = v; 700 return 0; 701} 702 703static struct snd_kcontrol_new headphone_detected = { 704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 705 .name = "Headphone Detected", 706 .info = control_info, 707 .access = SNDRV_CTL_ELEM_ACCESS_READ, 708 .get = detected_get, 709 .private_value = 0, 710}; 711 712static struct snd_kcontrol_new lineout_detected = { 713 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 714 .name = "Line-Out Detected", 715 .info = control_info, 716 .access = SNDRV_CTL_ELEM_ACCESS_READ, 717 .get = detected_get, 718 .private_value = 1, 719}; 720 721static int check_codec(struct aoa_codec *codec, 722 struct layout_dev *ldev, 723 struct codec_connect_info *cci) 724{ 725 const u32 *ref; 726 char propname[32]; 727 struct codec_connection *cc; 728 729 /* if the codec has a 'codec' node, we require a reference */ 730 if (codec->node && (strcmp(codec->node->name, "codec") == 0)) { 731 snprintf(propname, sizeof(propname), 732 "platform-%s-codec-ref", codec->name); 733 ref = of_get_property(ldev->sound, propname, NULL); 734 if (!ref) { 735 printk(KERN_INFO "snd-aoa-fabric-layout: " 736 "required property %s not present\n", propname); 737 return -ENODEV; 738 } 739 if (*ref != codec->node->linux_phandle) { 740 printk(KERN_INFO "snd-aoa-fabric-layout: " 741 "%s doesn't match!\n", propname); 742 return -ENODEV; 743 } 744 } else { 745 if (layouts_list_items != 1) { 746 printk(KERN_INFO "snd-aoa-fabric-layout: " 747 "more than one soundbus, but no references.\n"); 748 return -ENODEV; 749 } 750 } 751 codec->soundbus_dev = ldev->sdev; 752 codec->gpio = &ldev->gpio; 753 754 cc = cci->connections; 755 if (!cc) 756 return -EINVAL; 757 758 printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n"); 759 760 codec->connected = 0; 761 codec->fabric_data = cc; 762 763 while (cc->connected) { 764 codec->connected |= 1<<cc->codec_bit; 765 cc++; 766 } 767 768 return 0; 769} 770 771static int layout_found_codec(struct aoa_codec *codec) 772{ 773 struct layout_dev *ldev; 774 int i; 775 776 list_for_each_entry(ldev, &layouts_list, list) { 777 for (i=0; i<MAX_CODECS_PER_BUS; i++) { 778 if (!ldev->layout->codecs[i].name) 779 continue; 780 if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) { 781 if (check_codec(codec, 782 ldev, 783 &ldev->layout->codecs[i]) == 0) 784 return 0; 785 } 786 } 787 } 788 return -ENODEV; 789} 790 791static void layout_remove_codec(struct aoa_codec *codec) 792{ 793 int i; 794 /* here remove the codec from the layout dev's 795 * codec reference */ 796 797 codec->soundbus_dev = NULL; 798 codec->gpio = NULL; 799 for (i=0; i<MAX_CODECS_PER_BUS; i++) { 800 } 801} 802 803static void layout_notify(void *data) 804{ 805 struct layout_dev_ptr *dptr = data; 806 struct layout_dev *ldev; 807 int v, update; 808 struct snd_kcontrol *detected, *c; 809 struct snd_card *card = aoa_get_card(); 810 811 ldev = dptr->ptr; 812 if (data == &ldev->selfptr_headphone) { 813 v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE); 814 detected = ldev->headphone_detected_ctrl; 815 update = ldev->switch_on_headphone; 816 if (update) { 817 ldev->gpio.methods->set_speakers(&ldev->gpio, !v); 818 ldev->gpio.methods->set_headphone(&ldev->gpio, v); 819 ldev->gpio.methods->set_lineout(&ldev->gpio, 0); 820 } 821 } else if (data == &ldev->selfptr_lineout) { 822 v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT); 823 detected = ldev->lineout_detected_ctrl; 824 update = ldev->switch_on_lineout; 825 if (update) { 826 ldev->gpio.methods->set_speakers(&ldev->gpio, !v); 827 ldev->gpio.methods->set_headphone(&ldev->gpio, 0); 828 ldev->gpio.methods->set_lineout(&ldev->gpio, v); 829 } 830 } else 831 return; 832 833 if (detected) 834 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id); 835 if (update) { 836 c = ldev->headphone_ctrl; 837 if (c) 838 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); 839 c = ldev->speaker_ctrl; 840 if (c) 841 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); 842 c = ldev->lineout_ctrl; 843 if (c) 844 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); 845 } 846} 847 848static void layout_attached_codec(struct aoa_codec *codec) 849{ 850 struct codec_connection *cc; 851 struct snd_kcontrol *ctl; 852 int headphones, lineout; 853 struct layout_dev *ldev = layout_device; 854 855 /* need to add this codec to our codec array! */ 856 857 cc = codec->fabric_data; 858 859 headphones = codec->gpio->methods->get_detect(codec->gpio, 860 AOA_NOTIFY_HEADPHONE); 861 lineout = codec->gpio->methods->get_detect(codec->gpio, 862 AOA_NOTIFY_LINE_OUT); 863 864 while (cc->connected) { 865 if (cc->connected & CC_SPEAKERS) { 866 if (headphones <= 0 && lineout <= 0) 867 ldev->gpio.methods->set_speakers(codec->gpio, 1); 868 ctl = snd_ctl_new1(&speakers_ctl, codec->gpio); 869 ldev->speaker_ctrl = ctl; 870 aoa_snd_ctl_add(ctl); 871 } 872 if (cc->connected & CC_HEADPHONE) { 873 if (headphones == 1) 874 ldev->gpio.methods->set_headphone(codec->gpio, 1); 875 ctl = snd_ctl_new1(&headphone_ctl, codec->gpio); 876 ldev->headphone_ctrl = ctl; 877 aoa_snd_ctl_add(ctl); 878 ldev->have_headphone_detect = 879 !ldev->gpio.methods 880 ->set_notify(&ldev->gpio, 881 AOA_NOTIFY_HEADPHONE, 882 layout_notify, 883 &ldev->selfptr_headphone); 884 if (ldev->have_headphone_detect) { 885 ctl = snd_ctl_new1(&headphone_detect_choice, 886 ldev); 887 aoa_snd_ctl_add(ctl); 888 ctl = snd_ctl_new1(&headphone_detected, 889 ldev); 890 ldev->headphone_detected_ctrl = ctl; 891 aoa_snd_ctl_add(ctl); 892 } 893 } 894 if (cc->connected & CC_LINEOUT) { 895 if (lineout == 1) 896 ldev->gpio.methods->set_lineout(codec->gpio, 1); 897 ctl = snd_ctl_new1(&lineout_ctl, codec->gpio); 898 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) 899 strlcpy(ctl->id.name, 900 "Headphone Switch", sizeof(ctl->id.name)); 901 ldev->lineout_ctrl = ctl; 902 aoa_snd_ctl_add(ctl); 903 ldev->have_lineout_detect = 904 !ldev->gpio.methods 905 ->set_notify(&ldev->gpio, 906 AOA_NOTIFY_LINE_OUT, 907 layout_notify, 908 &ldev->selfptr_lineout); 909 if (ldev->have_lineout_detect) { 910 ctl = snd_ctl_new1(&lineout_detect_choice, 911 ldev); 912 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) 913 strlcpy(ctl->id.name, 914 "Headphone Detect Autoswitch", 915 sizeof(ctl->id.name)); 916 aoa_snd_ctl_add(ctl); 917 ctl = snd_ctl_new1(&lineout_detected, 918 ldev); 919 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) 920 strlcpy(ctl->id.name, 921 "Headphone Detected", 922 sizeof(ctl->id.name)); 923 ldev->lineout_detected_ctrl = ctl; 924 aoa_snd_ctl_add(ctl); 925 } 926 } 927 cc++; 928 } 929 /* now update initial state */ 930 if (ldev->have_headphone_detect) 931 layout_notify(&ldev->selfptr_headphone); 932 if (ldev->have_lineout_detect) 933 layout_notify(&ldev->selfptr_lineout); 934} 935 936static struct aoa_fabric layout_fabric = { 937 .name = "SoundByLayout", 938 .owner = THIS_MODULE, 939 .found_codec = layout_found_codec, 940 .remove_codec = layout_remove_codec, 941 .attached_codec = layout_attached_codec, 942}; 943 944static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) 945{ 946 struct device_node *sound = NULL; 947 const unsigned int *layout_id; 948 struct layout *layout; 949 struct layout_dev *ldev = NULL; 950 int err; 951 952 /* hm, currently we can only have one ... */ 953 if (layout_device) 954 return -ENODEV; 955 956 /* by breaking out we keep a reference */ 957 while ((sound = of_get_next_child(sdev->ofdev.node, sound))) { 958 if (sound->type && strcasecmp(sound->type, "soundchip") == 0) 959 break; 960 } 961 if (!sound) return -ENODEV; 962 963 layout_id = of_get_property(sound, "layout-id", NULL); 964 if (!layout_id) 965 goto outnodev; 966 printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n", 967 *layout_id); 968 969 layout = find_layout_by_id(*layout_id); 970 if (!layout) { 971 printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n"); 972 goto outnodev; 973 } 974 975 ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL); 976 if (!ldev) 977 goto outnodev; 978 979 layout_device = ldev; 980 ldev->sdev = sdev; 981 ldev->sound = sound; 982 ldev->layout = layout; 983 ldev->gpio.node = sound->parent; 984 switch (layout->layout_id) { 985 case 41: /* that unknown machine no one seems to have */ 986 case 51: /* PowerBook5,4 */ 987 case 58: /* Mac Mini */ 988 ldev->gpio.methods = ftr_gpio_methods; 989 printk(KERN_DEBUG 990 "snd-aoa-fabric-layout: Using direct GPIOs\n"); 991 break; 992 default: 993 ldev->gpio.methods = pmf_gpio_methods; 994 printk(KERN_DEBUG 995 "snd-aoa-fabric-layout: Using PMF GPIOs\n"); 996 } 997 ldev->selfptr_headphone.ptr = ldev; 998 ldev->selfptr_lineout.ptr = ldev; 999 sdev->ofdev.dev.driver_data = ldev; 1000 list_add(&ldev->list, &layouts_list); 1001 layouts_list_items++; 1002 1003 /* assign these before registering ourselves, so 1004 * callbacks that are done during registration 1005 * already have the values */ 1006 sdev->pcmid = ldev->layout->pcmid; 1007 if (ldev->layout->busname) { 1008 sdev->pcmname = ldev->layout->busname; 1009 } else { 1010 sdev->pcmname = "Master"; 1011 } 1012 1013 ldev->gpio.methods->init(&ldev->gpio); 1014 1015 err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev); 1016 if (err && err != -EALREADY) { 1017 printk(KERN_INFO "snd-aoa-fabric-layout: can't use," 1018 " another fabric is active!\n"); 1019 goto outlistdel; 1020 } 1021 1022 use_layout(layout); 1023 ldev->switch_on_headphone = 1; 1024 ldev->switch_on_lineout = 1; 1025 return 0; 1026 outlistdel: 1027 /* we won't be using these then... */ 1028 ldev->gpio.methods->exit(&ldev->gpio); 1029 /* reset if we didn't use it */ 1030 sdev->pcmname = NULL; 1031 sdev->pcmid = -1; 1032 list_del(&ldev->list); 1033 layouts_list_items--; 1034 outnodev: 1035 of_node_put(sound); 1036 layout_device = NULL; 1037 kfree(ldev); 1038 return -ENODEV; 1039} 1040 1041static int aoa_fabric_layout_remove(struct soundbus_dev *sdev) 1042{ 1043 struct layout_dev *ldev = sdev->ofdev.dev.driver_data; 1044 int i; 1045 1046 for (i=0; i<MAX_CODECS_PER_BUS; i++) { 1047 if (ldev->codecs[i]) { 1048 aoa_fabric_unlink_codec(ldev->codecs[i]); 1049 } 1050 ldev->codecs[i] = NULL; 1051 } 1052 list_del(&ldev->list); 1053 layouts_list_items--; 1054 of_node_put(ldev->sound); 1055 1056 ldev->gpio.methods->set_notify(&ldev->gpio, 1057 AOA_NOTIFY_HEADPHONE, 1058 NULL, 1059 NULL); 1060 ldev->gpio.methods->set_notify(&ldev->gpio, 1061 AOA_NOTIFY_LINE_OUT, 1062 NULL, 1063 NULL); 1064 1065 ldev->gpio.methods->exit(&ldev->gpio); 1066 layout_device = NULL; 1067 kfree(ldev); 1068 sdev->pcmid = -1; 1069 sdev->pcmname = NULL; 1070 return 0; 1071} 1072 1073#ifdef CONFIG_PM 1074static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state) 1075{ 1076 struct layout_dev *ldev = sdev->ofdev.dev.driver_data; 1077 1078 if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) 1079 ldev->gpio.methods->all_amps_off(&ldev->gpio); 1080 1081 return 0; 1082} 1083 1084static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) 1085{ 1086 struct layout_dev *ldev = sdev->ofdev.dev.driver_data; 1087 1088 if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) 1089 ldev->gpio.methods->all_amps_restore(&ldev->gpio); 1090 1091 return 0; 1092} 1093#endif 1094 1095static struct soundbus_driver aoa_soundbus_driver = { 1096 .name = "snd_aoa_soundbus_drv", 1097 .owner = THIS_MODULE, 1098 .probe = aoa_fabric_layout_probe, 1099 .remove = aoa_fabric_layout_remove, 1100#ifdef CONFIG_PM 1101 .suspend = aoa_fabric_layout_suspend, 1102 .resume = aoa_fabric_layout_resume, 1103#endif 1104 .driver = { 1105 .owner = THIS_MODULE, 1106 } 1107}; 1108 1109static int __init aoa_fabric_layout_init(void) 1110{ 1111 int err; 1112 1113 err = soundbus_register_driver(&aoa_soundbus_driver); 1114 if (err) 1115 return err; 1116 return 0; 1117} 1118 1119static void __exit aoa_fabric_layout_exit(void) 1120{ 1121 soundbus_unregister_driver(&aoa_soundbus_driver); 1122 aoa_fabric_unregister(&layout_fabric); 1123} 1124 1125module_init(aoa_fabric_layout_init); 1126module_exit(aoa_fabric_layout_exit); 1127