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