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