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